commit fd86c1b5c0be9f1fd9c9a643d746b6a238cfb5fd Author: Jeff Wilcox Date: Fri Nov 13 12:38:55 2015 -0800 Open Source Release v1.0 diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..458d1efe --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +# Node +node_modules/ +npm-debug.log + +# OS X +.DS_Store + +# Local test files +sync-*.js + +# Local development environment scripts +bin/local* +bin/contoso +app.yaml + +# Tooling +.vscode/ + +# Editors +.vscode/ + +# Other routes and components that need not be included here +docs/ +routes/microsoft-specific* +routes/friends/ +routes/docs.js +views/docs/ +public/css/docs.css diff --git a/.jshintignore b/.jshintignore new file mode 100644 index 00000000..2c3857c6 --- /dev/null +++ b/.jshintignore @@ -0,0 +1,6 @@ +.git +node_modules +public/js/jquery*.* +public/js/html5*.* +public/js/bootstrap*.* +public/js/timeago*.* diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..ffbf13f7 --- /dev/null +++ b/LICENSE @@ -0,0 +1,25 @@ +Azure Open Source Portal for GitHub v1.0 + +Copyright (c) Microsoft Corporation + +All rights reserved. + +MIT License + +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/README.md b/README.md new file mode 100644 index 00000000..96aeb95f --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +## azureopensource-portal + +The Azure Open Source Portal for GitHub is the culmination of years of trying to manage the +Azure presence on GitHub through a lot of trial, error, and improvement in tooling. + +## This file needs work! + +## LICENSE + +MIT license. See also: [LICENSE](LICENSE) diff --git a/app.js b/app.js new file mode 100644 index 00000000..6389c36e --- /dev/null +++ b/app.js @@ -0,0 +1,51 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +var async = require('async'); +var DataClient = require('./data'); +var express = require('express'); +var redis = require('redis'); +var app = express(); + +// Asynchronous initialization for the Express app, configuration and data stores. +app.initializeApplication = function init(config, callback) { + var dc; + var redisFirstCallback; + var redisClient = redis.createClient(config.redis.port, config.redis.host); + redisClient.on('connect', function () { + if (redisFirstCallback) { + var cb = redisFirstCallback; + redisFirstCallback = null; + cb(); + } + }); + async.parallel([ + function (cb) { + new DataClient(config, function (error, dcInstance) { + dc = dcInstance; + cb(); + }); + }, + function (cb) { + redisFirstCallback = cb; + redisClient.auth(config.redis.key); + }, + ], function (error) { + if (error) { + throw error; + } + app.set('dataclient', dc); + dc.cleanupInTheFuture = { + redisClient: redisClient + }; + app.set('runtimeConfig', config); + require('./middleware/')(app, express, config, __dirname); + app.use('/', require('./routes/')); + require('./middleware/error-routes')(app); + callback(null, app); + }); +}; + +module.exports = app; diff --git a/bin/www b/bin/www new file mode 100644 index 00000000..e3238ddf --- /dev/null +++ b/bin/www @@ -0,0 +1,72 @@ +#!/usr/bin/env node +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +var app = require('../app'); +var debug = require('debug')('g:server'); +var http = require('http'); + +function normalizePort(val) { + var port = parseInt(val, 10); + + if (isNaN(port)) { + // named pipe + return val; + } + + if (port >= 0) { + // port number + return port; + } + + return false; +} + +var port = normalizePort(process.env.PORT || '3000'); +app.set('port', port); + +var config = require('../configuration')(process.env); + +app.initializeApplication(config, function (error) { + if (error) throw error; + + var server = http.createServer(app); + + server.listen(port); + server.on('error', onError); + server.on('listening', onListening); + + function onError(error) { + if (error.syscall !== 'listen') { + throw error; + } + + var bind = typeof port === 'string' + ? 'Pipe ' + port + : 'Port ' + port + + // handle specific listen errors with friendly messages + switch (error.code) { + case 'EACCES': + console.error(bind + ' requires elevated privileges'); + process.exit(1); + break; + case 'EADDRINUSE': + console.error(bind + ' is already in use'); + process.exit(1); + break; + default: + throw error; + } + } + + function onListening() { + var addr = server.address(); + var bind = typeof addr === 'string' + ? 'pipe ' + addr + : 'port ' + addr.port; + debug('Listening on ' + bind); + } +}); diff --git a/configuration.js b/configuration.js new file mode 100644 index 00000000..49efe884 --- /dev/null +++ b/configuration.js @@ -0,0 +1,117 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +var utils = require('./utils'); + +module.exports = function translateEnvironmentToConfiguration(env) { + if (!env) { + env = process.env; + } + var i = 0; + var pkgInfo = require('./package.json'); + var config = { + logging: { + errors: env.SITE_SKIP_ERRORS === undefined, + version: pkgInfo.version, + }, + companyName: env.COMPANY_NAME, + serviceBanner: env.SITE_SERVICE_BANNER, + corporate: { + userProfilePrefix: env.CORPORATE_PROFILE_PREFIX, + trainingResources: require('./resources.json'), + portalAdministratorEmail: env.PORTAL_ADMIN_EMAIL, + }, + // Friends are GitHub username(s) which have special + // access for application use such as CLA tooling and + // compliance/audit accounts. Supports comma-sep lists. + friends: { + cla: utils.arrayFromString(env.FRIENDS_CLA), + employeeData: utils.arrayFromString(env.FRIENDS_DATA), + }, + // GitHub application properties and secrets + github: { + clientId: env.GITHUB_CLIENT_ID, + clientSecret: env.GITHUB_CLIENT_SECRET, + callbackUrl: env.GITHUB_CALLBACK_URL, + }, + organizations: [], + // A salt needs to be provided to secure sessions and cookies. + express: { + sessionSalt: env.SESSION_SALT + }, + // The app uses authentication with Azure Active Directory to grant access + // to the GitHub organization. + activeDirectory: { + clientId: env.AAD_CLIENT_ID, + clientSecret: env.AAD_CLIENT_SECRET, + tenantId: env.AAD_TENANT_ID, + redirectUrl: env.AAD_REDIRECT_URL, + allowTenantGuests: (env.AAD_ALLOW_TENANT_GUESTS && env.AAD_ALLOW_TENANT_GUESTS == 'allow') + }, + // AppInsights is a Microsoft Cloud product for gathering analytics and + // other useful information about apps. This app uses the Node.js npm + // module for app insights to gather information on server generation + // times, while the client JavaScript wrapper for AppInsights is also + // used for monitoring client browser attributes and information. If the + // key is not supplied, the app continues functioning. + applicationInsights: { + instrumentationKey: env.APPINSIGHTS_INSTRUMENTATION_KEY + }, + // An Azure storage account is used as all data is stored in a + // geo-replicated storage account in table store. This is simple + // model vs a SQL Database instance, but requires doing joins + // on the server. + azureStorage: { + account: env.XSTORE_ACCOUNT, + key: env.XSTORE_KEY, + prefix: env.XSTORE_PREFIX + }, + // Redis is used for shared session state across running site instances. + // The Azure Redis offering includes a redundant option, but as the + // session store is designed like a cache, the only outcome of lost + // Redis data is that the user will need to sign in again. + redis: { + port: env.REDIS_PORT, + host: env.REDIS_HOST, + key: env.REDIS_KEY, + ttl: env.REDIS_TTL || (60 * 60 * 24 * 7 /* one week */), + prefix: env.REDIS_PREFIX, + }, + }; + for (i = 1; env['GITHUB_ORG' + i + '_NAME']; i++) { + var prefix = 'GITHUB_ORG' + i + '_'; + var org = { + name: env[prefix + 'NAME'], + type: env[prefix + 'TYPE'] || 'public', + ownerToken: env[prefix + 'TOKEN'], + notificationRepo: env[prefix + 'NOTIFICATION_REPO'], + teamAllMembers: env[prefix + 'EVERYONE_TEAMID'], + teamRepoApprovers: env[prefix + 'REPO_APPROVERS_TEAMID'], + hookSecrets: utils.arrayFromString(env[prefix + 'HOOK_TOKENS']), + teamAllRepos: env[prefix + 'SECURITY_TEAMID'], + teamAllRepoWriteId: env[prefix + 'ALLREPOWRITE_TEAMID'], + teamSudoers: env[prefix + 'SUDOERS_TEAMID'], + description: env[prefix + 'DESCRIPTION'], + highlightedTeams: [], + }; + if (i == 1) { + org.teamPortalSudoers = env[prefix + 'PORTAL_SUDOERS_TEAMID']; + } + var highlightIds = utils.arrayFromString(env[prefix + 'HIGHLIGHTED_TEAMS']); + var highlightText = utils.arrayFromString(env[prefix + 'HIGHLIGHTED_TEAMS_INFO'], ';'); + if (highlightIds.length === highlightText.length) { + for (var j = 0; j < highlightIds.length; j++) { + org.highlightedTeams.push({ + id: highlightIds[j], + description: highlightText[j], + }); + } + } else { + throw new Error('Invalid matching of size for highlighted teams.'); + } + config.organizations.push(org); + } + return config; +}; diff --git a/data.js b/data.js new file mode 100644 index 00000000..c559ee68 --- /dev/null +++ b/data.js @@ -0,0 +1,639 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +// This is the original data interface for this portal. It uses Azure +// table storage and its Node.js SDK. There's a lot of potential work +// to do here to better factor this and allow for other data providers +// such as MonogDB... + +var azure = require('azure-storage'); +var async = require('async'); +var uuid = require('node-uuid'); +var os = require('os'); + +var staticHostname = os.hostname().toString(); + +function DataClient (config, callback) { + var storageAccountName = config.azureStorage.account; + var storageAccountKey = config.azureStorage.key; + var prefix = config.azureStorage.prefix; + this.table = azure.createTableService(storageAccountName, storageAccountKey); + this.entGen = azure.TableUtilities.entityGenerator; + this.options = { + partitionKey: prefix + 'pk', + linksTableName: prefix + 'links', + pendingApprovalsTableName: prefix + 'pending', + errorsTableName: prefix + 'errors', + auditTableName: prefix + 'auditlog', + }; + var dc = this; + var tableNames = [ + dc.options.linksTableName, + dc.options.pendingApprovalsTableName, + dc.options.errorsTableName, + dc.options.auditTableName, + ]; + async.each(tableNames, function (tableName, callback) { + dc.table.createTableIfNotExists(tableName, callback); + }, function (error) { + if (callback) { + return callback(error, dc); + } + }); +} + +// Strip the Azure table storage fields if no uninteresting fields are provided. +var reduceEntity = function reduceEntity(instance, uninterestingFields) { + if (instance === undefined || instance === null) { + return instance; + } + if (uninterestingFields === undefined) { + uninterestingFields = ['.metadata', 'Timestamp', 'RowKey', 'PartitionKey']; + } + if (uninterestingFields && uninterestingFields.length) { + for (var i = 0; i < uninterestingFields.length; i++) { + if (instance[uninterestingFields[i]] !== undefined) { + delete instance[uninterestingFields[i]]; + } + } + } + for (var column in instance) { + if (instance[column] && instance[column]._ !== undefined) { + instance[column] = instance[column]._; + } + } + return instance; +}; + +DataClient.prototype.reduceEntity = reduceEntity; + +DataClient.prototype.requestToUserInformation = function rtui(req, storeFullUserInformation) { + var info = { + ghid: undefined, + ghu: undefined, + aad: undefined, + fulluser: undefined + }; + if (storeFullUserInformation) { + info.fulluser = JSON.stringify(req.user); + } + if (req && req.user && req.user.github && req.user.github.id) { + info.ghid = req.user.github.id; + if (info.ghid.toString) { + info.ghid = info.ghid.toString(); + } + if (req.user.github.username) { + info.ghu = req.user.github.username; + } + } + if (req && req.user && req.user.azure && req.user.azure.username) { + info.aad = req.user.azure.username; + } + return info; +}; + +DataClient.prototype.insertErrorLogEntry = function insertErrorEntry(version, req, err, meta, callback) { + // generic configuration, should move out at some point... + var storeFullUserInformation = false; + var storeUnknownUserErrors = false; + var storeRequestInformation = true; + var cbNoErrors = function(callback) { + if (callback) { + callback(); + } + }; + var dc = this; + var entity; + // (PartitionKey, RowKey): (ghid || 0, new uuid) + // (ghu, ghid, aad): user information + // (t, cid): (time when method called, correlation ID) + // (e, json, meta): (error message, JSON serialized err, JSON metadata) + // (url, host, ...): various host and request informational fields + try + { + var info = dc.requestToUserInformation(req, storeFullUserInformation); + // We may encounter users without a session. In these cases, we could log with -1 ID for pkey (OR use correlation ID for the pkey... hmm.) + if (info.ghid === undefined) { + if (!storeUnknownUserErrors) { + return cbNoErrors(callback); + } + info.ghid = -1; + } + info.v = version; + if (req.headers && req.headers.referer) { + info.referer = req.headers.referer; + } + var partitionKey = info.ghid; + var uniqueErrorId = uuid.v4(); + entity = dc.createEntity(partitionKey, uniqueErrorId, info); + var errorMessage = 'The error object was undefined.'; + var errorJson; + var errorStack; + var errorStatus = '200'; + if (err) { + // If err.meta is set, use that for the metadata up-level, and remove from err object. + if (err.meta && ! meta) { + meta = err.meta; + delete err.meta; + } + errorStack = err.stack; + if (err.status) { + errorStatus = err.status; + // delete err.status; // ? may not want to do this... + } + if (err.message) { + errorMessage = err.message; + } else { + if (err.toString) { + errorMessage = err.toString(); + } else { + errorMessage = 'The provided error instance is not a string and has no toString method.'; + } + } + try { + errorJson = JSON.stringify(err); + } catch (je) { + // Ignore any serialization errors or circular reference problems, the rest will still be logged in this case. + } + } + var metaJson; + if (meta) { + try { + metaJson = JSON.stringify(meta); + } catch (je) { + // Ignore. + } + } + var errorEntity = { + t: new Date().getTime(), + cid: (req && req.correlationId ? req.correlationId : undefined), + e: errorMessage, + stack: errorStack, + json: errorJson, + meta: metaJson, + status: errorStatus, + 'new': true + }; + dc.mergeIntoEntity(entity, errorEntity); + if (storeRequestInformation) { + var sri = { + url: req.scrubbedUrl || req.originalUrl || req.url, + ua: req.headers['user-agent'], + host: staticHostname + }; + dc.mergeIntoEntity(entity, sri); + } + } catch (ex) { + // Retry policy could be nice, OR log this separately if possible. Streaming logs will store this for now at least. + console.dir(ex); + return cbNoErrors(callback); + } + if (entity) { + dc.table.insertEntity(dc.options.errorsTableName, entity, function (error, xy) { + if (error) { + // CONSIDER: Replace console with debug call for morgan + console.dir(error); + } + cbNoErrors(callback); + }); + } else { + cbNoErrors(callback); + } +}; + +DataClient.prototype.updateError = function (partitionKey, rowKey, mergeEntity, callback) { + var dc = this; + var entity = dc.createEntity(partitionKey, rowKey, mergeEntity); + dc.table.mergeEntity(dc.options.errorsTableName, entity, callback); +}; + +DataClient.prototype.removeError = function (partitionKey, rowKey, callback) { + var dc = this; + dc.table.deleteEntity(dc.options.errorsTableName, dc.createEntity(partitionKey, rowKey), callback); +}; + +DataClient.prototype.getActiveErrors = function (correlationId, callback) { + var dc = this; + // Correlation ID is optional + if (typeof(correlationId) == 'function') { + callback = correlationId; + correlationId = undefined; + } + var metadataFieldsToSkip = ['.metadata', 'Timestamp']; + var done = false; + var continuationToken = null; + var entries = []; + async.whilst( + function () { return !done; }, + function (asyncCallback) { + var query = new azure.TableQuery() + .where('new eq ?', true); + if (correlationId) { + query.and.apply(query, ['cid eq ?', correlationId]); + } + dc.table.queryEntities(dc.options.errorsTableName, query, continuationToken, function (error, results) { + if (error) { + done = true; + return asyncCallback(error); + } + if (results.continuationToken) { + continuationToken = results.continuationToken; + console.log('getErrors continuationToken'); + console.dir(continuationToken); + } else { + done = true; + } + if (results && results.entries && results.entries.length) { + for (var i = 0; i < results.entries.length; i++) { + entries.push(reduceEntity(results.entries[i], metadataFieldsToSkip)); + } + } + asyncCallback(); + }); + }, function (error) { + if (error) { + return callback(error); + } + async.sortBy(entries, function (entity, scb) { + var t; + var err = null; + try { + t = Math.round(entity.t) * -1; + } + catch (trx) { + err = trx; + } + return scb(err, t); + }, callback); + }); +}; + +DataClient.prototype.mergeIntoEntity = function mit(entity, obj, callback) { + var dc = this; + if (obj) { + for (var key in obj) { + if (obj[key] === undefined) { + // Skip undefined objects, including the key + } else if (obj[key] === true) { + entity[key] = dc.entGen.Boolean(true); + } else if (obj[key] === false) { + entity[key] = dc.entGen.Boolean(false); + } else { + // CONSIDER: Richer merging opportunities! + if (obj[key].toString) { + entity[key] = dc.entGen.String(obj[key].toString()); + } else { + entity[key] = dc.entGen.String(obj[key]); + } + } + } + } + if (callback) { + callback(null, entity); + } else { + return entity; + } +}; + +DataClient.prototype.createEntity = function ce(partitionKey, rowKey, obj, callback) { + var dc = this; + if (typeof(obj) == 'function') { + callback = obj; + obj = undefined; + } + var entity = { + PartitionKey: dc.entGen.String(partitionKey), + RowKey: dc.entGen.String(rowKey) + }; + if (obj) { + dc.mergeIntoEntity(entity, obj); + } + if (callback) { + callback(null, entity); + } else { + return entity; + } +}; + +// links +// ----- +// CONSIDER: Replace link calls with reduced entity "association" calls, then depre. & remove these funcs. +DataClient.prototype.createLinkObjectFromRequest = function createLinkObject(req, callback) { + if (req && req.user && req.user.github && req.user.azure && req.user.github.username && req.user.github.id && req.user.azure.username && req.user.azure.oid) { + return callback(null, { + ghu: req.user.github.username, + ghid: req.user.github.id.toString(), + aadupn: req.user.azure.username, + aadname: req.user.azure.displayName, + aadoid: req.user.azure.oid, + joined: new Date().getTime() + }); + } else { + return callback(new Error('Not all fields needed for creating a link are available and authenticated. This may be a temporary problem or an implementation bug.')); + } +}; + +DataClient.prototype.getUserLinks = function gul(users, callback) { + var dc = this; + var query = new azure.TableQuery() + .where('PartitionKey eq ?', this.options.partitionKey); + if (!(users && users.length && users.length > 0)) { + return callback(new Error('Must include an array of GitHub user IDs, and at least one in that array.')); + } + var clauses = []; + if (users.length > 250) { + console.log('Warning: getUserLinks called with ' + users.length + ' user IDs, which may be too many.'); + } + for (var i = 0; i < users.length; i++) { + clauses.push('ghid eq ?string?'); + } + var args = [clauses.join(' or ')].concat(users); + query.and.apply(query, args); + dc.table.queryEntities(dc.options.linksTableName, + query, + null, + function(error, results, headers) { + if (error) { + error.headers = headers; + return callback(error); + } + var entries = []; + if (results && results.entries && results.entries.length) { + for (var i = 0; i < results.entries.length; i++) { + entries.push(reduceEntity(results.entries[i])); + } + } + async.sortBy(entries, function (user, sortCallback) { + var value = user.aadupn || user.aadname || user.ghu || user.ghid; + if (value.toLowerCase) { + value = value.toLowerCase(); + } + sortCallback(null, value); + }, callback); + }); +}; + +DataClient.prototype.getUserLinkByUsername = function gulbyu(githubUsername, callback) { + this.getUserLinkByProperty('ghu', githubUsername, function (error, data) { + if (error) return callback(error); + if (data && data.length) { + if (data.length == 1) { + callback(null, data[0]); + } else { + if (data.length === 0) { + callback(null, false); + } else { + callback(new Error('Multiple entries returned. The data may be consistent. Please file a bug.')); + } + } + } else { + callback(new Error('No results.')); + } + }); +}; + +DataClient.prototype.updateLink = function updl(userid, mergeEntity, callback) { + var dc = this; + var entity = dc.createEntity(dc.options.partitionKey, userid, mergeEntity); + dc.table.mergeEntity(dc.options.linksTableName, entity, callback); +}; + +DataClient.prototype.getUserByAadUpn = function gubauapn(employeeAlias, callback) { + this.getUserLinkByProperty('aadupn', employeeAlias.toLowerCase(), callback); +}; + +DataClient.prototype.getUserLinkByProperty = function gulbprop(propertyName, value, callback) { + var dc = this; + var query = new azure.TableQuery() + .where(propertyName + ' eq ?', value); + dc.table.queryEntities(dc.options.linksTableName, + query, + null, + function(error, results) { + if (error) return callback(error); + var entries = []; + if (results && results.entries && results.entries.length) { + for (var i = 0; i < results.entries.length; i++) { + entries.push(reduceEntity(results.entries[i])); + } + } + callback(null, entries); + }); +}; + +DataClient.prototype.getLink = function getLink(githubId, callback) { + var dc = this; + if (githubId === undefined) { + return callback(new Error('The GitHub ID is undefined.')); + } + if (typeof githubId != 'string') { + githubId = githubId.toString(); + } + dc.table.retrieveEntity(dc.options.linksTableName, dc.options.partitionKey, githubId, function (error, result, response) { + if (error && !result) { + return callback(null, false); + } + return callback(error, result, response); + }); +}; + +DataClient.prototype.getAllEmployees = function getAllEmployees(callback) { + var dc = this; + var pageSize = 500; + var employees = []; + var done = false; + var continuationToken = null; + async.whilst( + function areWeDone() { return !done; }, + function grabPage(cb) { + var query = new azure.TableQuery() + .select(['aadupn', 'ghu', 'ghid']) + .top(pageSize); + dc.table.queryEntities(dc.options.linksTableName, query, continuationToken, function (error, results) { + if (error) { + done = true; + return cb(error); + } + if (results.continuationToken) { + continuationToken = results.continuationToken; + } else { + done = true; + } + if (results && results.entries && results.entries.length) { + for (var i = 0; i < results.entries.length; i++) { + employees.push(reduceEntity(results.entries[i])); + } + } + cb(); + }); + }, function (error) { + if (error) return callback(error); + async.sortBy(employees, function (person, sortCallback) { + if (person.aadupn && person.aadupn.toLowerCase) { + person.aadupn = person.aadupn.toLowerCase(); + } + sortCallback(null, person.aadupn); + }, callback); + }); +}; + +// 9/4/15 jwilcox: insertLink and updateLink now use the shared merge/copy entity calls. Previously these 2 methods instead did a string-only entGen and copy of key/values, so beware any behavior changes. Remove this line once happy with that. +DataClient.prototype.insertLink = function insertLink(githubId, details, callback) { + var dc = this; + if (githubId === undefined) { + return callback(new Error('The GitHub ID is undefined.')); + } + if (typeof githubId != 'string') { + githubId = githubId.toString(); + } + var entity = dc.createEntity(dc.options.partitionKey, githubId, details); + dc.table.insertEntity(dc.options.linksTableName, entity, callback); +}; + +DataClient.prototype.updateLink = function insertLink(githubId, details, callback) { + var dc = this; + if (githubId === undefined) { + return callback(new Error('The GitHub ID is undefined.')); + } + if (typeof githubId != 'string') { + githubId = githubId.toString(); + } + var entity = dc.createEntity(dc.options.partitionKey, githubId, details); + dc.table.mergeEntity(dc.options.linksTableName, entity, callback); +}; + +DataClient.prototype.removeLink = function removeLink(githubId, callback) { + var dc = this; + if (githubId === undefined) { + return callback(new Error('The GitHub ID is undefined.')); + } + if (typeof githubId != 'string') { + githubId = githubId.toString(); + } + dc.table.deleteEntity(dc.options.linksTableName, dc.createEntity(dc.options.partitionKey, githubId), callback); +}; + +// pending approvals workflow +// -------------------------- +DataClient.prototype.getPendingApprovals = function getPendingApprovals(teamsIn, callback) { + var dc = this; + var teams = null; + var i; + if (typeof teamsIn == 'number') { + teams = [teamsIn.toString()]; + } + else if (typeof teamsIn == 'string') { + teams = [teamsIn]; + } else if (typeof teamsIn == 'function') { + callback = teamsIn; + teams = []; // Special case: empty list means all pending approvals + } else { + if (!(teamsIn && teamsIn.length)) { + throw new Error('Unknown "teams" type for getPendingApprovals. Please file a bug.'); + } + // New permissions system refactoring... + if (teamsIn.length > 0 && teamsIn[0] && teamsIn[0].id) { + teams = []; + for (i = 0; i < teamsIn.length; i++) { + teams.push(teamsIn[i].id); + } + } + } + var query = new azure.TableQuery() + .where('PartitionKey eq ?', this.options.partitionKey) + .and('active eq ?', true); + if (teams.length > 0) { + var clauses = []; + for (i = 0; i < teams.length; i++) { + clauses.push('teamid eq ?string?'); + } + var args = [clauses.join(' or ')].concat(teams); + query.and.apply(query, args); + } + dc.table.queryEntities(dc.options.pendingApprovalsTableName, + query, + null, + function(error, results) { + if (error) return callback(error); + var entries = []; + if (results && results.entries && results.entries.length) { + for (var i = 0; i < results.entries.length; i++) { + var r = results.entries[i]; + if (r && r.active && r.active._) { + entries.push(reduceEntity(r, ['.metadata'])); + } + } + } + callback(null, entries); + }); +}; + +DataClient.prototype.insertApprovalRequest = function iar(teamid, details, callback) { + var dc = this; + if (typeof teamid != 'string') { + teamid = teamid.toString(); + } + details.teamid = teamid; + dc.insertGeneralApprovalRequest('joinTeam', details, callback); +}; + +DataClient.prototype.insertGeneralApprovalRequest = function igar(ticketType, details, callback) { + var dc = this; + var id = uuid.v4(); + var entity = dc.createEntity(dc.options.partitionKey, id, { + tickettype: ticketType + }); + dc.mergeIntoEntity(entity, details); + dc.table.insertEntity(dc.options.pendingApprovalsTableName, entity, function (error, result, response) { + if (error) { + return callback(error); + } + // Pass back the generated request ID first. + callback(null, id, result, response); + }); +}; + +DataClient.prototype.getApprovalRequest = function gar(requestId, callback) { + var dc = this; + dc.table.retrieveEntity(dc.options.pendingApprovalsTableName, dc.options.partitionKey, requestId, function (error, ent) { + if (error) return callback(error); + callback(null, reduceEntity(ent, ['.metadata'])); + }); +}; + +DataClient.prototype.getPendingApprovalsForUserId = function gpeaf(githubid, callback) { + var dc = this; + if (typeof githubid == 'number') { + githubid = githubid.toString(); + } + var query = new azure.TableQuery() + .where('PartitionKey eq ?', this.options.partitionKey) + .and('active eq ?', true) + .and('ghid eq ?', githubid); + dc.table.queryEntities(dc.options.pendingApprovalsTableName, + query, + null, + function(error, results) { + if (error) return callback(error); + var entries = []; + if (results && results.entries && results.entries.length) { + for (var i = 0; i < results.entries.length; i++) { + var r = results.entries[i]; + if (r && r.active && r.active._) { + entries.push(reduceEntity(r, ['.metadata'])); + } + } + } + callback(null, entries); + }); +}; + +DataClient.prototype.updateApprovalRequest = function uar(requestId, mergeEntity, callback) { + var dc = this; + var entity = dc.createEntity(dc.options.partitionKey, requestId, mergeEntity); + dc.table.mergeEntity(dc.options.pendingApprovalsTableName, entity, callback); +}; + +module.exports = DataClient; diff --git a/middleware/appInsights.js b/middleware/appInsights.js new file mode 100644 index 00000000..2dd3b295 --- /dev/null +++ b/middleware/appInsights.js @@ -0,0 +1,18 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +// ---------------------------------------------------------------------------- +// Application Insights integration +// ---------------------------------------------------------------------------- +module.exports = function initializeAppInsights(config) { + if (config.applicationInsights.instrumentationKey) { + var AppInsights = require('applicationinsights'); + var appInsights = new AppInsights({ + instrumentationKey: config.applicationInsights.instrumentationKey + }); + appInsights.trackAllHttpServerRequests('favicon'); + appInsights.trackAllUncaughtExceptions(); + } +}; diff --git a/middleware/correlationId.js b/middleware/correlationId.js new file mode 100644 index 00000000..739741b2 --- /dev/null +++ b/middleware/correlationId.js @@ -0,0 +1,14 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +var uuid = require('node-uuid'); + +// ---------------------------------------------------------------------------- +// Generate a correlation ID +// ---------------------------------------------------------------------------- +module.exports = function (req, res, next) { + req.correlationId = uuid.v4(); + next(); +}; diff --git a/middleware/error-routes.js b/middleware/error-routes.js new file mode 100644 index 00000000..15b853e7 --- /dev/null +++ b/middleware/error-routes.js @@ -0,0 +1,14 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +module.exports = function configureErrorRoutes(app) { + app.use(function(req, res, next) { + var err = new Error('Not Found'); + err.status = 404; + err.skipLog = true; + next(err); + }); + app.use(require('./errorHandler')); +}; diff --git a/middleware/errorHandler.js b/middleware/errorHandler.js new file mode 100644 index 00000000..f56d9b97 --- /dev/null +++ b/middleware/errorHandler.js @@ -0,0 +1,66 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +var uuid = require('node-uuid'); + +module.exports = function(err, req, res, next) { + var config = null; + var errorStatus = err && err.status ? err.status : undefined; + if (req && req.app && req.app.settings && req.app.settings.dataclient && req.app.settings.runtimeConfig) { + config = req.app.settings.runtimeConfig; + var version = config && config.logging && config.logging.version ? config.logging.version: '?'; + var dc = req.app.settings.dataclient; + if (config.logging.errors && err.status !== 403 && err.skipLog !== true) { + dc.insertErrorLogEntry(version, req, err); + } + } + if (err !== undefined && err.skipLog !== true) { + console.log('Error: ' + (err && err.message ? err.message : 'Error is undefined.')); + if (err.stack) { + console.error(err.stack); + } + if (err.innerError) { + var inner = err.innerError; + console.log('Inner: ' + inner.message); + if (inner.stack) { + console.log(inner.stack); + } + } + } + // Bubble OAuth errors to the forefront... this is the rate limit scenario. + if (err && err.oauthError && err.oauthError.statusCode && err.oauthError.statusCode && err.oauthError.data) { + var detailed = err.message; + err = err.oauthError; + err.status = err.statusCode; + var data = JSON.parse(err.data); + if (data && data.message) { + err.message = err.statusCode + ': ' + data.message; + } else { + err.message = err.statusCode + ' Unauthorized received. You may have exceeded your GitHub API rate limit or have an invalid auth token at this time.'; + } + err.detailed = detailed; + } + // Don't leak the Redis connection information. + if (err && err.message && err.message.indexOf('Redis connection') >= 0 && err.message.indexOf('ETIMEDOUT')) { + err.message = 'The session store was temporarily unavailable. Please try again.'; + err.detailed = 'Azure Redis Cache'; + } + if (res.headersSent) { + console.error('Headers were already sent.'); + return next(err); + } + res.status(err.status || 500); + res.render('error', { + message: err.message, + serviceBanner: config && config.serviceBanner ? config.serviceBanner : undefined, + detailed: err && err.detailed ? err.detailed : undefined, + errorFancyLink: err && err.fancyLink ? err.fancyLink : undefined, + errorStatus: errorStatus, + error: {}, + title: err.status === 404 ? 'Not Found' : 'Oops', + user: req.user, + config: config, + }); +}; diff --git a/middleware/index.js b/middleware/index.js new file mode 100644 index 00000000..5483e126 --- /dev/null +++ b/middleware/index.js @@ -0,0 +1,40 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +var path = require('path'); +var favicon = require('serve-favicon'); +var cookieParser = require('cookie-parser'); +var bodyParser = require('body-parser'); +var compression = require('compression'); + +module.exports = function initMiddleware(app, express, config, dirname) { + require('./appInsights')(config); + + app.set('views', path.join(dirname, 'views')); + app.set('view engine', 'jade'); + app.set('view cache', false); + + app.use(favicon(dirname + '/public/favicon.ico')); + + app.use(bodyParser.json()); + app.use(bodyParser.urlencoded({ extended: false })); + app.use(compression()); + app.use(cookieParser()); + + app.use(require('./session')(config)); + var passport = require('./passport-config')(app, config); + + app.use(express.static(path.join(dirname, 'public'))); + + app.use(require('./scrubbedUrl')); + app.use(require('./logger')); + if (process.env.WEBSITE_SKU) { + app.use(require('./requireSecureAppService')); + } + app.use(require('./correlationId')); + app.use(require('./locals')); + + require('./passport-routes')(app, passport); +}; diff --git a/middleware/locals.js b/middleware/locals.js new file mode 100644 index 00000000..f2f22d7a --- /dev/null +++ b/middleware/locals.js @@ -0,0 +1,17 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +var os = require('os'); + +// ---------------------------------------------------------------------------- +// Set local variables that we want every view to share. +// ---------------------------------------------------------------------------- +module.exports = function (req, res, next) { + req.app.locals.correlationId = req.correlationId; + req.app.locals.serverName = os.hostname(); + req.app.locals.appInsightsKey = req.app.settings.runtimeConfig.applicationInsights.instrumentationKey; + + next(); +}; diff --git a/middleware/logger.js b/middleware/logger.js new file mode 100644 index 00000000..653d954a --- /dev/null +++ b/middleware/logger.js @@ -0,0 +1,27 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +var logger = require('morgan'); + +logger.token('github', function getGitHub(req) { + if (req.user && req.user.github && req.user.github.username) { + return req.user.github.username; + } else { + return undefined; + } +}); + +logger.token('correlationId', function getCorrelationId(req) { + return req.correlationId ? req.correlationId : undefined; +}); + +logger.token('scrubbedUrl', function getScrubbedUrl(req) { + return req.scrubbedUrl || req.originalUrl || req.url; +}); + +// ---------------------------------------------------------------------------- +// Use the customized ogger for Express requests. +// ---------------------------------------------------------------------------- +module.exports = logger(':github :method :scrubbedUrl :status :response-time ms - :res[content-length] :correlationId'); diff --git a/middleware/passport-config.js b/middleware/passport-config.js new file mode 100644 index 00000000..f2c639a0 --- /dev/null +++ b/middleware/passport-config.js @@ -0,0 +1,84 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +var passport = require('passport'); +var utils = require('../utils'); + +var GitHubStrategy = require('passport-github').Strategy; +var OIDCStrategy = require('passport-azure-ad').OIDCStrategy; + +module.exports = function (app, config) { + // ---------------------------------------------------------------------------- + // GitHub Passport session setup. + // ---------------------------------------------------------------------------- + // To support persistent login sessions, Passport needs to be able to + // serialize users into and deserialize users out of the session. Typically, + // this will be as simple as storing the user ID when serializing, and finding + // the user by ID when deserializing. However, since this example does not + // have a database of user records, the complete GitHub profile is serialized + // and deserialized. + passport.serializeUser(function(user, done) { + done(null, user); + }); + passport.deserializeUser(function(obj, done) { + done(null, obj); + }); + var gitHubTokenToSubset = function (accessToken, refreshToken, profile, done) { + var subset = { + github: { + accessToken: accessToken, + avatarUrl: profile._json && profile._json.avatar_url ? profile._json.avatar_url : undefined, + displayName: profile.displayName, + id: profile.id, + profileUrl: profile.profileUrl, + username: profile.username, + } + }; + return done(null, subset); + }; + passport.use(new GitHubStrategy({ + clientID: config.github.clientId, + clientSecret: config.github.clientSecret, + callbackURL: config.github.callbackUrl, + scope: ['user:email'], + userAgent: 'passport-azure-oss-portal-for-github' // CONSIDER: User agent should be configured. + }, gitHubTokenToSubset)); + + // ---------------------------------------------------------------------------- + // Azure Active Directory Passport session setup. + // ---------------------------------------------------------------------------- + var aadStrategy = new OIDCStrategy({ + callbackURL: config.activeDirectory.redirectUrl, + realm: config.activeDirectory.tenantId, + clientID: config.activeDirectory.clientId, + clientSecret: config.activeDirectory.clientSecret, + //oidcIssuer: config.creds.issuer, + identityMetadata: 'https://login.microsoftonline.com/common/.well-known/openid-configuration', + skipUserProfile: true, + responseType: 'id_token code', + responseMode: 'form_post', + }, function (iss, sub, profile, accessToken, refreshToken, done) { + done(null, profile); + }); + passport.use('azure-active-directory', aadStrategy); + + // ---------------------------------------------------------------------------- + // Expanded OAuth-scope GitHub access for org membership writes. + // ---------------------------------------------------------------------------- + var expandedGitHubScopeStrategy = new GitHubStrategy({ + clientID: config.github.clientId, + clientSecret: config.github.clientSecret, + callbackURL: config.github.callbackUrl + '/increased-scope', + scope: ['user:email', 'write:org'], + userAgent: 'passport-azure-oss-portal-for-github' // CONSIDER: User agent should be configured. + }, gitHubTokenToSubset); + + passport.use('expanded-github-scope', expandedGitHubScopeStrategy); + + app.use(passport.initialize()); + app.use(passport.session()); + + return passport; +}; diff --git a/middleware/passport-routes.js b/middleware/passport-routes.js new file mode 100644 index 00000000..3e1c701c --- /dev/null +++ b/middleware/passport-routes.js @@ -0,0 +1,106 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +module.exports = function configurePassport(app, passport) { + // ---------------------------------------------------------------------------- + // passport integration with GitHub + // ---------------------------------------------------------------------------- + app.get('/signin/github', function (req, res) { + if (req.session && req.headers && req.headers.referer) { + req.session.referer = req.headers.referer; + } + return res.redirect('/auth/github'); + }); + + app.get('/auth/github', + passport.authenticate('github'), + function (req, res){ + // The request will be redirected to GitHub for authentication, so this + // function will not be called. + }); + + app.get('/auth/github/callback', + passport.authenticate('github', { failureRedirect: '/failure/github' }), + function (req, res) { + var url = '/'; + if (req.session && req.session.referer) { + url = req.session.referer; + delete req.session.referer; + } + res.redirect(url); + }); + + app.get('/signout', function (req, res) { + req.logout(); + res.redirect('/'); + }); + + // ---------------------------------------------------------------------------- + // Expanded GitHub auth scope routes + // ---------------------------------------------------------------------------- + app.get('/signin/github/increased-scope', function (req, res){ + if (req.session && req.headers && req.headers.referer) { + req.session.referer = req.headers.referer; + } + return res.redirect('/auth/github/increased-scope'); + }); + + app.get('/auth/github/increased-scope', passport.authorize('expanded-github-scope')); + + app.get('/auth/github/callback/increased-scope', + passport.authorize('expanded-github-scope'), function (req, res, next) { + var account = req.account; + var user = req.user; + user.github.increasedScope = account; + var url = '/'; + if (req.session && req.session.referer) { + url = req.session.referer; + delete req.session.referer; + } + res.redirect(url); + }); + + // ---------------------------------------------------------------------------- + // passport integration with Azure Active Directory + // ---------------------------------------------------------------------------- + app.get('/auth/azure', passport.authorize('azure-active-directory')); + + app.post('/auth/azure/callback', + passport.authorize('azure-active-directory'), function (req, res, next) { + var account = req.account; + var username = account._json.upn; + if (account !== null && username && account.displayName) { + req.user.azure = { + displayName: account.displayName, + oid: account._json.oid, + username: username, + }; + var url = '/'; + if (req.session && req.session.referer) { + url = req.session.referer; + delete req.session.referer; + } + return res.redirect(url); + } else { + return next(new Error('Azure Active Directory authentication failed.')); + } + }); + + app.get('/signin/azure', function(req, res){ + if (req.session && req.headers && req.headers.referer) { + if (req.session.referer === undefined) { + req.session.referer = req.headers.referer; + } + } + return res.redirect('/auth/azure'); + }); + + app.get('/signout/azure', function(req, res){ + if (req.user && req.user.azure) { + delete req.user.azure; + } + res.redirect('/'); + }); +}; diff --git a/middleware/requireSecureAppService.js b/middleware/requireSecureAppService.js new file mode 100644 index 00000000..07312cff --- /dev/null +++ b/middleware/requireSecureAppService.js @@ -0,0 +1,34 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +// ---------------------------------------------------------------------------- +// If this portal is deployed to Azure App Service, let's make sure that they +// are connecting over SSL by validating the load balancer headers. If they are +// not, redirect them. Keys off of WEBSITE_SKU env variable that is injected. +// ---------------------------------------------------------------------------- +module.exports = function (req, res, next) { + if (!req.headers['x-arr-ssl']) { + return res.redirect('https://' + req.headers.host + req.originalUrl); + } else { + var arr = req.headers['x-arr-ssl']; + var expectedHeaders = [ + '2048|128|C=US, S=Washington, L=Redmond, O=Microsoft Corporation, OU=Microsoft IT, CN=Microsoft IT SSL SHA2|CN=*.azurewebsites.net', + '2048|256|C=US, S=Washington, L=Redmond, O=Microsoft Corporation, OU=Microsoft IT, CN=Microsoft IT SSL SHA2|CN=*.azurewebsites.net' + ]; + var isLegit = false; + for (var i = 0; i < expectedHeaders.length; i++) { + if (arr === expectedHeaders[i]) { + isLegit = true; + } + } + if (isLegit === false) { + var err = new Error('The SSL connection may not be secured via Azure App Service. Please contact the site sponsors to investigate.'); + err.headers = req.headers; + err.arrHeader = arr; + return next(err); + } + } + next(); +}; diff --git a/middleware/scrubbedUrl.js b/middleware/scrubbedUrl.js new file mode 100644 index 00000000..ad8c6a55 --- /dev/null +++ b/middleware/scrubbedUrl.js @@ -0,0 +1,25 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +// ---------------------------------------------------------------------------- +// Scrub the incoming URL value(s) in the request, replacing tokens and other +// secrets. +// ---------------------------------------------------------------------------- +module.exports = function (req, res, next) { + var url = req.originalUrl || req.url; + var secretKeys = [ + 'code', + 'token', + ]; + for (var i = 0; i < secretKeys.length; i++) { + var key = secretKeys[i]; + var value = req.query[key]; + if (value !== undefined) { + url = url.replace(key + '=' + value, key + '=*****'); + } + } + req.scrubbedUrl = url; + next(); +}; diff --git a/middleware/session.js b/middleware/session.js new file mode 100644 index 00000000..2cd29dce --- /dev/null +++ b/middleware/session.js @@ -0,0 +1,26 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +var session = require('express-session'); +var RedisStore = require('connect-redis')(session); + +module.exports = function (config) { + var settings = { + store: new RedisStore({ + port: config.redis.port, + host: config.redis.host, + pass: config.redis.key, + ttl: config.redis.ttl + }), + secret: config.express.sessionSalt, + name: 'sid', + resave: false, + saveUninitialized: false, + cookie: { + maxAge: config.redis.ttl * 1000 /* milliseconds for maxAge, not seconds */ + } + }; + return session(settings); +}; diff --git a/oss/audit.js b/oss/audit.js new file mode 100644 index 00000000..9413e2f1 --- /dev/null +++ b/oss/audit.js @@ -0,0 +1,12 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +// This file as it stands is a stub. + +var insertAuditLogEntry = function insertAuditEntry(details, callback) { + if (callback) { + callback(); + } +}; diff --git a/oss/index.js b/oss/index.js new file mode 100644 index 00000000..2e53c16c --- /dev/null +++ b/oss/index.js @@ -0,0 +1,581 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +var async = require('async'); +var debug = require('debug')('azureossportal'); +var utils = require('../utils'); +var github = require('octonode'); + +var Org = require('./org'); +var Team = require('./team'); +var User = require('./user'); +var Repo = require('./repo'); +var RedisHelper = require('./redis'); + +function OpenSourceUserContext (applicationConfiguration, dataClient, user, redisInstance, callback) { + var self = this; + var modernUser; + this.cache = { + orgs: {}, + users: {}, + }; + this.modernUser = function () { + return modernUser; + }; + this.setting = function (name) { + return applicationConfiguration[name]; + }; + this.dataClient = function () { + return dataClient; + }; + this.redisClient = function () { + return redisInstance; + }; + this.requestUser = function () { + return user; + }; + this.safeConfigurationTemp = safeSettings(applicationConfiguration); + this.authenticated = { + github: user && user.github && user.github.id, + azure: user && user.azure && user.azure.username, + }; + this.entities = { + link: null, + primaryMembership: null, + }; + this.usernames = { + github: user && user.github && user.github.username ? user.github.username : undefined, + azure: user && user.azure && user.azure.username ? user.azure.username : undefined, + }; + this.id = { + github: user && user.github && user.github.id ? user.github.id.toString() : undefined, + }; + if (this.id.github) { + modernUser = new User(this, this.id.github); + modernUser.login = this.usernames.github; + } + this.baseUrl = '/'; + this.redis = new RedisHelper(this, applicationConfiguration.redis.prefix); + this.initializeBasics(function () { + if (callback) { + return callback(null, self); + } + }); +} + +// ---------------------------------------------------------------------------- +// Populate the user's OSS context object. +// ---------------------------------------------------------------------------- +OpenSourceUserContext.prototype.initializeBasics = function (callback) { + var userObject = this.modernUser(); + if (!userObject) { + return callback(new Error("There's a logic bug in the user context object. We cannot continue.")); + } + var self = this; + userObject.getLink(function (error, link) { + if (error) { + return callback(utils.wrapError(error, 'We were not able to retrieve information about any link for your user account at this time.')); + } + if (link) { + self.entities.link = link; + } + callback(null, false); + /*self.org().queryUserMembership(true, function (error, result) { + // CONSIDER: This is part of the isAdministrator updates... + if (result && result.state && result.role && result.role === 'admin') { + self.entities.primaryMembership = result; + } + callback(null, false); + }); + */ + }); +}; + +// ---------------------------------------------------------------------------- +// SECURITY METHOD: +// Determine whether the authenticated user is an Administrator of the org. At +// this time there is a special "portal sudoers" team that is used. The GitHub +// admin flag is not used [any longer] for performance reasons to reduce REST +// calls to GitHub. +// ---------------------------------------------------------------------------- +OpenSourceUserContext.prototype.isPortalAdministrator = function (callback) { + /* + var self = this; + if (self.entities && self.entities.primaryMembership) { + var pm = self.entities.primaryMembership; + if (pm.role && pm.role === 'admin') { + return callback(null, true); + } + } + */ + this.org().getPortalSudoersTeam().isMember(function (error, isMember) { + if (error) { + return callback(utils.wrapError(error, + 'We had trouble querying GitHub for important team management ' + + 'information. Please try again later or report this issue.')); + } + callback(null, isMember === true); + }); +}; + +// ---------------------------------------------------------------------------- +// Create a simple GitHub client. Should be audited, since using this library +// directly may result in methods which are not cached, etc. +// ---------------------------------------------------------------------------- +OpenSourceUserContext.prototype.createGenericGitHubClient = function () { + var ownerToken = this.org().setting('ownerToken'); + if (!ownerToken) { + throw new Error('No "ownerToken" set for the ' + this.org().name + ' organization.'); + } + return github.client(ownerToken); +}; + +// ---------------------------------------------------------------------------- +// Make sure system links are loaded for a set of users. +// ---------------------------------------------------------------------------- +OpenSourceUserContext.prototype.getLinksForUsers = function (list, callback) { + var dc = this.dataClient(); + async.map(list, function (person, cb) { + if (person && person.id) { + cb(null, person.id); + } else { + cb(new Error('No ID known for this person instance.')); + } + }, function (error, map) { + if (error) { + return callback(error); + } + // In large organizations, we will have trouble getting this much data back + // all at once. + var groups = []; + var j = 0; + var perGroup = 200; + var group = []; + for (var i = 0; i < map.length; i++) { + if (j++ == perGroup) { + groups.push(group); + group = []; + j = 0; + } + group.push(map[i]); + } + if (group.length > 0) { + groups.push(group); + group = []; + } + async.each(groups, function (userGroup, cb) { + dc.getUserLinks(userGroup, function (error, links) { + if (error) { + // Specific to problems we've had with storage results... + if (error.headers && error.headers.statusCode && error.headers.body) { + var oldError = error; + error = new Error('Storage returned an HTTP ' + oldError.headers.statusCode + '.'); + console.error.log(oldError.headers.body); + error.innerError = oldError; + } + return cb(error); + } + // So inefficient and lazy: + for (var i = 0; i < list.length; i++) { + list[i].trySetLinkInstance(links, true); + } + cb(); + }); + }, function (error) { + callback(error ? error : null, error ? null : list); + }); + }); +}; + +// ---------------------------------------------------------------------------- +// Translate a list of IDs into developed objects and their system links. +// ---------------------------------------------------------------------------- +OpenSourceUserContext.prototype.getUsersAndLinksFromIds = function (list, callback) { + var self = this; + for (var i = 0; i < list.length; i++) { + var id = list[i]; + list[i] = self.user(id); + } + self.getLinksForUsers(list, callback); +}; + +// ---------------------------------------------------------------------------- +// Translate a hash of IDs to usernames into developed objects, system links +// and details loaded. Hash key is username, ID is the initial hash value. +// ---------------------------------------------------------------------------- +OpenSourceUserContext.prototype.getCompleteUsersFromUsernameIdHash = function (hash, callback) { + var self = this; + var users = {}; + var list = []; + for (var key in hash) { + var id = hash[key]; + var username = key; + var user = self.user(id); + user.login = username; + users[username] = user; + list.push(user); + } + async.parallel([ + function (cb) { + self.getLinksForUsers(list, cb); + }, + function (cb) { + async.each(list, function (user, innerCb) { + user.getDetailsByUsername(innerCb); + }, function (error) { + cb(error); + }); + }, + ], function (error) { + callback(error, users); + }); +}; + + +// ---------------------------------------------------------------------------- +// Retrieve all organizations that the user is a member of, if any. +// Caching: this set of calls can optionally turn off Redis caching, for use +// during onboarding. +// ---------------------------------------------------------------------------- +OpenSourceUserContext.prototype.getMyOrganizations = function (allowCaching, callback) { + var self = this; + if (typeof allowCaching == 'function') { + callback = allowCaching; + allowCaching = true; + } + var orgs = []; + async.each(self.orgs(), function (org, callback) { + org.queryUserMembership(allowCaching, function (error, result) { + var state = false; + if (result && result.state) { + state = result.state; + } + // Not sure how I feel about updating values on the org directly... + org.membershipStateTemporary = state; + orgs.push(org); + callback(error); + }); + }, function (error) { + callback(null, orgs); + }); +}; + +// ---------------------------------------------------------------------------- +// Retrieve all of the teams -across all registered organizations. This is not +// specific to the user. This will include secret teams. +// Caching: the org.getTeams call has an internal cache at this time. +// ---------------------------------------------------------------------------- +OpenSourceUserContext.prototype.getAllOrganizationsTeams = function (callback) { + var self = this; + async.concat(self.orgs(), function (org, cb) { + org.getTeams(cb); + }, function (error, teams) { + if (error) { + return callback(error); + } + // CONSIDER: SORT: Do these results need to be sorted? + callback(null, teams); + }); +}; + +// ---------------------------------------------------------------------------- +// This function uses heavy use of caching since it is an expensive set of +// calls to make to the GitHub API when the cache misses: N API calls for N +// teams in M organizations. +// ---------------------------------------------------------------------------- +OpenSourceUserContext.prototype.getMyTeamMemberships = function (role, alternateUserId, callback) { + var self = this; + if (typeof alternateUserId == 'function') { + callback = alternateUserId; + alternateUserId = self.id.github; + } + this.getAllOrganizationsTeams(function (error, teams) { + if (error) { + return callback(error); + } + var myTeams = []; + async.each(teams, function (team, callback) { + team.getMembersCached(role, function (error, members) { + if (error) { + return callback(error); + } + for (var i = 0; i < members.length; i++) { + var member = members[i]; + if (member.id == alternateUserId) { + myTeams.push(team); + break; + } + } + callback(); + }); + }, function (error) { + callback(error, myTeams); + }); + }); +}; + +// ---------------------------------------------------------------------------- +// Designed for use by tooling, this returns the full set of administrators of +// teams across all orgs. Designed to help setup communication with the people +// using this portal for their daily engineering group work. +// ---------------------------------------------------------------------------- +OpenSourceUserContext.prototype.getAllMaintainers = function (callback) { + this.getAllOrganizationsTeams(function (error, teams) { + if (error) { + return callback(error); + } + var users = {}; + async.each(teams, function (team, callback) { + team.getMembersCached('maintainer', function (error, members) { + if (error) { + return callback(error); + } + for (var i = 0; i < members.length; i++) { + var member = members[i]; + if (users[member.id] === undefined) { + users[member.id] = member; + } + // A dirty patch on top, just to save time now. + if (users[member.id]._getAllMaintainersTeams === undefined) { + users[member.id]._getAllMaintainersTeams = {}; + } + users[member.id]._getAllMaintainersTeams[team.id] = team; + } + callback(); + }); + }, function (error) { + var asList = []; + for (var key in users) { + var user = users[key]; + asList.push(user); + } + async.each(asList, function (user, cb) { + user.getLink(cb); + }, function (error) { + callback(error, asList); + }); + }); + }); +}; + + +// ---------------------------------------------------------------------------- +// Retrieve a set of team results. +// ---------------------------------------------------------------------------- +// [_] CONSIDER: Cache/ Consider caching this sort of important return result... +OpenSourceUserContext.prototype.getTeamSet = function (teamIds, inflate, callback) { + var self = this; + if (typeof inflate === 'function') { + callback = inflate; + inflate = false; + } + var teams = []; + async.each(teamIds, function (teamId, cb) { + self.getTeam(teamId, inflate, function (error, team) { + if (!error) { + teams.push(team); + } + cb(error); + }); + }, function (error) { + // CONSIDER: SORT: Do these results need to be sorted? + callback(error, teams); + }); +}; + +// ---------------------------------------------------------------------------- +// Retrieve a single team instance. This version hydrates the team's details +// and also sets the organization instance. +// ---------------------------------------------------------------------------- +// [_] CONSIDER: Cache/ Consider caching this sort of important return result... +OpenSourceUserContext.prototype.getTeam = function (teamId, callback) { + var self = this; + var team = createBareTeam(self, teamId); + team.getDetails(function (error) { + if (error) { + error = utils.wrapError(error, 'There was a problem retrieving the details for the team. The team may no longer exist.'); + } + callback(error, error ? null : team); + }); +}; + +// ---------------------------------------------------------------------------- +// Prepare a list of all organization names, lowercased, from the original +// config instance. +// ---------------------------------------------------------------------------- +function allOrgNamesLowercase(orgs) { + var list = []; + if (orgs && orgs.length) { + for (var i = 0; i < orgs.length; i++) { + var name = orgs[i].name; + if (!name) { + throw new Error('No organization name has been provided for one of the configured organizations.'); + } + list.push(name.toLowerCase()); + } + } + return list; +} + +// ---------------------------------------------------------------------------- +// Retrieve an array of all organizations registered for management with this +// portal instance. Used for iterating through global operations. We'll need to +// use smart caching to land this experience better than in the past, and to +// preserve API use rates. +// ---------------------------------------------------------------------------- +OpenSourceUserContext.prototype.orgs = function getAllOrgs() { + var self = this; + var allOrgNames = allOrgNamesLowercase(self.setting('organizations')); + var orgs = []; + for (var i = 0; i < allOrgNames.length; i++) { + orgs.push(self.org(allOrgNames[i])); + } + return orgs; +}; + +// ---------------------------------------------------------------------------- +// Retrieve a user-scoped elevated organization object via a static +// configuration lookup. +// ---------------------------------------------------------------------------- +OpenSourceUserContext.prototype.org = function getOrg(orgNameAnycase) { + if (orgNameAnycase === undefined || orgNameAnycase === '') { + orgNameAnycase = this.setting('organizations')[0].name; + } + var name = orgNameAnycase.toLowerCase(); + if (this.cache.orgs[name]) { + return this.cache.orgs[name]; + } + var settings; + var orgs = this.setting('organizations'); + for (var i = 0; i < orgs.length; i++) { + if (orgs[i].name && orgs[i].name.toLowerCase() == name) { + settings = orgs[i]; + break; + } + } + if (!settings) { + throw new Error('The requested organization "' + orgNameAnycase + '" is not currently available for actions or is not configured for use at this time.'); + } + var tr = this.setting('corporate').trainingResources; + if (tr && tr['onboarding-complete']) { + var tro = tr['onboarding-complete']; + var trainingResources = { + corporate: tro.all, + github: tro.github, + }; + if (tro[name]) { + trainingResources.organization = tro[name]; + } + settings.trainingResources = trainingResources; + } + this.cache.orgs[name] = new Org(this, settings.name, settings); + return this.cache.orgs[name]; +}; + +// ---------------------------------------------------------------------------- +// Retrieve an object representing the user, by GitHub ID. +// ---------------------------------------------------------------------------- +OpenSourceUserContext.prototype.user = function getUser(id, optionalGitHubInstance) { + var self = this; + if (typeof id != 'string') { + id = id.toString(); + } + if (self.cache.users[id]) { + return self.cache.users[id]; + } else { + self.cache.users[id] = new User(self, id, optionalGitHubInstance); + return self.cache.users[id]; + } +}; + +// ---------------------------------------------------------------------------- +// Allows creating a team reference with just a team ID, no org instance. +// ---------------------------------------------------------------------------- +function createBareTeam(oss, teamId) { + var teamInstance = new Team(oss.org(), teamId, null); + teamInstance.org = null; + return teamInstance; +} + +// ---------------------------------------------------------------------------- +// Helper function for UI: Store in the user's session an alert message or +// action to be shown in another successful render. Contexts come from Twitter +// Bootstrap, i.e. 'success', 'info', 'warning', 'danger'. +// ---------------------------------------------------------------------------- +OpenSourceUserContext.prototype.saveUserAlert = function (req, message, title, context, optionalLink, optionalCaption) { + var alert = { + message: message, + title: title || 'FYI', + context: context || 'success', + optionalLink: optionalLink, + optionalCaption: optionalCaption, + }; + if (req.session) { + if (req.session.alerts && req.session.alerts.length) { + req.session.alerts.push(alert); + } else { + req.session.alerts = [ + alert, + ]; + } + } +}; + +function safeSettings(config) { + // CONSIDER: IMPLEMENT. + return config; +} + +// ---------------------------------------------------------------------------- +// Helper function for UI: Render a view. By using our own rendering function, +// we can make sure that events such as alert views are still actually shown, +// even through redirect sequences. +// ---------------------------------------------------------------------------- +OpenSourceUserContext.prototype.render = function (req, res, view, title, optionalObject) { + if (typeof title == 'object') { + optionalObject = title; + title = ''; + debug('context::render: the provided title was actually an object'); + } + var breadcrumbs = req.breadcrumbs; + if (breadcrumbs && breadcrumbs.length && breadcrumbs.length > 0) { + breadcrumbs[breadcrumbs.length - 1].isLast = true; + } + var obj = { + title: title, + config: this.safeConfigurationTemp, + serviceBanner: this.setting('serviceBanner'), + user: this.requestUser(), + ossLink: this.entities.link, + showBreadcrumbs: true, + breadcrumbs: breadcrumbs, + sudoMode: req.sudoMode, + }; + if (optionalObject) { + utils.merge(obj, optionalObject); + } + if (req.session && req.session.alerts && req.session.alerts.length && req.session.alerts.length > 0) { + var alerts = []; + utils.merge(alerts, req.session.alerts); + req.session.alerts = []; + for (var i = 0; i < alerts.length; i++) { + if (typeof alerts[i] == 'object') { + alerts[i].number = i + 1; + } + } + obj.alerts = alerts; + } + res.render(view, obj); +}; + +// ---------------------------------------------------------------------------- +// Cheap breadcrumbs on a request object as it goes through our routes. Does +// not actually store anything in the OSS instance at this time. +// ---------------------------------------------------------------------------- +OpenSourceUserContext.prototype.addBreadcrumb = function (req, breadcrumbTitle, optionalBreadcrumbLink) { + utils.addBreadcrumb(req, breadcrumbTitle, optionalBreadcrumbLink); +}; + +module.exports = OpenSourceUserContext; diff --git a/oss/issue.js b/oss/issue.js new file mode 100644 index 00000000..ef4beaf9 --- /dev/null +++ b/oss/issue.js @@ -0,0 +1,36 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +// CONSIDER: Cleanup issue.js. + +function OpenSourceIssue (repoInstance, issueNumber, optionalInitialData) { + this.repo = repoInstance; + if (!repoInstance.full_name) { + throw new Error('No full_name set for this instance.'); + } + this.oss = repoInstance.oss; + this.number = issueNumber; + if (optionalInitialData) { + throw new Error('optionalInitialData is not yet supported for the OpenSourceIssue type.'); + } +} + +OpenSourceIssue.prototype.createComment = function (body, callback) { + this.oss.createGenericGitHubClient().issue(this.repo.full_name, this.number).createComment({ + body: body + }, callback); +}; + +OpenSourceIssue.prototype.update = function (patch, callback) { + this.oss.createGenericGitHubClient().issue(this.repo.full_name, this.number).update(patch, callback); +}; + +OpenSourceIssue.prototype.close = function (callback) { + this.oss.createGenericGitHubClient().issue(this.repo.full_name, this.number).update({ + state: 'closed', + }, callback); +}; + +module.exports = OpenSourceIssue; diff --git a/oss/org.js b/oss/org.js new file mode 100644 index 00000000..386c3197 --- /dev/null +++ b/oss/org.js @@ -0,0 +1,709 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +var async = require('async'); +var github = require('octonode'); +var debug = require('debug')('azureossportal'); +var utils = require('../utils'); +var Team = require('./team'); +var Repo = require('./repo'); + +function OpenSourceOrganization (ossInstance, name, settings) { + var self = this; + self.name = name; + // CONSIDER: Do not expose. + self.inner = { + settings: settings, + teams: {}, + repos: {}, + }; + self.oss = ossInstance; + self.baseUrl = self.oss.baseUrl + name + '/'; + self.setting = function (name) { + var value = self.inner.settings[name]; + if (value === undefined) { + debug('setting ' + name + ' is undefined!'); + } + return value; + }; +} + +// ---------------------------------------------------------------------------- +// Create a GitHub 'octonode' client using our standard owner elevation token +// or an alternate token. +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.createGenericGitHubClient = function createGitHubClient(alternateToken) { + var ownerToken = this.inner.settings.ownerToken; + if (!ownerToken) { + throw new Error('No "ownerToken" available for the ' + this.name + ' organization.'); + } + return github.client(alternateToken || ownerToken); +}; + +// ---------------------------------------------------------------------------- +// With the GitHub OAuth scope of 'write:org', we can accept the invitation for +// the user on their behalf, improving the onboarding workflow from our earlier +// implementation with the invitation dance and hop. +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.acceptOrganizationInvitation = function acceptInvite(userToken, callback) { + if (!userToken) { + return callback(new Error('No GitHub token available for the user operation.')); + } + this.createGenericGitHubClient(userToken).me().updateMembership(this.name, 'active', callback); +}; + +// ---------------------------------------------------------------------------- +// Special Team: "Everyone" team used for handling invites and 2FA checks. +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.getAllMembersTeam = function (throwIfMissing) { + return getSpecialTeam(this, 'teamAllMembers', 'all members', throwIfMissing); +}; + +// ---------------------------------------------------------------------------- +// Special Team: "Repo Approvers" for the repo create workflow. +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.getRepoApproversTeam = function (throwIfMissing) { + return getSpecialTeam(this, 'teamRepoApprovers', 'repo create approvers', throwIfMissing); +}; + +// ---------------------------------------------------------------------------- +// Get the highlighted teams for the org, if any. +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.getHighlightedTeams = function () { + var highlightedTeams = this.inner.settings.highlightedTeams; + var teams = []; + if (utils.isArray(highlightedTeams)) { + for (var i = 0; i < highlightedTeams.length; i++) { + var team = this.team(highlightedTeams[i].id); + teams.push(team); + } + } + return teams; +}; + +// ---------------------------------------------------------------------------- +// Special Team: "All Repos" which receives access to all repos in the org. +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.getSecurityTeam = function (throwIfMissing) { + return getSpecialTeam(this, 'teamAllRepos', 'all repos access team', throwIfMissing); +}; + +// ---------------------------------------------------------------------------- +// Special Team: "All Repo Write" which gives write access to all repos for +// very specific engineering system use cases. +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.getAllRepoWriteTeam = function (throwIfMissing) { + return getSpecialTeam(this, 'teamAllRepoWriteId', 'all repo write team', throwIfMissing); +}; + +// ---------------------------------------------------------------------------- +// Retrieve a user-scoped team object. +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.team = function getTeam(id, optionalInitialData) { + var self = this; + if (typeof id != 'string') { + id = id.toString(); + } + if (self.inner.teams[id]) { + var team = self.inner.teams[id]; + if (team._detailsLoaded === false && optionalInitialData) { + team.setDetails(optionalInitialData); + } + return team; + } else { + self.inner.teams[id] = new Team(self, id, optionalInitialData); + return self.inner.teams[id]; + } +}; + +// ---------------------------------------------------------------------------- +// Retrieve a user-scoped repo object. +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.repo = function getRepo(repoName, optionalInitialData) { + var self = this; + var normalized = repoName.toLowerCase(); + if (self.inner.repos[normalized]) { + return self.inner.repos[normalized]; + } else { + self.inner.repos[normalized] = new Repo(self, repoName, optionalInitialData); + return self.inner.repos[normalized]; + } +}; + +// ---------------------------------------------------------------------------- +// Get a repository client for the notifications repo used in the workflow. +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.getWorkflowRepository = function () { + var repoName = this.inner.settings.notificationRepo; + if (!repoName) { + throw new Error('No workflow/notification repository is defined for the organization.'); + } + return this.repo(repoName); +}; + +// ---------------------------------------------------------------------------- +// Retrieve a team object by name. To be much more efficient, this should +// actually live in a global memory cache (vs per-user context like the other +// OSS instances). But it works for now. +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.teamFromName = function getTeamName(teamName, callback) { + var self = this; + this.getTeams(true /* allow caching */, function (error, teams) { + if (error) { + return callback(error); + } + for (var i = 0; i < teams.length; i++) { + var name = teams[i].name; + var slug = teams[i].slug; + if (name && name.toLowerCase && name.toLowerCase() == teamName.toLowerCase()) { + var redirectError = null; + if (name.toLowerCase() != slug.toLowerCase()) { + redirectError = new Error(); + redirectError.status = 401; + redirectError.slug = slug; + } + return callback(redirectError, teams[i]); + } + if (slug && slug.toLowerCase && slug.toLowerCase() == teamName.toLowerCase()) { + return callback(null, teams[i]); + } + } + // Make a secondary request without caching, to be sure... it may have just + // been created, for example. + self.getTeams(false, function (error, teams) { + if (error) { + return callback(error); + } + for (var i = 0; i < teams.length; i++) { + var name = teams[i].name; + if (name && name.toLowerCase && name.toLowerCase() == teamName) { + return callback(null, teams[i]); + } + } + return callback(null, null); + }); + }); +}; + +// ---------------------------------------------------------------------------- +// SECURITY METHOD: +// Is the user in this context authorized as a sudoer of this organization? +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.isUserSudoer = function (callback) { + this.getSudoersTeam().isMember(function (error, isMember) { + if (error) { + return callback(utils.wrapError(error, + 'We had trouble querying GitHub for important team management ' + + 'information. Please try again later or report this issue.')); + } + callback(null, isMember === true); + }); +}; + +// ---------------------------------------------------------------------------- +// Special Team: Sudoers for this specific organization. The members +// of this team have semi-sudoers ability - the ability to maintain their org +// as needed. It is important to notice that the organization that the sudoers +// are in may actually be the primary org and not the leaf node org. +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.getSudoersTeam = function () { + var self = this; + var config = self.inner.settings; + if (config && config.teamSudoers) { + return self.team(config.teamSudoers); + } else { + throw new Error('Configuration for the sudoers team is missing.'); + } +}; + +// ---------------------------------------------------------------------------- +// Special Team: Portal sudoers. This only applies to the first org. +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.getPortalSudoersTeam = function () { + var self = this; + var config = self.inner.settings; + if (config && config.teamPortalSudoers) { + return self.team(config.teamPortalSudoers); + } else { + throw new Error('Configuration for the portal sudoers team is missing.'); + } +}; + +// ---------------------------------------------------------------------------- +// Check for public membership +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.queryUserPublicMembership = function getSingleUserMembership(callback) { + var self = this; + var ghorg = self.createGenericGitHubClient().org(self.name); + ghorg.publicMember(self.oss.usernames.github, function (error, result) { + return callback(null, result === true); + }); +}; + +// ---------------------------------------------------------------------------- +// Make membership public for the authenticated user. +// Requires an expanded GitHub API scope (write:org). +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.setPublicMembership = function goPublic(userToken, callback) { + var ghorg = this.createGenericGitHubClient(userToken).org(this.name); + ghorg.publicizeMembership(this.oss.usernames.github, callback); +}; + +// ---------------------------------------------------------------------------- +// Make membership private for the authenticated user. +// Requires an expanded GitHub API scope (write:org). +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.setPrivateMembership = function goPrivate(userToken, callback) { + var ghorg = this.createGenericGitHubClient(userToken).org(this.name); + ghorg.concealMembership(this.oss.usernames.github, callback); +}; + +// ---------------------------------------------------------------------------- +// Create a repository on GitHub within this org. +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.createRepository = function createRepo(name, properties, callback) { + if (typeof properties == 'function') { + callback = properties; + properties = {}; + } + var ghorg = this.createGenericGitHubClient().org(this.name); + var repoProperties = { + name: name, + }; + utils.merge(repoProperties, properties); + ghorg.repo(repoProperties, callback); +}; + +// ---------------------------------------------------------------------------- +// Check for membership (private or public). Use Redis for performance reasons +// and fallback to a live API query for pending/negative results. +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.queryUserMembership = function getSingleUserGeneralMembership(allowRedis, callback) { + var self = this; + if (typeof allowRedis == 'function') { + callback = allowRedis; + allowRedis = true; + } + if (allowRedis === true) { + return self.queryUserMembershipCached(callback); + } + self.createGenericGitHubClient().org(self.name).membership(self.oss.usernames.github, function (error, result) { + if (!(result && result.state && (result.state == 'active' || result.state == 'pending'))) { + result = false; + } + var redisKey = 'user#' + self.oss.id.github + ':org#' + self.name + ':membership'; + self.oss.redis.setObjectWithExpire(redisKey, result, 60 * 48 /* 2 days */, function () { + callback(null, result); + }); + }); +}; + +// ---------------------------------------------------------------------------- +// Check for membership (private or public) for any GitHub username. Does not +// cache. +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.queryAnyUserMembership = function (username, callback) { + var self = this; + self.createGenericGitHubClient().org(self.name).membership(username, function (error, result) { + if (!(result && result.state && (result.state == 'active' || result.state == 'pending'))) { + result = false; + } + callback(null, result); + }); +}; + +// ---------------------------------------------------------------------------- +// Clears the cached state for a user's organization membership value. +// ---------------------------------------------------------------------------- +function removeCachedUserMembership(self, callback) { + var redisKey = 'user#' + self.oss.id.github + ':org#' + self.name + ':membership'; + self.oss.redis.delete(redisKey, function () { + callback(); + }); +} + +// ---------------------------------------------------------------------------- +// Check for membership (private or public). Use Redis for performance reasons +// (the "active" example) and always fallback to a live API query when needed. +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.queryUserMembershipCached = function getSingleUserGeneralMembershipCached(callback) { + var self = this; + var redisKey = 'user#' + self.oss.id.github + ':org#' + self.name + ':membership'; + self.oss.redis.getObject(redisKey, function (error, data) { + if (!error && data && data.state && data.state == 'active') { + return callback(null, data); + } + self.createGenericGitHubClient().org(self.name).membership(self.oss.usernames.github, function (error, result) { + if (error) { + error = null; + result = false; + } + self.oss.redis.setObjectWithExpire(redisKey, result, 60 * 48 /* 2 days */, function () { + callback(null, result); + }); + }); + }); +}; + +// ---------------------------------------------------------------------------- +// Remove the user from the organization. +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.removeUserMembership = function dropUser(optionalUsername, callback) { + var self = this; + if (typeof optionalUsername == 'function') { + callback = optionalUsername; + optionalUsername = self.oss.usernames.github; + } + self.createGenericGitHubClient().org(self.name).removeMember(optionalUsername, function (error, result) { + removeCachedUserMembership(self, function () { + callback(error, result); + }); + }); +}; + +// ---------------------------------------------------------------------------- +// Retrieve the list of all teams in the organization. This is not specific to +// the user but instead a general query across this org. +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.getTeams = function getBasicTeamList(allowRedis, callback) { + var self = this; + if (typeof allowRedis == 'function') { + callback = allowRedis; + allowRedis = true; + } + var instancesFromJson = function (teamInstances) { + async.map(teamInstances, function (teamInstance, cb) { + cb(null, self.team(teamInstance.id, teamInstance)); + }, callback); + }; + var redisKey = 'org#' + self.name + ':teams'; + self.oss.redis.getObject(redisKey, function (error, data) { + if (!error && data && allowRedis === true) { + return instancesFromJson(data); + } + var ghorg = self.createGenericGitHubClient().org(self.name); + utils.retrieveAllPages(ghorg.teams.bind(ghorg), function (error, teamInstances) { + if (error) { + return callback(error); + } + self.oss.redis.setObjectWithExpire(redisKey, teamInstances, utils.randomInteger(20, 90), function () { + instancesFromJson(teamInstances); + }); + }); + }); +}; + +// ---------------------------------------------------------------------------- +// Clear the organization's team list cache. +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.clearTeamsCache = function (callback) { + var redisKey = 'org#' + this.name + ':teams'; + this.oss.redis.delete(redisKey, function () { + callback(); + }); +}; + +// ---------------------------------------------------------------------------- +// Gets all source repos for the organization. +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.getRepos = function getRepos(allowRedis, callback) { + var self = this; + if (typeof allowRedis == 'function') { + callback = allowRedis; + allowRedis = true; + } + var instancesFromJson = function (repos) { + async.map(repos, function (repo, cb) { + cb(null, self.repo(repo.name, repo)); + }, callback); + }; + var redisKey = 'org#' + self.name + ':repos'; + self.oss.redis.getObject(redisKey, function (error, data) { + if (!error && data && allowRedis === true) { + return instancesFromJson(data); + } + var ghorg = self.createGenericGitHubClient().org(self.name); + utils.retrieveAllPages(ghorg.repos.bind(ghorg), { + 'type': 'sources', + }, function (error, repos) { + if (error) { + return callback(error); + } + self.oss.redis.setObjectWithExpire(redisKey, repos, utils.randomInteger(30, 60 * 12), function () { + instancesFromJson(repos); + }); + }); + }); +}; + +// ---------------------------------------------------------------------------- +// Gets a list of team memberships for the authenticated user. This is a slower +// implementation than the GitHub API provides, since that requires additional +// authenticated scope, which our users have had negative feedback about +// requiring. Instead, this uses an org-authorized token vs the user's. +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.getMyTeamMemberships = function (role, alternateUserId, callback) { + var self = this; + if (typeof alternateUserId == 'function') { + callback = alternateUserId; + alternateUserId = self.oss.id.github; + } + self.getTeams(function (error, teams) { + if (error) { + return callback(error); + } + var myTeams = []; + async.each(teams, function (team, callback) { + team.getMembersCached(role, function (error, members) { + if (error) { + return callback(error); + } + for (var i = 0; i < members.length; i++) { + var member = members[i]; + if (member.id == alternateUserId) { + myTeams.push(team); + break; + } + } + callback(); + }); + }, function (error) { + callback(error, myTeams); + }); + }); +}; + +// ---------------------------------------------------------------------------- +// Builds a hash mapping organization member's GitHub user IDs to a cached +// member object. This version actually walks all of the teams, which is a +// super CPU-intensive way to do this, but it makes some use of Redis. Need +// to fix that someday and cache the whole thing probably. +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.getAllMembersById = function (callback) { + var self = this; + var memberHash = {}; + self.getTeams(function (error, teams) { + if (error) { + return callback(error); + } + async.each(teams, function (team, callback) { + team.getMembersCached('all', function (error, members) { + if (error) { + return callback(error); + } + for (var i = 0; i < members.length; i++) { + var member = members[i]; + if (memberHash[member.id] === undefined) { + memberHash[member.id] = member; + } + } + callback(); + }); + }, function (error) { + callback(error, memberHash); + }); + }); +}; + +// ---------------------------------------------------------------------------- +// Retrieve the list of all accounts in the org that do not have multi-factor +// (modern security) auth turned on. Uses the GitHub API. This version uses a +// cache to speed up the use of the site. +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.getAuditListCached = function getAuditListCached(callback) { + var self = this; + var redisKey = 'org#' + self.name + ':2fa-disabled'; + var ghorg = this.createGenericGitHubClient().org(this.name); + self.oss.redis.getObject(redisKey, function (error, data) { + if (!error && data) { + return mapUsernameToId(data, callback); + } + utils.retrieveAllPages(ghorg.members.bind(ghorg), { filter: '2fa_disabled' }, function (error, people) { + if (error) { + return callback(error); + } + self.oss.redis.setObjectWithExpire(redisKey, people, 60 * 48 /* 2 days */, function () { + mapUsernameToId(people, callback); + }); + }); + }); +}; + +// ---------------------------------------------------------------------------- +// Retrieve a hash, by username, of all admins for the organization. +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.getAdministratorsHashCached = function getAdminsCached(callback) { + var self = this; + var redisKey = 'org#' + self.name + ':admins'; + var ghorg = this.createGenericGitHubClient().org(this.name); + self.oss.redis.getObject(redisKey, function (error, data) { + if (!error && data) { + return mapUsernameToId(data, callback); + } + utils.retrieveAllPages(ghorg.members.bind(ghorg), { role: 'admin' }, function (error, people) { + if (error) { + return callback(error); + } + self.oss.redis.setObjectWithExpire(redisKey, people, 60 * 48 /* 2 days */, function () { + mapUsernameToId(people, callback); + }); + }); + }); +}; + +// ---------------------------------------------------------------------------- +// Check whether this user has multi-factor authentication turned on. Returns +// true for a user in good standing. +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.queryUserMultifactorStateOk = function getSingleUserMfaState(callback) { + var self = this; + self.getAuditList(function (error, list) { + if (error) { + return callback(utils.wrapError(error, 'A problem occurred while trying to query important information about the org.')); + } + var twoFactorOff = list[self.oss.usernames.github.toLowerCase()] !== undefined; + callback(null, twoFactorOff === false); + }); +}; + +// ---------------------------------------------------------------------------- +// Check whether this user has multi-factor authentication turned on. Returns +// true for a user in good standing. Uses the cache initially. If the cache +// result implies that this user may not be in compliance, we reach out with a +// real GitHub API request, resetting the cache and writing the results. This +// was the user only receives false in the case of an API failure or actually +// not having multifactor authentication turned on. +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.queryUserMultifactorStateOkCached = function getSingleUserMfaStateCached(callback) { + var self = this; + self.getAuditListCached(function (error, list) { + if (error) { + return callback(utils.wrapError(error, 'A problem occurred while trying to query important information about the org.')); + } + var twoFactorOff = list[self.oss.usernames.github.toLowerCase()] !== undefined; + if (twoFactorOff === false) { + return callback(null, true); + } + // Go to the live version of the app... + self.getAuditList(function (error, list) { + if (error) { + return callback(utils.wrapError(error, 'A problem occurred while trying to read the current authentication state for your account. Please check that you have turned multifactor authentication on for your GitHub account - thanks.')); + } + var twoFactorOff = list[self.oss.usernames.github.toLowerCase()] !== undefined; + callback(null, twoFactorOff === false); + }); + }); +}; + +// ---------------------------------------------------------------------------- +// Retrieve the list of all accounts in the org that do not have multi-factor +// (modern security) auth turned on. Uses the GitHub API. +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.getAuditList = function getAuditList(callback) { + var self = this; + var ghorg = this.createGenericGitHubClient().org(this.name); + utils.retrieveAllPages(ghorg.members.bind(ghorg), { filter: '2fa_disabled' }, function (error, people) { + if (error) { + return callback(error); + } + // Cache the result, updating the org-wide view... + var redisKey = 'org#' + self.name + ':2fa-disabled'; + self.oss.redis.setObjectWithExpire(redisKey, people, 60 * 48 /* 2 days */, function () { + mapUsernameToId(people, callback); + }); + }); +}; + +// ---------------------------------------------------------------------------- +// Clear the cached MFA list for this organization. +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.clearAuditList = function clearAuditList(callback) { + var self = this; + var redisKey = 'org#' + self.name + ':2fa-disabled'; + self.oss.redis.delete(redisKey, function () { + callback(); + }); +}; + +// ---------------------------------------------------------------------------- +// Get the cached high-level information from GitHub for this organization. +// Unlike the team and user objects, these properties are simply returned to +// the caller and not merged into the type and its values. +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.getDetails = function getOrgDetails(allowRedis, callback) { + var self = this; + if (typeof allowRedis == 'function') { + callback = allowRedis; + allowRedis = true; + } + var redisKey = 'org#' + self.name + ':details'; + self.oss.redis.getObject(redisKey, function (error, data) { + if (!error && data && allowRedis === true) { + return callback(null, data); + } + var ghorg = self.createGenericGitHubClient().org(self.name); + ghorg.info(function (error, info) { + if (error) { + return callback(utils.wrapError(error, 'The GitHub API had trouble returning information about the organization ' + self.name)); + } + self.oss.redis.setObjectWithExpire(redisKey, info, utils.randomInteger(60 * 24, 60 * 24 * 2), function () { + callback(null, info); + }); + }); + }); +}; + + +// ---------------------------------------------------------------------------- +// Gets the organization's psuedo-user account details from GitHub. +// ---------------------------------------------------------------------------- +OpenSourceOrganization.prototype.getOrganizationUserProfile = function getOrganizationUserProfile(callback) { + var self = this; + this.getDetails(function (error, details) { + if (error || !details) { + return callback(utils.wrapError(error, 'We had trouble retrieving the profile of the ' + self.name + ' organization from GitHub.')); + } + var user = self.oss.user(details.id, details); + callback(null, user); + }); +}; + +// ---------------------------------------------------------------------------- +// Private: Project a team members list to a dictionary of username:id. +// ---------------------------------------------------------------------------- +function mapUsernameToId(people, callback) { + var projected = {}; + async.each(people, function (person, cb) { + if (person.id && person.login && person.login.toLowerCase) { + projected[person.login.toLowerCase()] = person.id; + } + cb(); + }, function (error) { + callback(error, error ? undefined : projected); + }); +} + +// ---------------------------------------------------------------------------- +// Private: get a special team instance +// ---------------------------------------------------------------------------- +function getSpecialTeam(org, configName, prettyName, throwIfMissing) { + if (throwIfMissing === undefined) { + throwIfMissing = true; + } + var mySettings = org.inner.settings; + if (mySettings[configName]) { + return org.team(mySettings[configName]); + } else { + var message = 'Configuration is missing. The "' + prettyName + '" team is not defined.'; + if (throwIfMissing === true) { + throw new Error(message); + } else { + debug(message); + return null; + } + } +} + +module.exports = OpenSourceOrganization; diff --git a/oss/redis.js b/oss/redis.js new file mode 100644 index 00000000..d519fb17 --- /dev/null +++ b/oss/redis.js @@ -0,0 +1,99 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +var async = require('async'); +var debug = require('debug')('oss-redis'); +var utils = require('../utils'); + +function RedisHelper (ossInstance, prefix) { + this.oss = ossInstance; + this.redis = ossInstance.redisClient(); + this.prefix = prefix ? prefix + ',' : ''; +} + +function objectFromJson(json, callback) { + var error = null; + var object = null; + try { + if (json) { + object = JSON.parse(json); + } + } catch (ex) { + error = ex; + object = null; + } + callback(error, object); +} + +function objectToJson(object, callback) { + var error = null; + var json = null; + try { + json = JSON.stringify(object); + } catch (ex) { + error = ex; + } + callback(error, json); +} + +RedisHelper.prototype.get = function (key, callback) { + var k = this.prefix + key; + // debug('GET ' + k); + this.redis.get(k, callback); +}; + +RedisHelper.prototype.set = function (key, value, callback) { + var k = this.prefix + key; + debug('SET ' + k); + this.redis.set(k, value, callback); +}; + + +RedisHelper.prototype.delete = function (key, callback) { + var k = this.prefix + key; + debug('DEL ' + k); + this.redis.del(k, callback); +}; + +RedisHelper.prototype.setWithExpire = function (key, value, minutesToExpire, callback) { + var k = this.prefix + key; + debug('SET ' + k + ' EX ' + minutesToExpire + 'm'); + this.redis.set(k, value, 'EX', minutesToExpire * 60, callback); +}; + +// Helper versions for object/json conversions + +RedisHelper.prototype.getObject = function (key, callback) { + this.get(key, function (error, json) { + if (error) { + return callback(error); + } + objectFromJson(json, callback); + }); +}; + +RedisHelper.prototype.setObject = function (key, value, callback) { + var self = this; + objectToJson(value, function (error, json) { + if (!error) { + self.set(key, json, callback); + } else { + callback(error); + } + }); +}; + +RedisHelper.prototype.setObjectWithExpire = function (key, value, minutesToExpire, callback) { + var self = this; + objectToJson(value, function (error, json) { + if (!error) { + self.setWithExpire(key, json, minutesToExpire, callback); + } else { + callback(error); + } + }); +}; + +module.exports = RedisHelper; diff --git a/oss/repo.js b/oss/repo.js new file mode 100644 index 00000000..2861f064 --- /dev/null +++ b/oss/repo.js @@ -0,0 +1,314 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +var async = require('async'); +var github = require('octonode'); +var debug = require('debug')('azureossportal'); +var utils = require('../utils'); +var Issue = require('./issue'); + +function OpenSourceRepo (orgInstance, repoName, optionalGitHubInstance) { + if (!orgInstance) { + throw new Error('orgInstance is not defined.'); + } + this.org = orgInstance; + this.oss = this.org.oss; + var i = repoName.indexOf('/'); + if (i >= 0) { + this.full_name = repoName; + var orgName = repoName.substring(0, i); + repoName = repoName.substring(i + 1); + if (orgName.toLowerCase() !== orgInstance.name.toLowerCase()) { + debug('WARNING: The org name does not match: (' + orgName + ', ' + orgInstance.name + ')'); + } + } else { + this.full_name = orgInstance.name + '/' + repoName; + } + this.name = repoName; + this.inner = { + issues: {} + }; + this.otherFields = {}; + this._detailsLoaded = false; + if (optionalGitHubInstance) { + setDetails(this, optionalGitHubInstance); + } +} + +// ---------------------------------------------------------------------------- +// Properties of interest in the standard GitHub response for a user +// ---------------------------------------------------------------------------- +var detailsToCopy = [ + 'id', + 'name', + 'full_name', + 'private', + 'html_url', + 'description', + 'fork', + 'url', + 'created_at', + 'updated_at', + 'pushed_at', + 'git_url', + 'ssh_url', + 'clone_url', + 'homepage', + 'size', + 'stargazers_count', + 'watchers_count', + 'language', + 'has_issues', + 'has_downloads', + 'has_wiki', + 'has_pages', + 'forks_count', + 'open_issues_count', + 'forks', + 'open_issues', + 'watchers', + 'default_branch', + 'permissions', +]; +var detailsToSkip = [ + 'owner', + 'forks_url', + 'keys_url', + 'collaborators_url', + 'teams_url', + 'hooks_url', + 'issue_events_url', + 'events_url', + 'assignees_url', + 'branches_url', + 'tags_url', + 'blobs_url', + 'git_tags_url', + 'git_refs_url', + 'trees_url', + 'statuses_url', + 'languages_url', + 'stargazers_url', + 'contributors_url', + 'subscribers_url', + 'subscription_url', + 'commits_url', + 'git_commits_url', + 'comments_url', + 'issue_comment_url', + 'contents_url', + 'compare_url', + 'merges_url', + 'archive_url', + 'downloads_url', + 'issues_url', + 'pulls_url', + 'milestones_url', + 'notifications_url', + 'labels_url', + 'releases_url', + 'svn_url', + 'mirror_url', +]; + +// ---------------------------------------------------------------------------- +// Creates a GitHub API client for this repo. +// ---------------------------------------------------------------------------- +OpenSourceRepo.prototype.createGitHubRepoClient = function () { + var client = this.org.createGenericGitHubClient(); + debug('creating repo client for ' + this.org.name + '/' + this.name); + return client.repo(this.org.name + '/' + this.name); +}; + +// ---------------------------------------------------------------------------- +// Get contribution statistics for the repo. +// ---------------------------------------------------------------------------- +OpenSourceRepo.prototype.contributorsStatsOneTime = function (callback) { + this.createGitHubRepoClient().contributorsStats(function (error, stats) { + if (error) { + var er = utils.wrapError(error, ''); + if (error && error.status && error.status == 202) { + er.status = 202; + } + return callback(er); + } + callback(null, stats); + }); +}; + +// ---------------------------------------------------------------------------- +// Add a collaborator with a specified permission level. +// ---------------------------------------------------------------------------- +OpenSourceRepo.prototype.addCollaborator = function (githubUsername, permissionLevel, callback) { + if (typeof permissionLevel == 'function') { + callback = permissionLevel; + permissionLevel = 'pull'; + } + this.createGitHubRepoClient().addCollaborator(githubUsername, { + permission: permissionLevel, + }, function(error, info) { + if (error) { + var message = error.statusCode == 404 ? 'The GitHub username "' + githubUsername + '" does not exist.' : 'The collaborator could not be added to GitHub at this time. There may be a problem with the GitHub API.'; + error.skipLog = error.statusCode == 404; + return callback(utils.wrapError(error, message)); + } + callback(); + }); +}; + +// ---------------------------------------------------------------------------- +// Remove a collaborator. +// ---------------------------------------------------------------------------- +OpenSourceRepo.prototype.removeCollaborator = function (githubUsername, callback) { + var self = this; + this.createGitHubRepoClient().removeCollaborator(githubUsername, function(error) { + if (error) { + return callback(utils.wrapError(error, 'The collaborator could not be removed at this time. Was "' + githubUsername + '" even a collaborator for ' + self.name + '?')); + } + callback(); + }); +}; + +// ---------------------------------------------------------------------------- +// Get the list of collaborators for the repo from GitHub. +// ---------------------------------------------------------------------------- +// CONSIDER: Use the Redis cache for this super hacky call. +OpenSourceRepo.prototype.getOutsideCollaborators = function (callback) { + var self = this; + var client = this.createGitHubRepoClient(); + this.org.getAdministratorsHashCached(function (error, adminUsernamesToIds) { + var administratorIds = {}; + for (var admin in adminUsernamesToIds) { + administratorIds[adminUsernamesToIds[admin]] = true; + } + self.org.getAllMembersById(function (error, membersHash) { + if (error) { + return callback(utils.wrapError(error, 'While looking up collaborators, we were not able to retrieve organization membership information.')); + } + utils.retrieveAllPages(client.collaborators.bind(client), function (error, collaborators) { + if (error) { + return callback(utils.wrapError(error, 'We ran into a problem while trying to retrieve the collaborators for this repo.')); + } + async.map(collaborators, function (data, cb) { + var rcp = data.permissions; + delete data.permissions; + var user = self.oss.user(data.id, data); + user._repoCollaboratorPermissions = rcp; + cb(null, user); + }, function (error, collaboratorObjects) { + // This is a workaround as suggested by GitHub. + var corporateUsersToRemove = {}; + var corporateUsersWithCollaborationRights = []; + async.each(collaboratorObjects, function (co, cb) { + if (administratorIds[co.id]) { + // Organization admin + corporateUsersToRemove[co.id] = true; + return cb(); + } + if (membersHash[co.id]) { + corporateUsersToRemove[co.id] = true; + if (co._repoCollaboratorPermissions && co._repoCollaboratorPermissions.admin === true) { + // This is a corporate user who has collaborator rights for this one. + // We will still resolve the link. + corporateUsersWithCollaborationRights.push(co); + return co.getLink(function (ignored, link) { + cb(); + }); + } + } + cb(); + }, function (error) { + if (error) { + return callback(error); + } + async.reject(collaboratorObjects, function (co, cb) { + cb(corporateUsersToRemove[co.id] === true); + }, function (results) { + async.sortBy(results, function (entry, cb) { + cb(null, entry.login); + }, function (error, sorted) { + callback(error, sorted, corporateUsersWithCollaborationRights); + }); + }); + }); + }); + }); + }); + }); +}; + +// ---------------------------------------------------------------------------- +// Update the repo properties with a patch. +// ---------------------------------------------------------------------------- +OpenSourceRepo.prototype.update = function updateRepo(patch, callback) { + // CONSIDER: Wrap errors. + this.createGitHubRepoClient().update(patch, callback); +}; + +// ---------------------------------------------------------------------------- +// Delete the repo from GitHub. +// ---------------------------------------------------------------------------- +OpenSourceRepo.prototype.delete = function updateRepo(patch, callback) { + // CONSIDER: Wrap errors. + this.createGitHubRepoClient().destroy(callback); +}; + +// ---------------------------------------------------------------------------- +// Retrieve a repo-scoped issue object. +// ---------------------------------------------------------------------------- +OpenSourceRepo.prototype.issue = function getIssueInstance(issueNumber, optionalInitialData) { + var self = this; + if (typeof issueNumber != 'string') { + issueNumber = issueNumber.toString(); + } + if (self.inner.issues[issueNumber]) { + return self.inner.issues[issueNumber]; + } else { + self.inner.issues[issueNumber] = new Issue(self, issueNumber, optionalInitialData); + return self.inner.issues[issueNumber]; + } +}; + +// CONSIDER: OLD: Is this needed still? +OpenSourceRepo.prototype.createIssue = function (issue, callback) { + var fullName = this.full_name; + var repositoryClient = this.oss.createGenericGitHubClient().repo(fullName); + repositoryClient.createIssue(issue, function (error, createdIssue) { + if (error) { + error = utils.wrapError(error, 'We had trouble opening an issue to track this request in the ' + fullName + ' repo.'); + } + callback(error, createdIssue); + }); +}; + +// CONSIDER: OLD: Is this needed still? +OpenSourceRepo.prototype.updateIssue = function (issueNumber, patch, callback) { + var fullName = this.full_name; + var issueClient = this.oss.createGenericGitHubClient().issue(this.full_name, issueNumber); + issueClient.update(patch, function (error, updatedIssue) { + if (error) { + error = utils.wrapError(error, 'We had trouble updated the issue in the ' + fullName + ' repo.'); + } + callback(error, updatedIssue); + }); +}; + +function setDetails(self, details) { + var key = null; + for (var i = 0; i < detailsToCopy.length; i++) { + key = detailsToCopy[i]; + self[key] = utils.stealValue(details, key); + } + for (i = 0; i < detailsToSkip.length; i++) { + key = detailsToSkip[i]; + self.otherFields[key] = utils.stealValue(details, key); + } + for (var k in details) { + debug('Repo details import, remaining key: ' + k); + } + self._detailsLoaded = true; +} + +module.exports = OpenSourceRepo; diff --git a/oss/team.js b/oss/team.js new file mode 100644 index 00000000..3076c341 --- /dev/null +++ b/oss/team.js @@ -0,0 +1,464 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +var async = require('async'); +var github = require('octonode'); +var debug = require('debug')('azureossportal'); +var utils = require('../utils'); +var OpenSourceRepo = require('./repo'); + +function OpenSourceOrganizationTeam (orgInstance, id, optionalInitialData) { + if (!id) { + throw new Error('No team ID was provided for construction.'); + } + this.id = id; + if (!orgInstance) { + throw new Error('Required organization instance is missing.'); + } + this.org = orgInstance; + this.oss = orgInstance.oss; + this.otherFields = {}; + this._detailsLoaded = false; + if (optionalInitialData) { + setDetails(this, optionalInitialData); + } +} + +// ---------------------------------------------------------------------------- +// Properties of interest in the standard GitHub response for a team +// ---------------------------------------------------------------------------- +var detailsToCopy = [ + 'name', + 'slug', + 'description', + 'permission', + 'url', + 'members_url', + 'repositories_url', + 'members_count', + 'repos_count', + 'privacy', +]; +var detailsToSkip = [ + 'id', + 'organization', +]; + +// ---------------------------------------------------------------------------- +// Creates a GitHub (octonode) API client for this team ID. +// ---------------------------------------------------------------------------- +OpenSourceOrganizationTeam.prototype.createGitHubTeamClient = function () { + var source = this[this.org ? 'org' : 'oss']; + var method = source.createGenericGitHubClient; + if (method === undefined) { + throw new Error('Unable to find the GitHub client factory associated with the team.'); + } + var client = method.call(source); + return client.team(this.id); +}; + +// ---------------------------------------------------------------------------- +// Get the team details +// ---------------------------------------------------------------------------- +OpenSourceOrganizationTeam.prototype.getDetails = function queryTeamDetails(callback) { + var self = this; + self.createGitHubTeamClient().info(function (error, info) { + if (error) { + return callback(utils.wrapError(error, 'We were unable to retrieve information about team ID ' + self.id + '.')); + } + var copy = {}; + utils.merge(copy, info); + if (!self.org && info.organization && info.organization.login) { + self.org = self.oss.org(info.organization.login); + } + setDetails(self, info); // destructive operation + callback(null, copy); + }); +}; + +// ---------------------------------------------------------------------------- +// Set the team details +// ---------------------------------------------------------------------------- +OpenSourceOrganizationTeam.prototype.setDetails = function setDetailsExternal(details) { + if (details.id == this.id) { + setDetails(this, details); + } else { + throw new Error('The provided details object does not reference team ID ' + this.id); + } +}; + +// ---------------------------------------------------------------------------- +// Delete the team. +// ---------------------------------------------------------------------------- +OpenSourceOrganizationTeam.prototype.delete = function deleteTeam(callback) { + this.createGitHubTeamClient().destroy(function (error) { + if (error) { + return callback(utils.wrapError(error, 'We were unable to delete team ID ' + self.id + ' using the GitHub API.')); + } + callback(); + }); +}; + +// ---------------------------------------------------------------------------- +// Update specific team details. Also updates the local copies in case the same +// request needs to show the updated info. +// ---------------------------------------------------------------------------- +OpenSourceOrganizationTeam.prototype.update = function updateTeamDetails(updates, callback) { + var self = this; + self.createGitHubTeamClient().update(updates, function (error, info) { + if (error) { + return callback(utils.wrapError(error, 'We were unable to update team ID ' + self.id + ' using the GitHub API.')); + } + var copy = {}; + utils.merge(copy, updates); + setDetails(self, info); // destructive operation + // Clear the org's cache in case the team was renamed... + self.org.clearTeamsCache(callback); + }); +}; + +// ---------------------------------------------------------------------------- +// Delete the team. +// ---------------------------------------------------------------------------- +OpenSourceOrganizationTeam.prototype.delete = function deleteTeam(callback) { + var self = this; + self.createGitHubTeamClient().destroy(function (error) { + if (error) { + return callback(utils.wrapError(error, 'We were unable to destroy the team ID ' + self.id + ' via the GitHub API.')); + } + self.org.clearTeamsCache(callback); + }); +}; + +// ---------------------------------------------------------------------------- +// Ensure that we have team details. +// ---------------------------------------------------------------------------- +OpenSourceOrganizationTeam.prototype.ensureDetailsAndOrganization = function insurance(callback) { + var self = this; + var ensureOrganizationReference = function (cb) { + if (!self.org) { + if (self.otherFields.organization && self.otherFields.organization.login) { + var orgName = self.otherFields.organization.login; + self.org = self.oss.org(orgName); + } else { + return cb(new Error('The name of the organization for a team could not be retrieved logically.')); + } + } + cb(); + }; + if (!self._detailsLoaded) { + self.getDetails(function (error) { + if (error) { + return callback(error); + } + ensureOrganizationReference(callback); + }); + } else { + ensureOrganizationReference(callback); + } +}; + +// ---------------------------------------------------------------------------- +// Add a repo and permission level to a GitHub team. +// ---------------------------------------------------------------------------- +OpenSourceOrganizationTeam.prototype.addRepository = function addRepo(repoName, permission, callback) { + this.org.createGenericGitHubClient().org(this.org.name).addTeamRepo(this.id, repoName, { + permission: permission + }, callback); +}; + +// ---------------------------------------------------------------------------- +// Get the repos managed by the team. +// ---------------------------------------------------------------------------- +OpenSourceOrganizationTeam.prototype.getRepos = function queryRepos(callback) { + var self = this; + var ghteam = self.createGitHubTeamClient(); + // CONSIDER: GitHub API can let y ou filter for just org-owned repos now... + utils.retrieveAllPages(ghteam.repos.bind(ghteam), function (error, repos) { + if (error) { + return callback(error); + } + async.filter(repos, function (repo, cb) { + cb(repo && repo.owner && repo.owner.login && repo.owner.login.toLowerCase() == self.org.name.toLowerCase()); + }, function (repos) { + async.map(repos, function (repo, cb) { + cb(null, new OpenSourceRepo(self.org, repo.name, repo)); + }, callback); + }); + }); +}; + +// ---------------------------------------------------------------------------- +// Check for public membership +// ---------------------------------------------------------------------------- +OpenSourceOrganizationTeam.prototype.isMember = function queryTeamMembership(callback) { + var self = this; + var username = self.oss.usernames.github; + self.createGitHubTeamClient().membership(username, function (error, result) { + return callback(null, result === true); + }); +}; + +// ---------------------------------------------------------------------------- +// Add membership for the authenticated user OR another GitHub username +// ---------------------------------------------------------------------------- +OpenSourceOrganizationTeam.prototype.addMembership = function addTeamMembership(role, optionalUsername, callback) { + var self = this; + if (!(role == 'member' || role == 'maintainer')) { + return callback(new Error('The provided role type "' + role + '" is not supported at this time.')); + } + if (typeof optionalUsername == 'function') { + callback = optionalUsername; + optionalUsername = self.oss.usernames.github; + } + var options = { + role: role + }; + self.createGitHubTeamClient().addMembership(optionalUsername, options, function (error, obj) { + if (error) { + callback(error); + } else { + clearRedisKeysAfterMembershipChange(self, function () { + callback(null, obj); + }); + } + }); +}; + +// ---------------------------------------------------------------------------- +// Remove membership for the authenticated user OR another GitHub username +// ---------------------------------------------------------------------------- +OpenSourceOrganizationTeam.prototype.removeMembership = function removeTeamMembership(optionalUsername, callback) { + var self = this; + if (typeof optionalUsername == 'function') { + callback = optionalUsername; + optionalUsername = this.oss.usernames.github; + } + this.createGitHubTeamClient().removeMembership(optionalUsername, function (error) { + if (!error) { + clearRedisKeysAfterMembershipChange(self, callback); + } else { + callback(error); + } + }); +}; + +function clearRedisKeysAfterMembershipChange(self, silentCallback) { + var keys = [ + 'team#' + self.id + '(all)', + 'team#' + self.id + '(member)', + 'team#' + self.id + '(maintainer)', + ]; + async.each(keys, function (key, cb) { + self.oss.redis.delete(key, cb); + }, function () { + if (silentCallback) { + silentCallback(); + } + }); +} + +// ---------------------------------------------------------------------------- +// Retrieves the members of the team. +// ---------------------------------------------------------------------------- +OpenSourceOrganizationTeam.prototype.getMembers = function getMembers(optionalRole, callback) { + var self = this; + var params = null; + if (typeof optionalRole == 'function') { + callback = optionalRole; + optionalRole = null; + } else { + params = { + role: optionalRole + }; + } + var ghteam = this.createGitHubTeamClient(); + utils.retrieveAllPages(ghteam.members.bind(ghteam), params, function (error, members) { + if (error) { + return callback(error); + } + // Update the cache for this team + var redisKey = 'team#' + self.id + '(' + optionalRole + ')'; + var randomExpireMinutes = utils.randomInteger(240, 60 * 24 * 2 /* 2 days max */); + self.oss.redis.setObjectWithExpire(redisKey, members, randomExpireMinutes, function () { + async.map(members, function (member, cb) { + cb(null, self.oss.user(member.id, member)); + }, callback); + }); + }); +}; + +// ---------------------------------------------------------------------------- +// Retrieves the members of the team. This is a fork of the getMembers method +// that does explicit Redis caching when available. For now, forked to avoid +// confusion. +// ---------------------------------------------------------------------------- +OpenSourceOrganizationTeam.prototype.getMembersCached = function getMembersCached(requiredRole, callback) { + var self = this; + if (typeof requiredRole == 'function') { + return callback(new Error('getMembersCached requires a role.')); + } + var instancesFromJson = function (members) { + async.map(members, function (member, cb) { + cb(null, self.oss.user(member.id, member)); + }, callback); + }; + var lightweightFieldsToPreserve = ['login', 'id']; + var params = { + role: requiredRole + }; + var redisKey = 'team#' + self.id + '(' + requiredRole + ')'; + var ghteam = this.createGitHubTeamClient(); + self.oss.redis.getObject(redisKey, function (error, data) { + if (!error && data) { + return instancesFromJson(data); + } + utils.retrieveAllPages(ghteam.members.bind(ghteam), params, function (error, members) { + if (error) { + return callback(error); + } + async.map(members, function (member, cb) { + var lw = {}; + for (var i = 0; i < lightweightFieldsToPreserve.length; i++) { + lw[lightweightFieldsToPreserve[i]] = member[lightweightFieldsToPreserve[i]]; + } + cb(null, lw); + }, function (error, lightweightMembers) { + if (error) { + return callback(error); + } + var randomExpireMinutes = utils.randomInteger(240, 60 * 24 * 2 /* 2 days max */); + self.oss.redis.setObjectWithExpire(redisKey, lightweightMembers, randomExpireMinutes, function () { + instancesFromJson(lightweightMembers); + }); + }); + }); + }); +}; + +// ---------------------------------------------------------------------------- +// Retrieves the members of the team. +// ---------------------------------------------------------------------------- +OpenSourceOrganizationTeam.prototype.getMemberLinks = function getMembersAndLinks(callback) { + var self = this; + this.getMembers(function (error, members) { + if (error) { + return callback(error); + } + if (members.length && members.length > 0) { + self.oss.getLinksForUsers(members, callback); + } else { + callback(null, []); + } + }); +}; + +// ---------------------------------------------------------------------------- +// Retrieves the maintainers of the team. +// ---------------------------------------------------------------------------- +OpenSourceOrganizationTeam.prototype.getMaintainers = function getMaintainers(callback) { + this.getMembers('maintainer', callback); +}; + +// ---------------------------------------------------------------------------- +// Retrieves the maintainers of the team, including fallback logic, +// in the case there are no explicit maintainers, we go to the organization's +// sudoers - a special team where any member of that specific team is granted +// special portal abilities. In the case that this organization does not have +// any sudoers defined, and this is a leaf node org, then the sudoers from the +// primary org will be appointed the official maintainers for this team. This +// function also loads the links from the underlying data system to be able to +// provide robust information about the users, including their corporate +// relationship. +// ---------------------------------------------------------------------------- +OpenSourceOrganizationTeam.prototype.getOfficialMaintainers = function (callback) { + var self = this; + self.ensureDetailsAndOrganization(function (error) { + if (error) { + return callback(error); + } + self.getMaintainers(function (error, maintainers) { + if (error) { + return callback(error); + } + if (maintainers.length > 0) { + self.oss.getLinksForUsers(maintainers, callback); + } else { + // Better design here would be to then fallback to the org obj. to get members themselves. + var team = self.org.getSudoersTeam(); + team.getMembers(function (error, members) { + if (!error && members && members.length === 0) { + error = new Error('No official organization approvers could be retrieved.'); + } + if (error) { + return callback(error); + } + self.oss.getLinksForUsers(members, callback); + }); + } + }); + }); +}; + +// ---------------------------------------------------------------------------- +// Retrieves pending approvals for this specific team and hydrates user links +// and accounts. It is possible that errors could happen if a user were to +// rename their GitHub account after submitting a request since the request's +// copy of the login is used for link hydration. +// ---------------------------------------------------------------------------- +OpenSourceOrganizationTeam.prototype.getApprovals = function (callback) { + var self = this; + var dc = this.oss.dataClient(); + dc.getPendingApprovals(this.id, function (error, pendingApprovals) { + if (error) { + return callback(utils.wrapError(error, 'We were unable to retrieve the pending approvals list for this team. There may be a data store problem.')); + } + var requestingUsers = {}; + async.each(pendingApprovals, function (approval, cb) { + requestingUsers[approval.ghu] = approval.ghid; + if (approval.requested) { + var asInt = parseInt(approval.requested, 10); + approval.requestedTime = new Date(asInt); + } + cb(); + }, function () { + self.oss.getCompleteUsersFromUsernameIdHash(requestingUsers, function (error, users) { + if (error) { + return callback(error); + } + async.each(pendingApprovals, function (approval, cb) { + var login = approval.ghu; + if (users[login]) { + approval.completeRequestingUser = users[login]; + } + cb(); + }, function (error) { + callback(error, pendingApprovals); + }); + }); + }); + }); +}; + +// PRIVATE FUNCTIONS + +function setDetails(team, details) { + var self = team; + var key = null; + for (var i = 0; i < detailsToCopy.length; i++) { + key = detailsToCopy[i]; + self[key] = utils.stealValue(details, key); + } + for (i = 0; i < detailsToSkip.length; i++) { + key = detailsToSkip[i]; + self.otherFields[key] = utils.stealValue(details, key); + } + for (var k in details) { + debug('Team details import, remaining key: ' + k); + } + self._detailsLoaded = true; +} + +module.exports = OpenSourceOrganizationTeam; diff --git a/oss/user.js b/oss/user.js new file mode 100644 index 00000000..67cb3ee3 --- /dev/null +++ b/oss/user.js @@ -0,0 +1,272 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +var async = require('async'); +var github = require('octonode'); +var utils = require('../utils'); +var debug = require('debug')('azureossportal'); + +function OpenSourceUser (ossInstance, githubId, optionalGitHubInstance) { + this.id = githubId; + this.oss = ossInstance; + this.otherFields = {}; + this.link = null; + this._detailsLoaded = false; + if (optionalGitHubInstance) { + setDetails(this, optionalGitHubInstance); + } +} + +// ---------------------------------------------------------------------------- +// Properties of interest in the standard GitHub response for a user +// ---------------------------------------------------------------------------- +var detailsToCopy = [ + 'login', + 'avatar_url', + // only in detailed info responses: + 'name', + 'company', + 'location', + 'email', + 'bio', + 'created_at', + 'updated_at', +]; +var detailsToSkip = [ + 'id', + 'gravatar_id', + 'url', + 'html_url', + 'followers_url', + 'following_url', + 'gists_url', + 'starred_url', + 'subscriptions_url', + 'organizations_url', + 'repos_url', + 'events_url', + 'received_events_url', + 'type', + 'site_admin', + // only in detailed info responses: + 'blog', + 'hireable', + 'public_repos', + 'public_gists', + 'followers', + 'following', + // organizations: + 'members_url', + 'public_members_url', + 'description', + 'total_private_repos', + 'owned_private_repos', + 'private_gists', + 'disk_usage', + 'collaborators', + 'billing_email', + 'plan', + // when in the context of a collaborators response only: + 'permissions', +]; + +// ---------------------------------------------------------------------------- +// Retrieve the link contact information, if the link has been loaded. +// ---------------------------------------------------------------------------- +OpenSourceUser.prototype.contactEmail = function () { + return this.link ? this.link.aadupn : null; +}; + +// ---------------------------------------------------------------------------- +// Retrieve the link contact information alias subset, if link loaded. +// ---------------------------------------------------------------------------- +OpenSourceUser.prototype.corporateAlias = function () { + if (this.link && this.link.aadupn) { + var email = this.link.aadupn; + var i = email.indexOf('@'); + if (i >= 0) { + return email.substring(0, i); + } + } + return null; +}; + +// ---------------------------------------------------------------------------- +// Retrieve the link contact information alias subset, if link loaded. +// ---------------------------------------------------------------------------- +OpenSourceUser.prototype.corporateProfileUrl = function () { + var alias = this.corporateAlias(); + var prefix = this.oss.setting('corporate').userProfilePrefix; + if (alias && prefix) { + return prefix + alias; + } + return null; +}; + +// ---------------------------------------------------------------------------- +// Retrieve the link contact information, if the link has been loaded. +// ---------------------------------------------------------------------------- +OpenSourceUser.prototype.contactName = function () { + if (this.link) { + return this.link.aadname || this.login; + } + return this.login; +}; + +// ---------------------------------------------------------------------------- +// Retrieves the URL for the user's avatar, if present. If the user's details +// have not been loaded, we will not yet have an avatar URL. +// ---------------------------------------------------------------------------- +OpenSourceUser.prototype.avatar = function (optionalSize) { + if (!optionalSize) { + optionalSize = 80; + } + if (this.avatar_url) { + return this.avatar_url + '&s=' + optionalSize; + } else { + return undefined; + } +}; + +// ---------------------------------------------------------------------------- +// Retrieve the link, if any, for this user from the underlying datastore. Will +// cache the value in memory for this instance, since the lifetime of these +// objects is a single request. +// ---------------------------------------------------------------------------- +OpenSourceUser.prototype.getLink = function (callback) { + if (this.link) { + return callback(null, this.link); + } + var self = this; + var dc = self.oss.dataClient(); + dc.getLink(self.id, function (error, link) { + if (error) { + return callback(utils.wrapError(error, 'We were not able to retrieve information about the link for user ' + self.id + ' at this time.')); + } + self.link = (link === false) ? false : dc.reduceEntity(link); + callback(null, self.link); + }); +}; + +OpenSourceUser.prototype.getLinkRequired = function (callback) { + var self = this; + this.getLink(function (error) { + if (!error && self.link === false) { + error = new Error('No link retrieved.'); + } + if (error) { + return callback(error); + } + callback(null, self.link); + }); +}; + +// ---------------------------------------------------------------------------- +// Special-use function to set the link when provided elsewhere. This is +// helpful since we can efficiently query a large set of links for team list +// scenarios and then set them here. +// ---------------------------------------------------------------------------- +OpenSourceUser.prototype.setLinkInstance = function (links, optionalSuppressDebug) { + if (!Array.isArray(links)) { + links = [links]; + } + for (var i = 0; i < links.length; i++) { + var link = links[i]; + if (link.ghid === this.id) { + this.link = link; + break; + } + } + if (!this.link && optionalSuppressDebug !== true) { + throw new Error('No matching link was provided for the user ID ' + this.id + '.'); + } +}; + +// ---------------------------------------------------------------------------- +// Special-use function to set the link when provided elsewhere. This is +// helpful since we can efficiently query a large set of links for team list +// scenarios and then set them here. Captures a throw and ignores the issue. +// ---------------------------------------------------------------------------- +OpenSourceUser.prototype.trySetLinkInstance = function (links, optionalSuppressDebug) { + try { + this.setLinkInstance(links, optionalSuppressDebug); + } catch (error) { + debug('trySetLinkInstance: No link exists for user ' + this.id); + } +}; + +// ---------------------------------------------------------------------------- +// Load the GitHub details for the user. +// Problem: we have the ID, but GitHub cheaply prefers usernames, not IDs... +// ---------------------------------------------------------------------------- +OpenSourceUser.prototype.getDetailsByUsername = function (login, callback) { + var self = this; + var username = this.login; + if (typeof login == 'function') { + callback = login; + login = null; + } else { + username = login; + } + if (!username) { + return callback(new Error('No username provided for retrieving the details of user ' + self.id)); + } + self.oss.createGenericGitHubClient().user(username).info(function (error, info) { + if (error) { + return callback(utils.wrapError(error, 'We were unable to retrieve information about user ' + username + ' (' + self.id + ').')); + } + var copy = {}; + utils.merge(copy, info); + setDetails(self, info); // destructive operation + callback(null, copy); + }); +}; + +OpenSourceUser.prototype.getProfileCreatedDate = function () { + if (this.created_at) { + return new Date(this.created_at); + } + return null; +}; + +OpenSourceUser.prototype.getProfileUpdatedDate = function () { + if (this.updated_at) { + return new Date(this.updated_at); + } + return null; +}; + +OpenSourceUser.prototype.debugView = function () { + var obj = {}; + for (var key in this) { + var val = this[key]; + if (typeof val == 'string') { + obj[key] = val; + } else { + if (key == 'otherFields' || key == 'link' || key == 'bio') { + obj[key] = val; + } + } + } + return obj; +}; + +function setDetails(self, details) { + var key = null; + for (var i = 0; i < detailsToCopy.length; i++) { + key = detailsToCopy[i]; + self[key] = utils.stealValue(details, key); + } + for (i = 0; i < detailsToSkip.length; i++) { + key = detailsToSkip[i]; + self.otherFields[key] = utils.stealValue(details, key); + } + for (var k in details) { + debug('User details import, remaining key: ' + k); + } + self._detailsLoaded = true; +} + +module.exports = OpenSourceUser; diff --git a/package.json b/package.json new file mode 100644 index 00000000..18ce359d --- /dev/null +++ b/package.json @@ -0,0 +1,53 @@ +{ + "name": "open-source-portal-for-github", + "author": "Microsoft Corporation", + "contributors": [ + "Wilcox, Jeff " + ], + "version": "3.0.2", + "license": "MIT", + "private": true, + "keywords": [ + "github", + "management", + "organization" + ], + "tags": [ + "github", + "node", + "management", + "organization" + ], + "scripts": { + "start": "node ./bin/www", + "jshint": "jshint ." + }, + "engines": { + "node": "~4.2.1" + }, + "dependencies": { + "applicationinsights": "^0.12.5", + "async": "^1.4.2", + "azure-storage": "^0.6.0", + "body-parser": "~1.14.1", + "compression": "^1.6.0", + "connect-redis": "^3.0.0", + "cookie-parser": "~1.4.0", + "debug": "~2.2.0", + "express": "~4.13.3", + "express-session": "^1.11.3", + "jade": "1.11.0", + "moment": "^2.10.6", + "morgan": "~1.6.1", + "node-uuid": "^1.4.3", + "octonode": "pksunkara/octonode", + "passport": "^0.3.0", + "passport-azure-ad": "^1.3.6", + "passport-github": "^1.0.0", + "redis": "^2.2.3", + "serve-favicon": "~2.3.0" + }, + "devDependencies": { + "jshint": "^2.8.0" + } +} diff --git a/public/browserconfig.xml b/public/browserconfig.xml new file mode 100644 index 00000000..0522a1f5 --- /dev/null +++ b/public/browserconfig.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/public/css/BOOTSTRAP-LICENSE.txt b/public/css/BOOTSTRAP-LICENSE.txt new file mode 100644 index 00000000..5a3367c6 --- /dev/null +++ b/public/css/BOOTSTRAP-LICENSE.txt @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2011-2015 Twitter, Inc + +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/public/css/bootstrap.css b/public/css/bootstrap.css new file mode 100644 index 00000000..67a5359a --- /dev/null +++ b/public/css/bootstrap.css @@ -0,0 +1,6302 @@ +/*! + * bootswatch v3.2.0 + * Homepage: http://bootswatch.com + * Copyright 2012-2014 Thomas Park + * Licensed under MIT + * Based on Bootstrap +*/ +/*! normalize.css v3.0.1 | MIT License | git.io/normalize */ +html { + font-family: sans-serif; + -ms-text-size-adjust: 100%; + -webkit-text-size-adjust: 100%; +} +body { + margin: 0; +} +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +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: transparent; +} +a:active, +a:hover { + outline: 0; +} +abbr[title] { + border-bottom: 1px dotted; +} +b, +strong { + font-weight: bold; +} +dfn { + font-style: italic; +} +h1 { + font-size: 2em; + margin: 0.67em 0; +} +mark { + background: #ff0; + color: #000; +} +small { + font-size: 80%; +} +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} +sup { + top: -0.5em; +} +sub { + bottom: -0.25em; +} +img { + border: 0; +} +svg:not(:root) { + overflow: hidden; +} +figure { + margin: 1em 40px; +} +hr { + -moz-box-sizing: content-box; + box-sizing: content-box; + height: 0; +} +pre { + overflow: auto; +} +code, +kbd, +pre, +samp { + font-family: monospace, monospace; + font-size: 1em; +} +button, +input, +optgroup, +select, +textarea { + color: inherit; + font: inherit; + margin: 0; +} +button { + overflow: visible; +} +button, +select { + text-transform: none; +} +button, +html input[type="button"], +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; + cursor: pointer; +} +button[disabled], +html input[disabled] { + cursor: default; +} +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} +input { + line-height: normal; +} +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; + padding: 0; +} +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + height: auto; +} +input[type="search"] { + -webkit-appearance: textfield; + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; + box-sizing: content-box; +} +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} +legend { + border: 0; + padding: 0; +} +textarea { + overflow: auto; +} +optgroup { + font-weight: bold; +} +table { + border-collapse: collapse; + border-spacing: 0; +} +td, +th { + padding: 0; +} +@media print { + * { + text-shadow: none !important; + color: #000 !important; + background: transparent !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^="javascript:"]:after, + a[href^="#"]: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; + } + .table td, + .table th { + background-color: #fff !important; + } + .btn > .caret, + .dropup > .btn > .caret { + border-top-color: #000 !important; + } + .label { + border: 1px solid #000; + } + .table { + border-collapse: collapse !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: normal; + 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 { + 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: "Segoe UI", Segoe, "Segoe WP", Calibri, Candara, Tahoma, Verdana, Arial, sans-serif; + font-size: 15px; + line-height: 1.42857143; + color: #333333; + background-color: #ffffff; +} +input, +button, +select, +textarea { + font-family: inherit; + font-size: inherit; + line-height: inherit; +} +a { + color: #0072c6; + text-decoration: none; +} +a:hover, +a:focus { + color: #00467a; + 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; + width: 100% \9; + max-width: 100%; + height: auto; +} +.img-rounded { + border-radius: 0; +} +.img-thumbnail { + padding: 4px; + line-height: 1.42857143; + background-color: #ffffff; + border: 1px solid #dddddd; + border-radius: 0; + -webkit-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; + display: inline-block; + width: 100% \9; + max-width: 100%; + height: auto; +} +.img-circle { + border-radius: 50%; +} +hr { + margin-top: 21px; + margin-bottom: 21px; + border: 0; + border-top: 1px solid #e6e6e6; +} +.sr-only { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; +} +.sr-only-focusable:active, +.sr-only-focusable:focus { + position: static; + width: auto; + height: auto; + margin: 0; + overflow: visible; + clip: auto; +} +h1, +h2, +h3, +h4, +h5, +h6, +.h1, +.h2, +.h3, +.h4, +.h5, +.h6 { + font-family: "Segoe UI", Segoe, "Segoe WP", Calibri, Candara, Tahoma, Verdana, Arial, sans-serif; + font-weight: 300; + 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: #999999; +} +h1, +.h1, +h2, +.h2, +h3, +.h3 { + margin-top: 21px; + margin-bottom: 10.5px; +} +h1 small, +.h1 small, +h2 small, +.h2 small, +h3 small, +.h3 small, +h1 .small, +.h1 .small, +h2 .small, +.h2 .small, +h3 .small, +.h3 .small { + font-size: 65%; +} +h4, +.h4, +h5, +.h5, +h6, +.h6 { + margin-top: 10.5px; + margin-bottom: 10.5px; +} +h4 small, +.h4 small, +h5 small, +.h5 small, +h6 small, +.h6 small, +h4 .small, +.h4 .small, +h5 .small, +.h5 .small, +h6 .small, +.h6 .small { + font-size: 75%; +} +h1, +.h1 { + font-size: 39px; +} +h2, +.h2 { + font-size: 32px; +} +h3, +.h3 { + font-size: 26px; +} +h4, +.h4 { + font-size: 19px; +} +h5, +.h5 { + font-size: 15px; +} +h6, +.h6 { + font-size: 13px; +} +p { + margin: 0 0 10.5px; +} +.lead { + margin-bottom: 21px; + font-size: 17px; + font-weight: 300; + line-height: 1.4; +} +@media (min-width: 768px) { + .lead { + font-size: 22.5px; + } +} +small, +.small { + font-size: 86%; +} +cite { + font-style: normal; +} +mark, +.mark { + background-color: #ff7518; + padding: .2em; +} +.text-left { + text-align: left; +} +.text-right { + text-align: right; +} +.text-center { + text-align: center; +} +.text-justify { + text-align: justify; +} +.text-nowrap { + white-space: nowrap; +} +.text-lowercase { + text-transform: lowercase; +} +.text-uppercase { + text-transform: uppercase; +} +.text-capitalize { + text-transform: capitalize; +} +.text-muted { + color: #999999; +} +.text-primary { + color: #0072c6; +} +a.text-primary:hover { + color: #005593; +} +.text-success { + color: #ffffff; +} +a.text-success:hover { + color: #e6e6e6; +} +.text-info { + color: #ffffff; +} +a.text-info:hover { + color: #e6e6e6; +} +.text-warning { + color: #ffffff; +} +a.text-warning:hover { + color: #e6e6e6; +} +.text-danger { + color: #ffffff; +} +a.text-danger:hover { + color: #e6e6e6; +} +.bg-primary { + color: #fff; + background-color: #0072c6; +} +a.bg-primary:hover { + background-color: #005593; +} +.bg-success { + background-color: #3fb618; +} +a.bg-success:hover { + background-color: #2f8912; +} +.bg-info { + background-color: #9954bb; +} +a.bg-info:hover { + background-color: #7e3f9d; +} +.bg-warning { + background-color: #ff7518; +} +a.bg-warning:hover { + background-color: #e45c00; +} +.bg-danger { + background-color: #ff0039; +} +a.bg-danger:hover { + background-color: #cc002e; +} +.page-header { + padding-bottom: 9.5px; + margin: 42px 0 21px; + border-bottom: 1px solid #e6e6e6; +} +ul, +ol { + margin-top: 0; + margin-bottom: 10.5px; +} +ul ul, +ol ul, +ul ol, +ol ol { + margin-bottom: 0; +} +.list-unstyled { + padding-left: 0; + list-style: none; +} +.list-inline { + padding-left: 0; + list-style: none; + margin-left: -5px; +} +.list-inline > li { + display: inline-block; + padding-left: 5px; + padding-right: 5px; +} +dl { + margin-top: 0; + margin-bottom: 21px; +} +dt, +dd { + line-height: 1.42857143; +} +dt { + font-weight: bold; +} +dd { + margin-left: 0; +} +@media (min-width: 768px) { + .dl-horizontal dt { + float: left; + width: 160px; + clear: left; + text-align: right; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .dl-horizontal dd { + margin-left: 180px; + } +} +abbr[title], +abbr[data-original-title] { + cursor: help; + border-bottom: 1px dotted #999999; +} +.initialism { + font-size: 90%; + text-transform: uppercase; +} +blockquote { + padding: 10.5px 21px; + margin: 0 0 21px; + font-size: 18.75px; + border-left: 5px solid #e6e6e6; +} +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: #999999; +} +blockquote footer:before, +blockquote small:before, +blockquote .small:before { + content: '\2014 \00A0'; +} +.blockquote-reverse, +blockquote.pull-right { + padding-right: 15px; + padding-left: 0; + border-right: 5px solid #e6e6e6; + border-left: 0; + text-align: right; +} +.blockquote-reverse footer:before, +blockquote.pull-right footer:before, +.blockquote-reverse small:before, +blockquote.pull-right small:before, +.blockquote-reverse .small:before, +blockquote.pull-right .small:before { + content: ''; +} +.blockquote-reverse footer:after, +blockquote.pull-right footer:after, +.blockquote-reverse small:after, +blockquote.pull-right small:after, +.blockquote-reverse .small:after, +blockquote.pull-right .small:after { + content: '\00A0 \2014'; +} +blockquote:before, +blockquote:after { + content: ""; +} +address { + margin-bottom: 21px; + font-style: normal; + line-height: 1.42857143; +} +code, +kbd, +pre, +samp { + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; +} +code { + padding: 2px 4px; + font-size: 90%; + color: #c7254e; + background-color: #f9f2f4; + border-radius: 0; +} +kbd { + padding: 2px 4px; + font-size: 90%; + color: #ffffff; + background-color: #333333; + border-radius: 0; + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25); +} +kbd kbd { + padding: 0; + font-size: 100%; + box-shadow: none; +} +pre { + display: block; + padding: 10px; + margin: 0 0 10.5px; + font-size: 14px; + line-height: 1.42857143; + word-break: break-all; + word-wrap: break-word; + color: #333333; + background-color: #f5f5f5; + border: 1px solid #cccccc; + border-radius: 0; +} +pre code { + padding: 0; + font-size: inherit; + color: inherit; + white-space: pre-wrap; + background-color: transparent; + border-radius: 0; +} +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} +.container { + margin-right: auto; + margin-left: auto; + padding-left: 15px; + padding-right: 15px; +} +@media (min-width: 768px) { + .container { + width: 750px; + } +} +@media (min-width: 992px) { + .container { + width: 970px; + } +} +@media (min-width: 1200px) { + .container { + width: 1170px; + } +} +.container-fluid { + margin-right: auto; + margin-left: auto; + padding-left: 15px; + padding-right: 15px; +} +.row { + margin-left: -15px; + margin-right: -15px; +} +.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 { + position: relative; + min-height: 1px; + padding-left: 15px; + padding-right: 15px; +} +.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 { + float: left; +} +.col-xs-12 { + width: 100%; +} +.col-xs-11 { + width: 91.66666667%; +} +.col-xs-10 { + width: 83.33333333%; +} +.col-xs-9 { + width: 75%; +} +.col-xs-8 { + width: 66.66666667%; +} +.col-xs-7 { + width: 58.33333333%; +} +.col-xs-6 { + width: 50%; +} +.col-xs-5 { + width: 41.66666667%; +} +.col-xs-4 { + width: 33.33333333%; +} +.col-xs-3 { + width: 25%; +} +.col-xs-2 { + width: 16.66666667%; +} +.col-xs-1 { + width: 8.33333333%; +} +.col-xs-pull-12 { + right: 100%; +} +.col-xs-pull-11 { + right: 91.66666667%; +} +.col-xs-pull-10 { + right: 83.33333333%; +} +.col-xs-pull-9 { + right: 75%; +} +.col-xs-pull-8 { + right: 66.66666667%; +} +.col-xs-pull-7 { + right: 58.33333333%; +} +.col-xs-pull-6 { + right: 50%; +} +.col-xs-pull-5 { + right: 41.66666667%; +} +.col-xs-pull-4 { + right: 33.33333333%; +} +.col-xs-pull-3 { + right: 25%; +} +.col-xs-pull-2 { + right: 16.66666667%; +} +.col-xs-pull-1 { + right: 8.33333333%; +} +.col-xs-pull-0 { + right: auto; +} +.col-xs-push-12 { + left: 100%; +} +.col-xs-push-11 { + left: 91.66666667%; +} +.col-xs-push-10 { + left: 83.33333333%; +} +.col-xs-push-9 { + left: 75%; +} +.col-xs-push-8 { + left: 66.66666667%; +} +.col-xs-push-7 { + left: 58.33333333%; +} +.col-xs-push-6 { + left: 50%; +} +.col-xs-push-5 { + left: 41.66666667%; +} +.col-xs-push-4 { + left: 33.33333333%; +} +.col-xs-push-3 { + left: 25%; +} +.col-xs-push-2 { + left: 16.66666667%; +} +.col-xs-push-1 { + left: 8.33333333%; +} +.col-xs-push-0 { + left: auto; +} +.col-xs-offset-12 { + margin-left: 100%; +} +.col-xs-offset-11 { + margin-left: 91.66666667%; +} +.col-xs-offset-10 { + margin-left: 83.33333333%; +} +.col-xs-offset-9 { + margin-left: 75%; +} +.col-xs-offset-8 { + margin-left: 66.66666667%; +} +.col-xs-offset-7 { + margin-left: 58.33333333%; +} +.col-xs-offset-6 { + margin-left: 50%; +} +.col-xs-offset-5 { + margin-left: 41.66666667%; +} +.col-xs-offset-4 { + margin-left: 33.33333333%; +} +.col-xs-offset-3 { + margin-left: 25%; +} +.col-xs-offset-2 { + margin-left: 16.66666667%; +} +.col-xs-offset-1 { + margin-left: 8.33333333%; +} +.col-xs-offset-0 { + margin-left: 0%; +} +@media (min-width: 768px) { + .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 { + float: left; + } + .col-sm-12 { + width: 100%; + } + .col-sm-11 { + width: 91.66666667%; + } + .col-sm-10 { + width: 83.33333333%; + } + .col-sm-9 { + width: 75%; + } + .col-sm-8 { + width: 66.66666667%; + } + .col-sm-7 { + width: 58.33333333%; + } + .col-sm-6 { + width: 50%; + } + .col-sm-5 { + width: 41.66666667%; + } + .col-sm-4 { + width: 33.33333333%; + } + .col-sm-3 { + width: 25%; + } + .col-sm-2 { + width: 16.66666667%; + } + .col-sm-1 { + width: 8.33333333%; + } + .col-sm-pull-12 { + right: 100%; + } + .col-sm-pull-11 { + right: 91.66666667%; + } + .col-sm-pull-10 { + right: 83.33333333%; + } + .col-sm-pull-9 { + right: 75%; + } + .col-sm-pull-8 { + right: 66.66666667%; + } + .col-sm-pull-7 { + right: 58.33333333%; + } + .col-sm-pull-6 { + right: 50%; + } + .col-sm-pull-5 { + right: 41.66666667%; + } + .col-sm-pull-4 { + right: 33.33333333%; + } + .col-sm-pull-3 { + right: 25%; + } + .col-sm-pull-2 { + right: 16.66666667%; + } + .col-sm-pull-1 { + right: 8.33333333%; + } + .col-sm-pull-0 { + right: auto; + } + .col-sm-push-12 { + left: 100%; + } + .col-sm-push-11 { + left: 91.66666667%; + } + .col-sm-push-10 { + left: 83.33333333%; + } + .col-sm-push-9 { + left: 75%; + } + .col-sm-push-8 { + left: 66.66666667%; + } + .col-sm-push-7 { + left: 58.33333333%; + } + .col-sm-push-6 { + left: 50%; + } + .col-sm-push-5 { + left: 41.66666667%; + } + .col-sm-push-4 { + left: 33.33333333%; + } + .col-sm-push-3 { + left: 25%; + } + .col-sm-push-2 { + left: 16.66666667%; + } + .col-sm-push-1 { + left: 8.33333333%; + } + .col-sm-push-0 { + left: auto; + } + .col-sm-offset-12 { + margin-left: 100%; + } + .col-sm-offset-11 { + margin-left: 91.66666667%; + } + .col-sm-offset-10 { + margin-left: 83.33333333%; + } + .col-sm-offset-9 { + margin-left: 75%; + } + .col-sm-offset-8 { + margin-left: 66.66666667%; + } + .col-sm-offset-7 { + margin-left: 58.33333333%; + } + .col-sm-offset-6 { + margin-left: 50%; + } + .col-sm-offset-5 { + margin-left: 41.66666667%; + } + .col-sm-offset-4 { + margin-left: 33.33333333%; + } + .col-sm-offset-3 { + margin-left: 25%; + } + .col-sm-offset-2 { + margin-left: 16.66666667%; + } + .col-sm-offset-1 { + margin-left: 8.33333333%; + } + .col-sm-offset-0 { + margin-left: 0%; + } +} +@media (min-width: 992px) { + .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 { + float: left; + } + .col-md-12 { + width: 100%; + } + .col-md-11 { + width: 91.66666667%; + } + .col-md-10 { + width: 83.33333333%; + } + .col-md-9 { + width: 75%; + } + .col-md-8 { + width: 66.66666667%; + } + .col-md-7 { + width: 58.33333333%; + } + .col-md-6 { + width: 50%; + } + .col-md-5 { + width: 41.66666667%; + } + .col-md-4 { + width: 33.33333333%; + } + .col-md-3 { + width: 25%; + } + .col-md-2 { + width: 16.66666667%; + } + .col-md-1 { + width: 8.33333333%; + } + .col-md-pull-12 { + right: 100%; + } + .col-md-pull-11 { + right: 91.66666667%; + } + .col-md-pull-10 { + right: 83.33333333%; + } + .col-md-pull-9 { + right: 75%; + } + .col-md-pull-8 { + right: 66.66666667%; + } + .col-md-pull-7 { + right: 58.33333333%; + } + .col-md-pull-6 { + right: 50%; + } + .col-md-pull-5 { + right: 41.66666667%; + } + .col-md-pull-4 { + right: 33.33333333%; + } + .col-md-pull-3 { + right: 25%; + } + .col-md-pull-2 { + right: 16.66666667%; + } + .col-md-pull-1 { + right: 8.33333333%; + } + .col-md-pull-0 { + right: auto; + } + .col-md-push-12 { + left: 100%; + } + .col-md-push-11 { + left: 91.66666667%; + } + .col-md-push-10 { + left: 83.33333333%; + } + .col-md-push-9 { + left: 75%; + } + .col-md-push-8 { + left: 66.66666667%; + } + .col-md-push-7 { + left: 58.33333333%; + } + .col-md-push-6 { + left: 50%; + } + .col-md-push-5 { + left: 41.66666667%; + } + .col-md-push-4 { + left: 33.33333333%; + } + .col-md-push-3 { + left: 25%; + } + .col-md-push-2 { + left: 16.66666667%; + } + .col-md-push-1 { + left: 8.33333333%; + } + .col-md-push-0 { + left: auto; + } + .col-md-offset-12 { + margin-left: 100%; + } + .col-md-offset-11 { + margin-left: 91.66666667%; + } + .col-md-offset-10 { + margin-left: 83.33333333%; + } + .col-md-offset-9 { + margin-left: 75%; + } + .col-md-offset-8 { + margin-left: 66.66666667%; + } + .col-md-offset-7 { + margin-left: 58.33333333%; + } + .col-md-offset-6 { + margin-left: 50%; + } + .col-md-offset-5 { + margin-left: 41.66666667%; + } + .col-md-offset-4 { + margin-left: 33.33333333%; + } + .col-md-offset-3 { + margin-left: 25%; + } + .col-md-offset-2 { + margin-left: 16.66666667%; + } + .col-md-offset-1 { + margin-left: 8.33333333%; + } + .col-md-offset-0 { + margin-left: 0%; + } +} +@media (min-width: 1200px) { + .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 { + float: left; + } + .col-lg-12 { + width: 100%; + } + .col-lg-11 { + width: 91.66666667%; + } + .col-lg-10 { + width: 83.33333333%; + } + .col-lg-9 { + width: 75%; + } + .col-lg-8 { + width: 66.66666667%; + } + .col-lg-7 { + width: 58.33333333%; + } + .col-lg-6 { + width: 50%; + } + .col-lg-5 { + width: 41.66666667%; + } + .col-lg-4 { + width: 33.33333333%; + } + .col-lg-3 { + width: 25%; + } + .col-lg-2 { + width: 16.66666667%; + } + .col-lg-1 { + width: 8.33333333%; + } + .col-lg-pull-12 { + right: 100%; + } + .col-lg-pull-11 { + right: 91.66666667%; + } + .col-lg-pull-10 { + right: 83.33333333%; + } + .col-lg-pull-9 { + right: 75%; + } + .col-lg-pull-8 { + right: 66.66666667%; + } + .col-lg-pull-7 { + right: 58.33333333%; + } + .col-lg-pull-6 { + right: 50%; + } + .col-lg-pull-5 { + right: 41.66666667%; + } + .col-lg-pull-4 { + right: 33.33333333%; + } + .col-lg-pull-3 { + right: 25%; + } + .col-lg-pull-2 { + right: 16.66666667%; + } + .col-lg-pull-1 { + right: 8.33333333%; + } + .col-lg-pull-0 { + right: auto; + } + .col-lg-push-12 { + left: 100%; + } + .col-lg-push-11 { + left: 91.66666667%; + } + .col-lg-push-10 { + left: 83.33333333%; + } + .col-lg-push-9 { + left: 75%; + } + .col-lg-push-8 { + left: 66.66666667%; + } + .col-lg-push-7 { + left: 58.33333333%; + } + .col-lg-push-6 { + left: 50%; + } + .col-lg-push-5 { + left: 41.66666667%; + } + .col-lg-push-4 { + left: 33.33333333%; + } + .col-lg-push-3 { + left: 25%; + } + .col-lg-push-2 { + left: 16.66666667%; + } + .col-lg-push-1 { + left: 8.33333333%; + } + .col-lg-push-0 { + left: auto; + } + .col-lg-offset-12 { + margin-left: 100%; + } + .col-lg-offset-11 { + margin-left: 91.66666667%; + } + .col-lg-offset-10 { + margin-left: 83.33333333%; + } + .col-lg-offset-9 { + margin-left: 75%; + } + .col-lg-offset-8 { + margin-left: 66.66666667%; + } + .col-lg-offset-7 { + margin-left: 58.33333333%; + } + .col-lg-offset-6 { + margin-left: 50%; + } + .col-lg-offset-5 { + margin-left: 41.66666667%; + } + .col-lg-offset-4 { + margin-left: 33.33333333%; + } + .col-lg-offset-3 { + margin-left: 25%; + } + .col-lg-offset-2 { + margin-left: 16.66666667%; + } + .col-lg-offset-1 { + margin-left: 8.33333333%; + } + .col-lg-offset-0 { + margin-left: 0%; + } +} +table { + background-color: transparent; +} +th { + text-align: left; +} +.table { + width: 100%; + max-width: 100%; + margin-bottom: 21px; +} +.table > thead > tr > th, +.table > tbody > tr > th, +.table > tfoot > tr > th, +.table > thead > tr > td, +.table > tbody > tr > td, +.table > tfoot > tr > td { + padding: 8px; + line-height: 1.42857143; + vertical-align: top; + border-top: 1px solid #dddddd; +} +.table > thead > tr > th { + vertical-align: bottom; + border-bottom: 2px solid #dddddd; +} +.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 #dddddd; +} +.table .table { + background-color: #ffffff; +} +.table-condensed > thead > tr > th, +.table-condensed > tbody > tr > th, +.table-condensed > tfoot > tr > th, +.table-condensed > thead > tr > td, +.table-condensed > tbody > tr > td, +.table-condensed > tfoot > tr > td { + padding: 5px; +} +.table-bordered { + border: 1px solid #dddddd; +} +.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 #dddddd; +} +.table-bordered > thead > tr > th, +.table-bordered > thead > tr > td { + border-bottom-width: 2px; +} +.table-striped > tbody > tr:nth-child(odd) > td, +.table-striped > tbody > tr:nth-child(odd) > th { + background-color: #f9f9f9; +} +.table-hover > tbody > tr:hover > td, +.table-hover > tbody > tr:hover > th { + background-color: #f5f5f5; +} +table col[class*="col-"] { + position: static; + float: none; + display: table-column; +} +table td[class*="col-"], +table th[class*="col-"] { + position: static; + float: none; + display: table-cell; +} +.table > thead > tr > td.active, +.table > tbody > tr > td.active, +.table > tfoot > tr > td.active, +.table > thead > tr > th.active, +.table > tbody > tr > th.active, +.table > tfoot > tr > th.active, +.table > thead > tr.active > td, +.table > tbody > tr.active > td, +.table > tfoot > tr.active > td, +.table > thead > tr.active > th, +.table > tbody > tr.active > th, +.table > tfoot > tr.active > th { + background-color: #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: #3fb618; +} +.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: #379f15; +} +.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: #9954bb; +} +.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: #8d46b0; +} +.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: #ff7518; +} +.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: #fe6600; +} +.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: #ff0039; +} +.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: #e60033; +} +@media screen and (max-width: 767px) { + .table-responsive { + width: 100%; + margin-bottom: 15.75px; + overflow-y: hidden; + overflow-x: auto; + -ms-overflow-style: -ms-autohiding-scrollbar; + border: 1px solid #dddddd; + -webkit-overflow-scrolling: touch; + } + .table-responsive > .table { + margin-bottom: 0; + } + .table-responsive > .table > thead > tr > th, + .table-responsive > .table > tbody > tr > th, + .table-responsive > .table > tfoot > tr > th, + .table-responsive > .table > thead > tr > td, + .table-responsive > .table > tbody > tr > td, + .table-responsive > .table > tfoot > tr > td { + white-space: nowrap; + } + .table-responsive > .table-bordered { + border: 0; + } + .table-responsive > .table-bordered > thead > tr > th:first-child, + .table-responsive > .table-bordered > tbody > tr > th:first-child, + .table-responsive > .table-bordered > tfoot > tr > th:first-child, + .table-responsive > .table-bordered > thead > tr > td:first-child, + .table-responsive > .table-bordered > tbody > tr > td:first-child, + .table-responsive > .table-bordered > tfoot > tr > td:first-child { + border-left: 0; + } + .table-responsive > .table-bordered > thead > tr > th:last-child, + .table-responsive > .table-bordered > tbody > tr > th:last-child, + .table-responsive > .table-bordered > tfoot > tr > th:last-child, + .table-responsive > .table-bordered > thead > tr > td:last-child, + .table-responsive > .table-bordered > tbody > tr > td:last-child, + .table-responsive > .table-bordered > tfoot > tr > td:last-child { + border-right: 0; + } + .table-responsive > .table-bordered > tbody > tr:last-child > th, + .table-responsive > .table-bordered > tfoot > tr:last-child > th, + .table-responsive > .table-bordered > tbody > tr:last-child > td, + .table-responsive > .table-bordered > tfoot > tr:last-child > td { + border-bottom: 0; + } +} +fieldset { + padding: 0; + margin: 0; + border: 0; + min-width: 0; +} +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 21px; + font-size: 22.5px; + line-height: inherit; + color: #333333; + 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: 11px; + font-size: 15px; + line-height: 1.42857143; + color: #333333; +} +.form-control { + display: block; + width: 100%; + height: 43px; + padding: 10px 18px; + font-size: 15px; + line-height: 1.42857143; + color: #333333; + background-color: #ffffff; + background-image: none; + border: 1px solid #cccccc; + border-radius: 0; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border-color ease-in-out .15s, 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, 0.6); + box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6); +} +.form-control::-moz-placeholder { + color: #999999; + opacity: 1; +} +.form-control:-ms-input-placeholder { + color: #999999; +} +.form-control::-webkit-input-placeholder { + color: #999999; +} +.form-control[disabled], +.form-control[readonly], +fieldset[disabled] .form-control { + cursor: not-allowed; + background-color: #e6e6e6; + opacity: 1; +} +textarea.form-control { + height: auto; +} +input[type="search"] { + -webkit-appearance: none; +} +input[type="date"], +input[type="time"], +input[type="datetime-local"], +input[type="month"] { + line-height: 43px; + line-height: 1.42857143 \0; +} +input[type="date"].input-sm, +input[type="time"].input-sm, +input[type="datetime-local"].input-sm, +input[type="month"].input-sm { + line-height: 31px; +} +input[type="date"].input-lg, +input[type="time"].input-lg, +input[type="datetime-local"].input-lg, +input[type="month"].input-lg { + line-height: 64px; +} +.form-group { + margin-bottom: 15px; +} +.radio, +.checkbox { + position: relative; + display: block; + min-height: 21px; + margin-top: 10px; + margin-bottom: 10px; +} +.radio label, +.checkbox label { + padding-left: 20px; + margin-bottom: 0; + font-weight: normal; + cursor: pointer; +} +.radio input[type="radio"], +.radio-inline input[type="radio"], +.checkbox input[type="checkbox"], +.checkbox-inline input[type="checkbox"] { + position: absolute; + margin-left: -20px; + margin-top: 4px \9; +} +.radio + .radio, +.checkbox + .checkbox { + margin-top: -5px; +} +.radio-inline, +.checkbox-inline { + display: inline-block; + padding-left: 20px; + margin-bottom: 0; + vertical-align: middle; + font-weight: normal; + cursor: pointer; +} +.radio-inline + .radio-inline, +.checkbox-inline + .checkbox-inline { + margin-top: 0; + margin-left: 10px; +} +input[type="radio"][disabled], +input[type="checkbox"][disabled], +input[type="radio"].disabled, +input[type="checkbox"].disabled, +fieldset[disabled] input[type="radio"], +fieldset[disabled] input[type="checkbox"] { + cursor: not-allowed; +} +.radio-inline.disabled, +.checkbox-inline.disabled, +fieldset[disabled] .radio-inline, +fieldset[disabled] .checkbox-inline { + cursor: not-allowed; +} +.radio.disabled label, +.checkbox.disabled label, +fieldset[disabled] .radio label, +fieldset[disabled] .checkbox label { + cursor: not-allowed; +} +.form-control-static { + padding-top: 11px; + padding-bottom: 11px; + margin-bottom: 0; +} +.form-control-static.input-lg, +.form-control-static.input-sm { + padding-left: 0; + padding-right: 0; +} +.input-sm, +.form-horizontal .form-group-sm .form-control { + height: 31px; + padding: 5px 10px; + font-size: 13px; + line-height: 1.5; + border-radius: 0; +} +select.input-sm { + height: 31px; + line-height: 31px; +} +textarea.input-sm, +select[multiple].input-sm { + height: auto; +} +.input-lg, +.form-horizontal .form-group-lg .form-control { + height: 64px; + padding: 18px 30px; + font-size: 19px; + line-height: 1.33; + border-radius: 0; +} +select.input-lg { + height: 64px; + line-height: 64px; +} +textarea.input-lg, +select[multiple].input-lg { + height: auto; +} +.has-feedback { + position: relative; +} +.has-feedback .form-control { + padding-right: 53.75px; +} +.form-control-feedback { + position: absolute; + top: 26px; + right: 0; + z-index: 2; + display: block; + width: 43px; + height: 43px; + line-height: 43px; + text-align: center; +} +.input-lg + .form-control-feedback { + width: 64px; + height: 64px; + line-height: 64px; +} +.input-sm + .form-control-feedback { + width: 31px; + height: 31px; + line-height: 31px; +} +.has-success .help-block, +.has-success .control-label, +.has-success .radio, +.has-success .checkbox, +.has-success .radio-inline, +.has-success .checkbox-inline { + color: #ffffff; +} +.has-success .form-control { + border-color: #ffffff; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.has-success .form-control:focus { + border-color: #e6e6e6; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; +} +.has-success .input-group-addon { + color: #ffffff; + border-color: #ffffff; + background-color: #3fb618; +} +.has-success .form-control-feedback { + color: #ffffff; +} +.has-warning .help-block, +.has-warning .control-label, +.has-warning .radio, +.has-warning .checkbox, +.has-warning .radio-inline, +.has-warning .checkbox-inline { + color: #ffffff; +} +.has-warning .form-control { + border-color: #ffffff; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.has-warning .form-control:focus { + border-color: #e6e6e6; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; +} +.has-warning .input-group-addon { + color: #ffffff; + border-color: #ffffff; + background-color: #ff7518; +} +.has-warning .form-control-feedback { + color: #ffffff; +} +.has-error .help-block, +.has-error .control-label, +.has-error .radio, +.has-error .checkbox, +.has-error .radio-inline, +.has-error .checkbox-inline { + color: #ffffff; +} +.has-error .form-control { + border-color: #ffffff; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.has-error .form-control:focus { + border-color: #e6e6e6; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; +} +.has-error .input-group-addon { + color: #ffffff; + border-color: #ffffff; + background-color: #ff0039; +} +.has-error .form-control-feedback { + color: #ffffff; +} +.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 .input-group { + display: inline-table; + vertical-align: middle; + } + .form-inline .input-group .input-group-addon, + .form-inline .input-group .input-group-btn, + .form-inline .input-group .form-control { + width: auto; + } + .form-inline .input-group > .form-control { + width: 100%; + } + .form-inline .control-label { + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .radio, + .form-inline .checkbox { + display: inline-block; + margin-top: 0; + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .radio label, + .form-inline .checkbox label { + padding-left: 0; + } + .form-inline .radio input[type="radio"], + .form-inline .checkbox input[type="checkbox"] { + position: relative; + margin-left: 0; + } + .form-inline .has-feedback .form-control-feedback { + top: 0; + } +} +.form-horizontal .radio, +.form-horizontal .checkbox, +.form-horizontal .radio-inline, +.form-horizontal .checkbox-inline { + margin-top: 0; + margin-bottom: 0; + padding-top: 11px; +} +.form-horizontal .radio, +.form-horizontal .checkbox { + min-height: 32px; +} +.form-horizontal .form-group { + margin-left: -15px; + margin-right: -15px; +} +@media (min-width: 768px) { + .form-horizontal .control-label { + text-align: right; + margin-bottom: 0; + padding-top: 11px; + } +} +.form-horizontal .has-feedback .form-control-feedback { + top: 0; + right: 15px; +} +@media (min-width: 768px) { + .form-horizontal .form-group-lg .control-label { + padding-top: 24.94px; + } +} +@media (min-width: 768px) { + .form-horizontal .form-group-sm .control-label { + padding-top: 6px; + } +} +.btn { + display: inline-block; + margin-bottom: 0; + font-weight: normal; + text-align: center; + vertical-align: middle; + cursor: pointer; + background-image: none; + border: 1px solid transparent; + white-space: nowrap; + padding: 10px 18px; + font-size: 15px; + line-height: 1.42857143; + border-radius: 0; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.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 { + color: #ffffff; + text-decoration: none; +} +.btn:active, +.btn.active { + outline: 0; + background-image: none; + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); +} +.btn.disabled, +.btn[disabled], +fieldset[disabled] .btn { + cursor: not-allowed; + pointer-events: none; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + box-shadow: none; +} +.btn-default { + color: #ffffff; + background-color: #222222; + border-color: #222222; +} +.btn-default:hover, +.btn-default:focus, +.btn-default:active, +.btn-default.active, +.open > .dropdown-toggle.btn-default { + color: #ffffff; + background-color: #090909; + border-color: #040404; +} +.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: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: #222222; + border-color: #222222; +} +.btn-default .badge { + color: #222222; + background-color: #ffffff; +} +.btn-primary { + color: #ffffff; + background-color: #0072c6; + border-color: #0072c6; +} +.btn-primary:hover, +.btn-primary:focus, +.btn-primary:active, +.btn-primary.active, +.open > .dropdown-toggle.btn-primary { + color: #ffffff; + background-color: #005593; + border-color: #004f89; +} +.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: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: #0072c6; + border-color: #0072c6; +} +.btn-primary .badge { + color: #0072c6; + background-color: #ffffff; +} +.btn-success { + color: #ffffff; + background-color: #3fb618; + border-color: #3fb618; +} +.btn-success:hover, +.btn-success:focus, +.btn-success:active, +.btn-success.active, +.open > .dropdown-toggle.btn-success { + color: #ffffff; + background-color: #2f8912; + border-color: #2c8011; +} +.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: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: #3fb618; + border-color: #3fb618; +} +.btn-success .badge { + color: #3fb618; + background-color: #ffffff; +} +.btn-info { + color: #ffffff; + background-color: #9954bb; + border-color: #9954bb; +} +.btn-info:hover, +.btn-info:focus, +.btn-info:active, +.btn-info.active, +.open > .dropdown-toggle.btn-info { + color: #ffffff; + background-color: #7e3f9d; + border-color: #783c96; +} +.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: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: #9954bb; + border-color: #9954bb; +} +.btn-info .badge { + color: #9954bb; + background-color: #ffffff; +} +.btn-warning { + color: #ffffff; + background-color: #ff7518; + border-color: #ff7518; +} +.btn-warning:hover, +.btn-warning:focus, +.btn-warning:active, +.btn-warning.active, +.open > .dropdown-toggle.btn-warning { + color: #ffffff; + background-color: #e45c00; + border-color: #da5800; +} +.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: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: #ff7518; + border-color: #ff7518; +} +.btn-warning .badge { + color: #ff7518; + background-color: #ffffff; +} +.btn-danger { + color: #ffffff; + background-color: #ff0039; + border-color: #ff0039; +} +.btn-danger:hover, +.btn-danger:focus, +.btn-danger:active, +.btn-danger.active, +.open > .dropdown-toggle.btn-danger { + color: #ffffff; + background-color: #cc002e; + border-color: #c2002b; +} +.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: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: #ff0039; + border-color: #ff0039; +} +.btn-danger .badge { + color: #ff0039; + background-color: #ffffff; +} +.btn-link { + color: #0072c6; + font-weight: normal; + cursor: pointer; + border-radius: 0; +} +.btn-link, +.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: #00467a; + 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: #999999; + text-decoration: none; +} +.btn-lg, +.btn-group-lg > .btn { + padding: 18px 30px; + font-size: 19px; + line-height: 1.33; + border-radius: 0; +} +.btn-sm, +.btn-group-sm > .btn { + padding: 5px 10px; + font-size: 13px; + line-height: 1.5; + border-radius: 0; +} +.btn-xs, +.btn-group-xs > .btn { + padding: 1px 5px; + font-size: 13px; + line-height: 1.5; + border-radius: 0; +} +.btn-block { + display: block; + width: 100%; +} +.btn-block + .btn-block { + margin-top: 5px; +} +input[type="submit"].btn-block, +input[type="reset"].btn-block, +input[type="button"].btn-block { + width: 100%; +} +.fade { + opacity: 0; + -webkit-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; +} +.fade.in { + opacity: 1; +} +.collapse { + display: none; +} +.collapse.in { + display: block; +} +tr.collapse.in { + display: table-row; +} +tbody.collapse.in { + display: table-row-group; +} +.collapsing { + position: relative; + height: 0; + overflow: hidden; + -webkit-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; +} +.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; + list-style: none; + font-size: 15px; + text-align: left; + background-color: #ffffff; + border: 1px solid #cccccc; + border: 1px solid rgba(0, 0, 0, 0.15); + border-radius: 0; + -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + background-clip: padding-box; +} +.dropdown-menu.pull-right { + right: 0; + left: auto; +} +.dropdown-menu .divider { + height: 1px; + margin: 9.5px 0; + overflow: hidden; + background-color: #e5e5e5; +} +.dropdown-menu > li > a { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: 1.42857143; + color: #333333; + white-space: nowrap; +} +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus { + text-decoration: none; + color: #ffffff; + background-color: #0072c6; +} +.dropdown-menu > .active > a, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > a:focus { + color: #ffffff; + text-decoration: none; + outline: 0; + background-color: #0072c6; +} +.dropdown-menu > .disabled > a, +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + color: #999999; +} +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + text-decoration: none; + background-color: transparent; + background-image: none; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + cursor: not-allowed; +} +.open > .dropdown-menu { + display: block; +} +.open > a { + outline: 0; +} +.dropdown-menu-right { + left: auto; + right: 0; +} +.dropdown-menu-left { + left: 0; + right: auto; +} +.dropdown-header { + display: block; + padding: 3px 20px; + font-size: 13px; + line-height: 1.42857143; + color: #999999; + white-space: nowrap; +} +.dropdown-backdrop { + position: fixed; + left: 0; + right: 0; + bottom: 0; + top: 0; + z-index: 990; +} +.pull-right > .dropdown-menu { + right: 0; + left: auto; +} +.dropup .caret, +.navbar-fixed-bottom .dropdown .caret { + border-top: 0; + border-bottom: 4px solid; + content: ""; +} +.dropup .dropdown-menu, +.navbar-fixed-bottom .dropdown .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 1px; +} +@media (min-width: 768px) { + .navbar-right .dropdown-menu { + left: auto; + right: 0; + } + .navbar-right .dropdown-menu-left { + left: 0; + right: auto; + } +} +.btn-group, +.btn-group-vertical { + position: relative; + display: inline-block; + vertical-align: middle; +} +.btn-group > .btn, +.btn-group-vertical > .btn { + position: relative; + float: left; +} +.btn-group > .btn:hover, +.btn-group-vertical > .btn:hover, +.btn-group > .btn:focus, +.btn-group-vertical > .btn:focus, +.btn-group > .btn:active, +.btn-group-vertical > .btn:active, +.btn-group > .btn.active, +.btn-group-vertical > .btn.active { + z-index: 2; +} +.btn-group > .btn:focus, +.btn-group-vertical > .btn:focus { + outline: 0; +} +.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-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.btn-group > .btn:last-child:not(:first-child), +.btn-group > .dropdown-toggle:not(:first-child) { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.btn-group > .btn-group { + float: left; +} +.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} +.btn-group > .btn-group:first-child > .btn:last-child, +.btn-group > .btn-group:first-child > .dropdown-toggle { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.btn-group > .btn-group:last-child > .btn:first-child { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.btn-group .dropdown-toggle:active, +.btn-group.open .dropdown-toggle { + outline: 0; +} +.btn-group > .btn + .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; +} +.btn-group > .btn-lg + .dropdown-toggle { + padding-left: 12px; + padding-right: 12px; +} +.btn-group.open .dropdown-toggle { + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); +} +.btn-group.open .dropdown-toggle.btn-link { + -webkit-box-shadow: none; + box-shadow: none; +} +.btn .caret { + margin-left: 0; +} +.btn-lg .caret { + border-width: 5px 5px 0; + border-bottom-width: 0; +} +.dropup .btn-lg .caret { + border-width: 0 5px 5px; +} +.btn-group-vertical > .btn, +.btn-group-vertical > .btn-group, +.btn-group-vertical > .btn-group > .btn { + display: block; + float: none; + width: 100%; + max-width: 100%; +} +.btn-group-vertical > .btn-group > .btn { + float: none; +} +.btn-group-vertical > .btn + .btn, +.btn-group-vertical > .btn + .btn-group, +.btn-group-vertical > .btn-group + .btn, +.btn-group-vertical > .btn-group + .btn-group { + margin-top: -1px; + margin-left: 0; +} +.btn-group-vertical > .btn:not(:first-child):not(:last-child) { + border-radius: 0; +} +.btn-group-vertical > .btn:first-child:not(:last-child) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group-vertical > .btn:last-child:not(:first-child) { + border-bottom-left-radius: 0; + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} +.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child, +.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child { + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.btn-group-justified { + display: table; + width: 100%; + table-layout: fixed; + border-collapse: separate; +} +.btn-group-justified > .btn, +.btn-group-justified > .btn-group { + float: none; + display: table-cell; + width: 1%; +} +.btn-group-justified > .btn-group .btn { + width: 100%; +} +.btn-group-justified > .btn-group .dropdown-menu { + left: auto; +} +[data-toggle="buttons"] > .btn > input[type="radio"], +[data-toggle="buttons"] > .btn > input[type="checkbox"] { + position: absolute; + z-index: -1; + opacity: 0; + filter: alpha(opacity=0); +} +.input-group { + position: relative; + display: table; + border-collapse: separate; +} +.input-group[class*="col-"] { + float: none; + padding-left: 0; + padding-right: 0; +} +.input-group .form-control { + position: relative; + z-index: 2; + float: left; + width: 100%; + margin-bottom: 0; +} +.input-group-lg > .form-control, +.input-group-lg > .input-group-addon, +.input-group-lg > .input-group-btn > .btn { + height: 64px; + padding: 18px 30px; + font-size: 19px; + line-height: 1.33; + border-radius: 0; +} +select.input-group-lg > .form-control, +select.input-group-lg > .input-group-addon, +select.input-group-lg > .input-group-btn > .btn { + height: 64px; + line-height: 64px; +} +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: 31px; + padding: 5px 10px; + font-size: 13px; + line-height: 1.5; + border-radius: 0; +} +select.input-group-sm > .form-control, +select.input-group-sm > .input-group-addon, +select.input-group-sm > .input-group-btn > .btn { + height: 31px; + line-height: 31px; +} +textarea.input-group-sm > .form-control, +textarea.input-group-sm > .input-group-addon, +textarea.input-group-sm > .input-group-btn > .btn, +select[multiple].input-group-sm > .form-control, +select[multiple].input-group-sm > .input-group-addon, +select[multiple].input-group-sm > .input-group-btn > .btn { + height: auto; +} +.input-group-addon, +.input-group-btn, +.input-group .form-control { + display: table-cell; +} +.input-group-addon:not(:first-child):not(:last-child), +.input-group-btn:not(:first-child):not(:last-child), +.input-group .form-control:not(:first-child):not(:last-child) { + border-radius: 0; +} +.input-group-addon, +.input-group-btn { + width: 1%; + white-space: nowrap; + vertical-align: middle; +} +.input-group-addon { + padding: 10px 18px; + font-size: 15px; + font-weight: normal; + line-height: 1; + color: #333333; + text-align: center; + background-color: #e6e6e6; + border: 1px solid #cccccc; + border-radius: 0; +} +.input-group-addon.input-sm { + padding: 5px 10px; + font-size: 13px; + border-radius: 0; +} +.input-group-addon.input-lg { + padding: 18px 30px; + font-size: 19px; + border-radius: 0; +} +.input-group-addon input[type="radio"], +.input-group-addon input[type="checkbox"] { + margin-top: 0; +} +.input-group .form-control:first-child, +.input-group-addon:first-child, +.input-group-btn:first-child > .btn, +.input-group-btn:first-child > .btn-group > .btn, +.input-group-btn:first-child > .dropdown-toggle, +.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle), +.input-group-btn:last-child > .btn-group:not(:last-child) > .btn { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.input-group-addon:first-child { + border-right: 0; +} +.input-group .form-control:last-child, +.input-group-addon:last-child, +.input-group-btn:last-child > .btn, +.input-group-btn:last-child > .btn-group > .btn, +.input-group-btn:last-child > .dropdown-toggle, +.input-group-btn:first-child > .btn:not(:first-child), +.input-group-btn:first-child > .btn-group:not(:first-child) > .btn { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.input-group-addon:last-child { + border-left: 0; +} +.input-group-btn { + position: relative; + font-size: 0; + white-space: nowrap; +} +.input-group-btn > .btn { + position: relative; +} +.input-group-btn > .btn + .btn { + margin-left: -1px; +} +.input-group-btn > .btn:hover, +.input-group-btn > .btn:focus, +.input-group-btn > .btn:active { + z-index: 2; +} +.input-group-btn:first-child > .btn, +.input-group-btn:first-child > .btn-group { + margin-right: -1px; +} +.input-group-btn:last-child > .btn, +.input-group-btn:last-child > .btn-group { + margin-left: -1px; +} +.nav { + margin-bottom: 0; + padding-left: 0; + list-style: none; +} +.nav > li { + position: relative; + display: block; +} +.nav > li > a { + position: relative; + display: block; + padding: 10px 15px; +} +.nav > li > a:hover, +.nav > li > a:focus { + text-decoration: none; + background-color: #e6e6e6; +} +.nav > li.disabled > a { + color: #999999; +} +.nav > li.disabled > a:hover, +.nav > li.disabled > a:focus { + color: #999999; + text-decoration: none; + background-color: transparent; + cursor: not-allowed; +} +.nav .open > a, +.nav .open > a:hover, +.nav .open > a:focus { + background-color: #e6e6e6; + border-color: #0072c6; +} +.nav .nav-divider { + height: 1px; + margin: 9.5px 0; + overflow: hidden; + background-color: #e5e5e5; +} +.nav > li > a > img { + max-width: none; +} +.nav-tabs { + border-bottom: 1px solid #dddddd; +} +.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: 0 0 0 0; +} +.nav-tabs > li > a:hover { + border-color: #e6e6e6 #e6e6e6 #dddddd; +} +.nav-tabs > li.active > a, +.nav-tabs > li.active > a:hover, +.nav-tabs > li.active > a:focus { + color: #555555; + background-color: #ffffff; + border: 1px solid #dddddd; + border-bottom-color: transparent; + cursor: default; +} +.nav-tabs.nav-justified { + width: 100%; + border-bottom: 0; +} +.nav-tabs.nav-justified > li { + float: none; +} +.nav-tabs.nav-justified > li > a { + text-align: center; + margin-bottom: 5px; +} +.nav-tabs.nav-justified > .dropdown .dropdown-menu { + top: auto; + left: auto; +} +@media (min-width: 768px) { + .nav-tabs.nav-justified > li { + display: table-cell; + width: 1%; + } + .nav-tabs.nav-justified > li > a { + margin-bottom: 0; + } +} +.nav-tabs.nav-justified > li > a { + margin-right: 0; + border-radius: 0; +} +.nav-tabs.nav-justified > .active > a, +.nav-tabs.nav-justified > .active > a:hover, +.nav-tabs.nav-justified > .active > a:focus { + border: 1px solid #dddddd; +} +@media (min-width: 768px) { + .nav-tabs.nav-justified > li > a { + border-bottom: 1px solid #dddddd; + border-radius: 0 0 0 0; + } + .nav-tabs.nav-justified > .active > a, + .nav-tabs.nav-justified > .active > a:hover, + .nav-tabs.nav-justified > .active > a:focus { + border-bottom-color: #ffffff; + } +} +.nav-pills > li { + float: left; +} +.nav-pills > li > a { + border-radius: 0; +} +.nav-pills > li + li { + margin-left: 2px; +} +.nav-pills > li.active > a, +.nav-pills > li.active > a:hover, +.nav-pills > li.active > a:focus { + color: #ffffff; + background-color: #0072c6; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li + li { + margin-top: 2px; + margin-left: 0; +} +.nav-justified { + width: 100%; +} +.nav-justified > li { + float: none; +} +.nav-justified > li > a { + text-align: center; + margin-bottom: 5px; +} +.nav-justified > .dropdown .dropdown-menu { + top: auto; + left: auto; +} +@media (min-width: 768px) { + .nav-justified > li { + display: table-cell; + width: 1%; + } + .nav-justified > li > a { + margin-bottom: 0; + } +} +.nav-tabs-justified { + border-bottom: 0; +} +.nav-tabs-justified > li > a { + margin-right: 0; + border-radius: 0; +} +.nav-tabs-justified > .active > a, +.nav-tabs-justified > .active > a:hover, +.nav-tabs-justified > .active > a:focus { + border: 1px solid #dddddd; +} +@media (min-width: 768px) { + .nav-tabs-justified > li > a { + border-bottom: 1px solid #dddddd; + border-radius: 0 0 0 0; + } + .nav-tabs-justified > .active > a, + .nav-tabs-justified > .active > a:hover, + .nav-tabs-justified > .active > a:focus { + border-bottom-color: #ffffff; + } +} +.tab-content > .tab-pane { + display: none; +} +.tab-content > .active { + display: block; +} +.nav-tabs .dropdown-menu { + margin-top: -1px; + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.navbar { + position: relative; + min-height: 50px; + margin-bottom: 21px; + border: 1px solid transparent; +} +@media (min-width: 768px) { + .navbar { + border-radius: 0; + } +} +@media (min-width: 768px) { + .navbar-header { + float: left; + } +} +.navbar-collapse { + overflow-x: visible; + padding-right: 15px; + padding-left: 15px; + border-top: 1px solid transparent; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1); + -webkit-overflow-scrolling: touch; +} +.navbar-collapse.in { + overflow-y: auto; +} +@media (min-width: 768px) { + .navbar-collapse { + width: auto; + border-top: 0; + box-shadow: none; + } + .navbar-collapse.collapse { + display: block !important; + height: auto !important; + padding-bottom: 0; + overflow: visible !important; + } + .navbar-collapse.in { + overflow-y: visible; + } + .navbar-fixed-top .navbar-collapse, + .navbar-static-top .navbar-collapse, + .navbar-fixed-bottom .navbar-collapse { + padding-left: 0; + padding-right: 0; + } +} +.navbar-fixed-top .navbar-collapse, +.navbar-fixed-bottom .navbar-collapse { + max-height: 340px; +} +@media (max-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; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); +} +@media (min-width: 768px) { + .navbar-fixed-top, + .navbar-fixed-bottom { + border-radius: 0; + } +} +.navbar-fixed-top { + top: 0; + border-width: 0 0 1px; +} +.navbar-fixed-bottom { + bottom: 0; + margin-bottom: 0; + border-width: 1px 0 0; +} +.navbar-brand { + float: left; + padding: 14.5px 15px; + font-size: 19px; + line-height: 21px; + height: 50px; +} +.navbar-brand:hover, +.navbar-brand:focus { + text-decoration: none; +} +@media (min-width: 768px) { + .navbar > .container .navbar-brand, + .navbar > .container-fluid .navbar-brand { + margin-left: -15px; + } +} +.navbar-toggle { + position: relative; + float: right; + margin-right: 15px; + padding: 9px 10px; + margin-top: 8px; + margin-bottom: 8px; + background-color: transparent; + background-image: none; + border: 1px solid transparent; + border-radius: 0; +} +.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.25px -15px; +} +.navbar-nav > li > a { + padding-top: 10px; + padding-bottom: 10px; + line-height: 21px; +} +@media (max-width: 767px) { + .navbar-nav .open .dropdown-menu { + position: static; + float: none; + width: auto; + margin-top: 0; + background-color: transparent; + border: 0; + box-shadow: none; + } + .navbar-nav .open .dropdown-menu > li > a, + .navbar-nav .open .dropdown-menu .dropdown-header { + padding: 5px 15px 5px 25px; + } + .navbar-nav .open .dropdown-menu > li > a { + line-height: 21px; + } + .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-nav .open .dropdown-menu > li > a:focus { + background-image: none; + } +} +@media (min-width: 768px) { + .navbar-nav { + float: left; + margin: 0; + } + .navbar-nav > li { + float: left; + } + .navbar-nav > li > a { + padding-top: 14.5px; + padding-bottom: 14.5px; + } + .navbar-nav.navbar-right:last-child { + margin-right: -15px; + } +} +@media (min-width: 768px) { + .navbar-left { + float: left !important; + } + .navbar-right { + float: right !important; + } +} +.navbar-form { + margin-left: -15px; + margin-right: -15px; + padding: 10px 15px; + border-top: 1px solid transparent; + border-bottom: 1px solid transparent; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + margin-top: 3.5px; + margin-bottom: 3.5px; +} +@media (min-width: 768px) { + .navbar-form .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .form-control { + display: inline-block; + width: auto; + vertical-align: middle; + } + .navbar-form .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; + } +} +@media (min-width: 768px) { + .navbar-form { + width: auto; + border: 0; + margin-left: 0; + margin-right: 0; + padding-top: 0; + padding-bottom: 0; + -webkit-box-shadow: none; + box-shadow: none; + } + .navbar-form.navbar-right:last-child { + margin-right: -15px; + } +} +.navbar-nav > li > .dropdown-menu { + margin-top: 0; + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.navbar-btn { + margin-top: 3.5px; + margin-bottom: 3.5px; +} +.navbar-btn.btn-sm { + margin-top: 9.5px; + margin-bottom: 9.5px; +} +.navbar-btn.btn-xs { + margin-top: 14px; + margin-bottom: 14px; +} +.navbar-text { + margin-top: 14.5px; + margin-bottom: 14.5px; +} +@media (min-width: 768px) { + .navbar-text { + float: left; + margin-left: 15px; + margin-right: 15px; + } + .navbar-text.navbar-right:last-child { + margin-right: 0; + } +} +.navbar-default { + background-color: #222222; + border-color: #121212; +} +.navbar-default .navbar-brand { + color: #ffffff; +} +.navbar-default .navbar-brand:hover, +.navbar-default .navbar-brand:focus { + color: #ffffff; + background-color: none; +} +.navbar-default .navbar-text { + color: #ffffff; +} +.navbar-default .navbar-nav > li > a { + color: #ffffff; +} +.navbar-default .navbar-nav > li > a:hover, +.navbar-default .navbar-nav > li > a:focus { + color: #ffffff; + background-color: #090909; +} +.navbar-default .navbar-nav > .active > a, +.navbar-default .navbar-nav > .active > a:hover, +.navbar-default .navbar-nav > .active > a:focus { + color: #ffffff; + background-color: #090909; +} +.navbar-default .navbar-nav > .disabled > a, +.navbar-default .navbar-nav > .disabled > a:hover, +.navbar-default .navbar-nav > .disabled > a:focus { + color: #cccccc; + background-color: transparent; +} +.navbar-default .navbar-toggle { + border-color: transparent; +} +.navbar-default .navbar-toggle:hover, +.navbar-default .navbar-toggle:focus { + background-color: #090909; +} +.navbar-default .navbar-toggle .icon-bar { + background-color: #ffffff; +} +.navbar-default .navbar-collapse, +.navbar-default .navbar-form { + border-color: #121212; +} +.navbar-default .navbar-nav > .open > a, +.navbar-default .navbar-nav > .open > a:hover, +.navbar-default .navbar-nav > .open > a:focus { + background-color: #090909; + color: #ffffff; +} +@media (max-width: 767px) { + .navbar-default .navbar-nav .open .dropdown-menu > li > a { + color: #ffffff; + } + .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus { + color: #ffffff; + background-color: #090909; + } + .navbar-default .navbar-nav .open .dropdown-menu > .active > a, + .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus { + color: #ffffff; + background-color: #090909; + } + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a, + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus { + color: #cccccc; + background-color: transparent; + } +} +.navbar-default .navbar-link { + color: #ffffff; +} +.navbar-default .navbar-link:hover { + color: #ffffff; +} +.navbar-default .btn-link { + color: #ffffff; +} +.navbar-default .btn-link:hover, +.navbar-default .btn-link:focus { + color: #ffffff; +} +.navbar-default .btn-link[disabled]:hover, +fieldset[disabled] .navbar-default .btn-link:hover, +.navbar-default .btn-link[disabled]:focus, +fieldset[disabled] .navbar-default .btn-link:focus { + color: #cccccc; +} +.navbar-inverse { + background-color: #0072c6; + border-color: #005593; +} +.navbar-inverse .navbar-brand { + color: #ffffff; +} +.navbar-inverse .navbar-brand:hover, +.navbar-inverse .navbar-brand:focus { + color: #ffffff; + background-color: none; +} +.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: #ffffff; + background-color: #005593; +} +.navbar-inverse .navbar-nav > .active > a, +.navbar-inverse .navbar-nav > .active > a:hover, +.navbar-inverse .navbar-nav > .active > a:focus { + color: #ffffff; + background-color: #005593; +} +.navbar-inverse .navbar-nav > .disabled > a, +.navbar-inverse .navbar-nav > .disabled > a:hover, +.navbar-inverse .navbar-nav > .disabled > a:focus { + color: #ffffff; + background-color: transparent; +} +.navbar-inverse .navbar-toggle { + border-color: transparent; +} +.navbar-inverse .navbar-toggle:hover, +.navbar-inverse .navbar-toggle:focus { + background-color: #005593; +} +.navbar-inverse .navbar-toggle .icon-bar { + background-color: #ffffff; +} +.navbar-inverse .navbar-collapse, +.navbar-inverse .navbar-form { + border-color: #005da2; +} +.navbar-inverse .navbar-nav > .open > a, +.navbar-inverse .navbar-nav > .open > a:hover, +.navbar-inverse .navbar-nav > .open > a:focus { + background-color: #005593; + color: #ffffff; +} +@media (max-width: 767px) { + .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header { + border-color: #005593; + } + .navbar-inverse .navbar-nav .open .dropdown-menu .divider { + background-color: #005593; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a { + color: #ffffff; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus { + color: #ffffff; + background-color: #005593; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a, + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus { + color: #ffffff; + background-color: #005593; + } + .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: #ffffff; + background-color: transparent; + } +} +.navbar-inverse .navbar-link { + color: #ffffff; +} +.navbar-inverse .navbar-link:hover { + color: #ffffff; +} +.navbar-inverse .btn-link { + color: #ffffff; +} +.navbar-inverse .btn-link:hover, +.navbar-inverse .btn-link:focus { + color: #ffffff; +} +.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: #ffffff; +} +.breadcrumb { + padding: 8px 15px; + margin-bottom: 21px; + list-style: none; + background-color: #f5f5f5; + border-radius: 0; +} +.breadcrumb > li { + display: inline-block; +} +.breadcrumb > li + li:before { + content: "/\00a0"; + padding: 0 5px; + color: #cccccc; +} +.breadcrumb > .active { + color: #999999; +} +.pagination { + display: inline-block; + padding-left: 0; + margin: 21px 0; + border-radius: 0; +} +.pagination > li { + display: inline; +} +.pagination > li > a, +.pagination > li > span { + position: relative; + float: left; + padding: 10px 18px; + line-height: 1.42857143; + text-decoration: none; + color: #0072c6; + background-color: #ffffff; + border: 1px solid #dddddd; + margin-left: -1px; +} +.pagination > li:first-child > a, +.pagination > li:first-child > span { + margin-left: 0; + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.pagination > li:last-child > a, +.pagination > li:last-child > span { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.pagination > li > a:hover, +.pagination > li > span:hover, +.pagination > li > a:focus, +.pagination > li > span:focus { + color: #00467a; + background-color: #e6e6e6; + border-color: #dddddd; +} +.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: #999999; + background-color: #f5f5f5; + border-color: #dddddd; + cursor: default; +} +.pagination > .disabled > span, +.pagination > .disabled > span:hover, +.pagination > .disabled > span:focus, +.pagination > .disabled > a, +.pagination > .disabled > a:hover, +.pagination > .disabled > a:focus { + color: #999999; + background-color: #ffffff; + border-color: #dddddd; + cursor: not-allowed; +} +.pagination-lg > li > a, +.pagination-lg > li > span { + padding: 18px 30px; + font-size: 19px; +} +.pagination-lg > li:first-child > a, +.pagination-lg > li:first-child > span { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.pagination-lg > li:last-child > a, +.pagination-lg > li:last-child > span { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.pagination-sm > li > a, +.pagination-sm > li > span { + padding: 5px 10px; + font-size: 13px; +} +.pagination-sm > li:first-child > a, +.pagination-sm > li:first-child > span { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.pagination-sm > li:last-child > a, +.pagination-sm > li:last-child > span { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.pager { + padding-left: 0; + margin: 21px 0; + list-style: none; + text-align: center; +} +.pager li { + display: inline; +} +.pager li > a, +.pager li > span { + display: inline-block; + padding: 5px 14px; + background-color: #ffffff; + border: 1px solid #dddddd; + border-radius: 0; +} +.pager li > a:hover, +.pager li > a:focus { + text-decoration: none; + background-color: #e6e6e6; +} +.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: #999999; + background-color: #ffffff; + cursor: not-allowed; +} +.label { + display: inline; + padding: .2em .6em .3em; + font-size: 75%; + font-weight: bold; + line-height: 1; + color: #ffffff; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: .25em; +} +a.label:hover, +a.label:focus { + color: #ffffff; + text-decoration: none; + cursor: pointer; +} +.label:empty { + display: none; +} +.btn .label { + position: relative; + top: -1px; +} +.label-default { + background-color: #222222; +} +.label-default[href]:hover, +.label-default[href]:focus { + background-color: #090909; +} +.label-primary { + background-color: #0072c6; +} +.label-primary[href]:hover, +.label-primary[href]:focus { + background-color: #005593; +} +.label-success { + background-color: #3fb618; +} +.label-success[href]:hover, +.label-success[href]:focus { + background-color: #2f8912; +} +.label-info { + background-color: #9954bb; +} +.label-info[href]:hover, +.label-info[href]:focus { + background-color: #7e3f9d; +} +.label-warning { + background-color: #ff7518; +} +.label-warning[href]:hover, +.label-warning[href]:focus { + background-color: #e45c00; +} +.label-danger { + background-color: #ff0039; +} +.label-danger[href]:hover, +.label-danger[href]:focus { + background-color: #cc002e; +} +.badge { + display: inline-block; + min-width: 10px; + padding: 3px 7px; + font-size: 13px; + font-weight: bold; + color: #ffffff; + line-height: 1; + vertical-align: baseline; + white-space: nowrap; + text-align: center; + background-color: #0072c6; + 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: #ffffff; + text-decoration: none; + cursor: pointer; +} +a.list-group-item.active > .badge, +.nav-pills > .active > a > .badge { + color: #0072c6; + background-color: #ffffff; +} +.nav-pills > li > a > .badge { + margin-left: 3px; +} +.jumbotron { + padding: 30px; + margin-bottom: 30px; + color: inherit; + background-color: #e6e6e6; +} +.jumbotron h1, +.jumbotron .h1 { + color: inherit; +} +.jumbotron p { + margin-bottom: 15px; + font-size: 23px; + font-weight: 200; +} +.jumbotron > hr { + border-top-color: #cccccc; +} +.container .jumbotron { + border-radius: 0; +} +.jumbotron .container { + max-width: 100%; +} +@media screen and (min-width: 768px) { + .jumbotron { + padding-top: 48px; + padding-bottom: 48px; + } + .container .jumbotron { + padding-left: 60px; + padding-right: 60px; + } + .jumbotron h1, + .jumbotron .h1 { + font-size: 67.5px; + } +} +.thumbnail { + display: block; + padding: 4px; + margin-bottom: 21px; + line-height: 1.42857143; + background-color: #ffffff; + border: 1px solid #dddddd; + border-radius: 0; + -webkit-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} +.thumbnail > img, +.thumbnail a > img { + margin-left: auto; + margin-right: auto; +} +a.thumbnail:hover, +a.thumbnail:focus, +a.thumbnail.active { + border-color: #0072c6; +} +.thumbnail .caption { + padding: 9px; + color: #333333; +} +.alert { + padding: 15px; + margin-bottom: 21px; + border: 1px solid transparent; + border-radius: 0; +} +.alert h4 { + margin-top: 0; + color: inherit; +} +.alert .alert-link { + font-weight: bold; +} +.alert > p, +.alert > ul { + margin-bottom: 0; +} +.alert > p + p { + margin-top: 5px; +} +.alert-dismissable, +.alert-dismissible { + padding-right: 35px; +} +.alert-dismissable .close, +.alert-dismissible .close { + position: relative; + top: -2px; + right: -21px; + color: inherit; +} +.alert-success { + background-color: #3fb618; + border-color: #4e9f15; + color: #ffffff; +} +.alert-success hr { + border-top-color: #438912; +} +.alert-success .alert-link { + color: #e6e6e6; +} +.alert-info { + background-color: #9954bb; + border-color: #7643a8; + color: #ffffff; +} +.alert-info hr { + border-top-color: #693c96; +} +.alert-info .alert-link { + color: #e6e6e6; +} +.alert-warning { + background-color: #ff7518; + border-color: #ff4309; + color: #ffffff; +} +.alert-warning hr { + border-top-color: #ee3800; +} +.alert-warning .alert-link { + color: #e6e6e6; +} +.alert-danger { + background-color: #ff0039; + border-color: #f0005e; + color: #ffffff; +} +.alert-danger hr { + border-top-color: #d60054; +} +.alert-danger .alert-link { + color: #e6e6e6; +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +@keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +.progress { + overflow: hidden; + height: 21px; + margin-bottom: 21px; + background-color: #cccccc; + border-radius: 0; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); +} +.progress-bar { + float: left; + width: 0%; + height: 100%; + font-size: 13px; + line-height: 21px; + color: #ffffff; + text-align: center; + background-color: #0072c6; + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} +.progress-striped .progress-bar, +.progress-bar-striped { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + 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[aria-valuenow="1"], +.progress-bar[aria-valuenow="2"] { + min-width: 30px; +} +.progress-bar[aria-valuenow="0"] { + color: #999999; + min-width: 30px; + background-color: transparent; + background-image: none; + box-shadow: none; +} +.progress-bar-success { + background-color: #3fb618; +} +.progress-striped .progress-bar-success { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-bar-info { + background-color: #9954bb; +} +.progress-striped .progress-bar-info { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-bar-warning { + background-color: #ff7518; +} +.progress-striped .progress-bar-warning { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-bar-danger { + background-color: #ff0039; +} +.progress-striped .progress-bar-danger { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.media, +.media-body { + overflow: hidden; + zoom: 1; +} +.media, +.media .media { + margin-top: 15px; +} +.media:first-child { + margin-top: 0; +} +.media-object { + display: block; +} +.media-heading { + margin: 0 0 5px; +} +.media > .pull-left { + margin-right: 10px; +} +.media > .pull-right { + margin-left: 10px; +} +.media-list { + padding-left: 0; + list-style: none; +} +.list-group { + margin-bottom: 20px; + padding-left: 0; +} +.list-group-item { + position: relative; + display: block; + padding: 10px 15px; + margin-bottom: -1px; + background-color: #ffffff; + border: 1px solid #dddddd; +} +.list-group-item:first-child { + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.list-group-item:last-child { + margin-bottom: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.list-group-item > .badge { + float: right; +} +.list-group-item > .badge + .badge { + margin-right: 5px; +} +a.list-group-item { + color: #555555; +} +a.list-group-item .list-group-item-heading { + color: #333333; +} +a.list-group-item:hover, +a.list-group-item:focus { + text-decoration: none; + color: #555555; + background-color: #f5f5f5; +} +.list-group-item.disabled, +.list-group-item.disabled:hover, +.list-group-item.disabled:focus { + background-color: #e6e6e6; + color: #999999; +} +.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: #999999; +} +.list-group-item.active, +.list-group-item.active:hover, +.list-group-item.active:focus { + z-index: 2; + color: #ffffff; + background-color: #0072c6; + border-color: #0072c6; +} +.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: #93d1ff; +} +.list-group-item-success { + color: #ffffff; + background-color: #3fb618; +} +a.list-group-item-success { + color: #ffffff; +} +a.list-group-item-success .list-group-item-heading { + color: inherit; +} +a.list-group-item-success:hover, +a.list-group-item-success:focus { + color: #ffffff; + background-color: #379f15; +} +a.list-group-item-success.active, +a.list-group-item-success.active:hover, +a.list-group-item-success.active:focus { + color: #fff; + background-color: #ffffff; + border-color: #ffffff; +} +.list-group-item-info { + color: #ffffff; + background-color: #9954bb; +} +a.list-group-item-info { + color: #ffffff; +} +a.list-group-item-info .list-group-item-heading { + color: inherit; +} +a.list-group-item-info:hover, +a.list-group-item-info:focus { + color: #ffffff; + background-color: #8d46b0; +} +a.list-group-item-info.active, +a.list-group-item-info.active:hover, +a.list-group-item-info.active:focus { + color: #fff; + background-color: #ffffff; + border-color: #ffffff; +} +.list-group-item-warning { + color: #ffffff; + background-color: #ff7518; +} +a.list-group-item-warning { + color: #ffffff; +} +a.list-group-item-warning .list-group-item-heading { + color: inherit; +} +a.list-group-item-warning:hover, +a.list-group-item-warning:focus { + color: #ffffff; + background-color: #fe6600; +} +a.list-group-item-warning.active, +a.list-group-item-warning.active:hover, +a.list-group-item-warning.active:focus { + color: #fff; + background-color: #ffffff; + border-color: #ffffff; +} +.list-group-item-danger { + color: #ffffff; + background-color: #ff0039; +} +a.list-group-item-danger { + color: #ffffff; +} +a.list-group-item-danger .list-group-item-heading { + color: inherit; +} +a.list-group-item-danger:hover, +a.list-group-item-danger:focus { + color: #ffffff; + background-color: #e60033; +} +a.list-group-item-danger.active, +a.list-group-item-danger.active:hover, +a.list-group-item-danger.active:focus { + color: #fff; + background-color: #ffffff; + border-color: #ffffff; +} +.list-group-item-heading { + margin-top: 0; + margin-bottom: 5px; +} +.list-group-item-text { + margin-bottom: 0; + line-height: 1.3; +} +.panel { + margin-bottom: 21px; + background-color: #ffffff; + border: 1px solid transparent; + border-radius: 0; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); +} +.panel-body { + padding: 15px; +} +.panel-heading { + padding: 10px 15px; + border-bottom: 1px solid transparent; + border-top-right-radius: -1; + border-top-left-radius: -1; +} +.panel-heading > .dropdown .dropdown-toggle { + color: inherit; +} +.panel-title { + margin-top: 0; + margin-bottom: 0; + font-size: 17px; + color: inherit; +} +.panel-title > a { + color: inherit; +} +.panel-footer { + padding: 10px 15px; + background-color: #f5f5f5; + border-top: 1px solid #dddddd; + border-bottom-right-radius: -1; + border-bottom-left-radius: -1; +} +.panel > .list-group { + margin-bottom: 0; +} +.panel > .list-group .list-group-item { + border-width: 1px 0; + border-radius: 0; +} +.panel > .list-group:first-child .list-group-item:first-child { + border-top: 0; + border-top-right-radius: -1; + border-top-left-radius: -1; +} +.panel > .list-group:last-child .list-group-item:last-child { + border-bottom: 0; + border-bottom-right-radius: -1; + border-bottom-left-radius: -1; +} +.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:first-child, +.panel > .table-responsive:first-child > .table:first-child { + border-top-right-radius: -1; + border-top-left-radius: -1; +} +.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: -1; +} +.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: -1; +} +.panel > .table:last-child, +.panel > .table-responsive:last-child > .table:last-child { + border-bottom-right-radius: -1; + border-bottom-left-radius: -1; +} +.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: -1; +} +.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: -1; +} +.panel > .panel-body + .table, +.panel > .panel-body + .table-responsive { + border-top: 1px solid #dddddd; +} +.panel > .table > tbody:first-child > tr:first-child th, +.panel > .table > tbody:first-child > tr:first-child td { + border-top: 0; +} +.panel > .table-bordered, +.panel > .table-responsive > .table-bordered { + border: 0; +} +.panel > .table-bordered > thead > tr > th:first-child, +.panel > .table-responsive > .table-bordered > thead > tr > th:first-child, +.panel > .table-bordered > tbody > tr > th:first-child, +.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child, +.panel > .table-bordered > tfoot > tr > th:first-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child, +.panel > .table-bordered > thead > tr > td:first-child, +.panel > .table-responsive > .table-bordered > thead > tr > td:first-child, +.panel > .table-bordered > tbody > tr > td:first-child, +.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child, +.panel > .table-bordered > tfoot > tr > td:first-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child { + border-left: 0; +} +.panel > .table-bordered > thead > tr > th:last-child, +.panel > .table-responsive > .table-bordered > thead > tr > th:last-child, +.panel > .table-bordered > tbody > tr > th:last-child, +.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child, +.panel > .table-bordered > tfoot > tr > th:last-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child, +.panel > .table-bordered > thead > tr > td:last-child, +.panel > .table-responsive > .table-bordered > thead > tr > td:last-child, +.panel > .table-bordered > tbody > tr > td:last-child, +.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child, +.panel > .table-bordered > tfoot > tr > td:last-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child { + border-right: 0; +} +.panel > .table-bordered > thead > tr:first-child > td, +.panel > .table-responsive > .table-bordered > thead > tr:first-child > td, +.panel > .table-bordered > tbody > tr:first-child > td, +.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td, +.panel > .table-bordered > thead > tr:first-child > th, +.panel > .table-responsive > .table-bordered > thead > tr:first-child > th, +.panel > .table-bordered > tbody > tr:first-child > th, +.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th { + border-bottom: 0; +} +.panel > .table-bordered > tbody > tr:last-child > td, +.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td, +.panel > .table-bordered > tfoot > tr:last-child > td, +.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td, +.panel > .table-bordered > tbody > tr:last-child > th, +.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th, +.panel > .table-bordered > tfoot > tr:last-child > th, +.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th { + border-bottom: 0; +} +.panel > .table-responsive { + border: 0; + margin-bottom: 0; +} +.panel-group { + margin-bottom: 21px; +} +.panel-group .panel { + margin-bottom: 0; + border-radius: 0; +} +.panel-group .panel + .panel { + margin-top: 5px; +} +.panel-group .panel-heading { + border-bottom: 0; +} +.panel-group .panel-heading + .panel-collapse > .panel-body { + border-top: 1px solid #dddddd; +} +.panel-group .panel-footer { + border-top: 0; +} +.panel-group .panel-footer + .panel-collapse .panel-body { + border-bottom: 1px solid #dddddd; +} +.panel-default { + border-color: #dddddd; +} +.panel-default > .panel-heading { + color: #333333; + background-color: #f5f5f5; + border-color: #dddddd; +} +.panel-default > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #dddddd; +} +.panel-default > .panel-heading .badge { + color: #f5f5f5; + background-color: #333333; +} +.panel-default > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #dddddd; +} +.panel-primary { + border-color: #0072c6; +} +.panel-primary > .panel-heading { + color: #ffffff; + background-color: #0072c6; + border-color: #0072c6; +} +.panel-primary > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #0072c6; +} +.panel-primary > .panel-heading .badge { + color: #0072c6; + background-color: #ffffff; +} +.panel-primary > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #0072c6; +} +.panel-success { + border-color: #4e9f15; +} +.panel-success > .panel-heading { + color: #ffffff; + background-color: #3fb618; + border-color: #4e9f15; +} +.panel-success > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #4e9f15; +} +.panel-success > .panel-heading .badge { + color: #3fb618; + background-color: #ffffff; +} +.panel-success > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #4e9f15; +} +.panel-info { + border-color: #7643a8; +} +.panel-info > .panel-heading { + color: #ffffff; + background-color: #9954bb; + border-color: #7643a8; +} +.panel-info > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #7643a8; +} +.panel-info > .panel-heading .badge { + color: #9954bb; + background-color: #ffffff; +} +.panel-info > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #7643a8; +} +.panel-warning { + border-color: #ff4309; +} +.panel-warning > .panel-heading { + color: #ffffff; + background-color: #ff7518; + border-color: #ff4309; +} +.panel-warning > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #ff4309; +} +.panel-warning > .panel-heading .badge { + color: #ff7518; + background-color: #ffffff; +} +.panel-warning > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #ff4309; +} +.panel-danger { + border-color: #f0005e; +} +.panel-danger > .panel-heading { + color: #ffffff; + background-color: #ff0039; + border-color: #f0005e; +} +.panel-danger > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #f0005e; +} +.panel-danger > .panel-heading .badge { + color: #ff0039; + background-color: #ffffff; +} +.panel-danger > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #f0005e; +} +.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 { + position: absolute; + top: 0; + left: 0; + bottom: 0; + height: 100%; + width: 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: 0; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} +.well-lg { + padding: 24px; + border-radius: 0; +} +.well-sm { + padding: 9px; + border-radius: 0; +} +.close { + float: right; + font-size: 22.5px; + font-weight: bold; + line-height: 1; + color: #ffffff; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} +.close:hover, +.close:focus { + color: #ffffff; + text-decoration: none; + cursor: pointer; + opacity: 0.5; + filter: alpha(opacity=50); +} +button.close { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; +} +.modal-open { + overflow: hidden; +} +.modal { + display: none; + overflow: hidden; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1050; + -webkit-overflow-scrolling: touch; + outline: 0; +} +.modal.fade .modal-dialog { + -webkit-transform: translate3d(0, -25%, 0); + transform: translate3d(0, -25%, 0); + -webkit-transition: -webkit-transform 0.3s ease-out; + -moz-transition: -moz-transform 0.3s ease-out; + -o-transition: -o-transform 0.3s ease-out; + transition: transform 0.3s ease-out; +} +.modal.in .modal-dialog { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); +} +.modal-open .modal { + overflow-x: hidden; + overflow-y: auto; +} +.modal-dialog { + position: relative; + width: auto; + margin: 10px; +} +.modal-content { + position: relative; + background-color: #ffffff; + border: 1px solid #999999; + border: 1px solid transparent; + border-radius: 0; + -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); + box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); + background-clip: padding-box; + outline: 0; +} +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} +.modal-backdrop.fade { + opacity: 0; + filter: alpha(opacity=0); +} +.modal-backdrop.in { + opacity: 0.5; + filter: alpha(opacity=50); +} +.modal-header { + padding: 15px; + border-bottom: 1px solid #e5e5e5; + min-height: 16.42857143px; +} +.modal-header .close { + margin-top: -2px; +} +.modal-title { + margin: 0; + line-height: 1.42857143; +} +.modal-body { + position: relative; + padding: 20px; +} +.modal-footer { + padding: 20px; + text-align: right; + border-top: 1px solid #e5e5e5; +} +.modal-footer .btn + .btn { + margin-left: 5px; + margin-bottom: 0; +} +.modal-footer .btn-group .btn + .btn { + margin-left: -1px; +} +.modal-footer .btn-block + .btn-block { + margin-left: 0; +} +.modal-scrollbar-measure { + position: absolute; + top: -9999px; + width: 50px; + height: 50px; + overflow: scroll; +} +@media (min-width: 768px) { + .modal-dialog { + width: 600px; + margin: 30px auto; + } + .modal-content { + -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); + } + .modal-sm { + width: 300px; + } +} +@media (min-width: 992px) { + .modal-lg { + width: 900px; + } +} +.tooltip { + position: absolute; + z-index: 1070; + display: block; + visibility: visible; + font-size: 13px; + line-height: 1.4; + opacity: 0; + filter: alpha(opacity=0); +} +.tooltip.in { + opacity: 0.9; + filter: alpha(opacity=90); +} +.tooltip.top { + margin-top: -3px; + padding: 5px 0; +} +.tooltip.right { + margin-left: 3px; + padding: 0 5px; +} +.tooltip.bottom { + margin-top: 3px; + padding: 5px 0; +} +.tooltip.left { + margin-left: -3px; + padding: 0 5px; +} +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: rgba(0, 0, 0, 0.9); + border-radius: 0; +} +.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: rgba(0, 0, 0, 0.9); +} +.tooltip.top-left .tooltip-arrow { + bottom: 0; + left: 5px; + border-width: 5px 5px 0; + border-top-color: rgba(0, 0, 0, 0.9); +} +.tooltip.top-right .tooltip-arrow { + bottom: 0; + right: 5px; + border-width: 5px 5px 0; + border-top-color: rgba(0, 0, 0, 0.9); +} +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-width: 5px 5px 5px 0; + border-right-color: rgba(0, 0, 0, 0.9); +} +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-width: 5px 0 5px 5px; + border-left-color: rgba(0, 0, 0, 0.9); +} +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-width: 0 5px 5px; + border-bottom-color: rgba(0, 0, 0, 0.9); +} +.tooltip.bottom-left .tooltip-arrow { + top: 0; + left: 5px; + border-width: 0 5px 5px; + border-bottom-color: rgba(0, 0, 0, 0.9); +} +.tooltip.bottom-right .tooltip-arrow { + top: 0; + right: 5px; + border-width: 0 5px 5px; + border-bottom-color: rgba(0, 0, 0, 0.9); +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1060; + display: none; + max-width: 276px; + padding: 1px; + text-align: left; + background-color: #ffffff; + background-clip: padding-box; + border: 1px solid #cccccc; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 0; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + white-space: normal; +} +.popover.top { + margin-top: -10px; +} +.popover.right { + margin-left: 10px; +} +.popover.bottom { + margin-top: 10px; +} +.popover.left { + margin-left: -10px; +} +.popover-title { + margin: 0; + padding: 8px 14px; + font-size: 15px; + font-weight: normal; + line-height: 18px; + background-color: #f7f7f7; + border-bottom: 1px solid #ebebeb; + border-radius: -1 -1 0 0; +} +.popover-content { + padding: 9px 14px; +} +.popover > .arrow, +.popover > .arrow:after { + position: absolute; + display: block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +.popover > .arrow { + border-width: 11px; +} +.popover > .arrow:after { + border-width: 10px; + content: ""; +} +.popover.top > .arrow { + left: 50%; + margin-left: -11px; + border-bottom-width: 0; + border-top-color: #999999; + border-top-color: rgba(0, 0, 0, 0.25); + bottom: -11px; +} +.popover.top > .arrow:after { + content: " "; + bottom: 1px; + margin-left: -10px; + border-bottom-width: 0; + border-top-color: #ffffff; +} +.popover.right > .arrow { + top: 50%; + left: -11px; + margin-top: -11px; + border-left-width: 0; + border-right-color: #999999; + border-right-color: rgba(0, 0, 0, 0.25); +} +.popover.right > .arrow:after { + content: " "; + left: 1px; + bottom: -10px; + border-left-width: 0; + border-right-color: #ffffff; +} +.popover.bottom > .arrow { + left: 50%; + margin-left: -11px; + border-top-width: 0; + border-bottom-color: #999999; + border-bottom-color: rgba(0, 0, 0, 0.25); + top: -11px; +} +.popover.bottom > .arrow:after { + content: " "; + top: 1px; + margin-left: -10px; + border-top-width: 0; + border-bottom-color: #ffffff; +} +.popover.left > .arrow { + top: 50%; + right: -11px; + margin-top: -11px; + border-right-width: 0; + border-left-color: #999999; + border-left-color: rgba(0, 0, 0, 0.25); +} +.popover.left > .arrow:after { + content: " "; + right: 1px; + border-right-width: 0; + border-left-color: #ffffff; + bottom: -10px; +} +.carousel { + position: relative; +} +.carousel-inner { + position: relative; + overflow: hidden; + width: 100%; +} +.carousel-inner > .item { + display: none; + position: relative; + -webkit-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} +.carousel-inner > .item > img, +.carousel-inner > .item > a > img { + line-height: 1; +} +.carousel-inner > .active, +.carousel-inner > .next, +.carousel-inner > .prev { + display: block; +} +.carousel-inner > .active { + left: 0; +} +.carousel-inner > .next, +.carousel-inner > .prev { + position: absolute; + top: 0; + width: 100%; +} +.carousel-inner > .next { + left: 100%; +} +.carousel-inner > .prev { + left: -100%; +} +.carousel-inner > .next.left, +.carousel-inner > .prev.right { + left: 0; +} +.carousel-inner > .active.left { + left: -100%; +} +.carousel-inner > .active.right { + left: 100%; +} +.carousel-control { + position: absolute; + top: 0; + left: 0; + bottom: 0; + width: 15%; + opacity: 0.5; + filter: alpha(opacity=50); + font-size: 20px; + color: #ffffff; + text-align: center; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); +} +.carousel-control.left { + background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%); + background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%); + background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1); +} +.carousel-control.right { + left: auto; + right: 0; + background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%); + background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%); + background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1); +} +.carousel-control:hover, +.carousel-control:focus { + outline: 0; + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} +.carousel-control .icon-prev, +.carousel-control .icon-next, +.carousel-control .glyphicon-chevron-left, +.carousel-control .glyphicon-chevron-right { + position: absolute; + top: 50%; + 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%; + margin-left: -30%; + padding-left: 0; + list-style: none; + text-align: center; +} +.carousel-indicators li { + display: inline-block; + width: 10px; + height: 10px; + margin: 1px; + text-indent: -999px; + border: 1px solid #ffffff; + border-radius: 10px; + cursor: pointer; + background-color: #000 \9; + background-color: rgba(0, 0, 0, 0); +} +.carousel-indicators .active { + margin: 0; + width: 12px; + height: 12px; + background-color: #ffffff; +} +.carousel-caption { + position: absolute; + left: 15%; + right: 15%; + bottom: 20px; + z-index: 10; + padding-top: 20px; + padding-bottom: 20px; + color: #ffffff; + text-align: center; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); +} +.carousel-caption .btn { + text-shadow: none; +} +@media screen and (min-width: 768px) { + .carousel-control .glyphicon-chevron-left, + .carousel-control .glyphicon-chevron-right, + .carousel-control .icon-prev, + .carousel-control .icon-next { + width: 30px; + height: 30px; + margin-top: -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 { + left: 20%; + right: 20%; + padding-bottom: 30px; + } + .carousel-indicators { + bottom: 20px; + } +} +.clearfix:before, +.clearfix:after, +.dl-horizontal dd:before, +.dl-horizontal dd:after, +.container:before, +.container:after, +.container-fluid:before, +.container-fluid:after, +.row:before, +.row:after, +.form-horizontal .form-group:before, +.form-horizontal .form-group:after, +.btn-toolbar:before, +.btn-toolbar:after, +.btn-group-vertical > .btn-group:before, +.btn-group-vertical > .btn-group:after, +.nav:before, +.nav:after, +.navbar:before, +.navbar:after, +.navbar-header:before, +.navbar-header:after, +.navbar-collapse:before, +.navbar-collapse:after, +.pager:before, +.pager:after, +.panel-body:before, +.panel-body:after, +.modal-footer:before, +.modal-footer:after { + content: " "; + display: table; +} +.clearfix:after, +.dl-horizontal dd:after, +.container:after, +.container-fluid:after, +.row:after, +.form-horizontal .form-group:after, +.btn-toolbar:after, +.btn-group-vertical > .btn-group:after, +.nav:after, +.navbar:after, +.navbar-header:after, +.navbar-collapse:after, +.pager:after, +.panel-body:after, +.modal-footer:after { + clear: both; +} +.center-block { + display: block; + margin-left: auto; + margin-right: auto; +} +.pull-right { + float: right !important; +} +.pull-left { + float: left !important; +} +.hide { + display: none !important; +} +.show { + display: block !important; +} +.invisible { + visibility: hidden; +} +.text-hide { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} +.hidden { + display: none !important; + visibility: hidden !important; +} +.affix { + position: fixed; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); +} +@-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; + } +} +.navbar-inverse .badge { + background-color: #fff; + color: #0072c6; +} +body { + -webkit-font-smoothing: antialiased; +} +.text-primary, +.text-primary:hover { + color: #0072c6; +} +.text-success, +.text-success:hover { + color: #3fb618; +} +.text-danger, +.text-danger:hover { + color: #ff0039; +} +.text-warning, +.text-warning:hover { + color: #ff7518; +} +.text-info, +.text-info:hover { + color: #9954bb; +} +table a:not(.btn), +.table a:not(.btn) { + text-decoration: underline; +} +table .success, +.table .success, +table .warning, +.table .warning, +table .danger, +.table .danger, +table .info, +.table .info { + color: #fff; +} +table .success a, +.table .success a, +table .warning a, +.table .warning a, +table .danger a, +.table .danger a, +table .info a, +.table .info a { + color: #fff; +} +.has-warning .help-block, +.has-warning .control-label, +.has-warning .form-control-feedback { + color: #ff7518; +} +.has-warning .form-control, +.has-warning .form-control:focus, +.has-warning .input-group-addon { + border: 1px solid #ff7518; +} +.has-error .help-block, +.has-error .control-label, +.has-error .form-control-feedback { + color: #ff0039; +} +.has-error .form-control, +.has-error .form-control:focus, +.has-error .input-group-addon { + border: 1px solid #ff0039; +} +.has-success .help-block, +.has-success .control-label, +.has-success .form-control-feedback { + color: #3fb618; +} +.has-success .form-control, +.has-success .form-control:focus, +.has-success .input-group-addon { + border: 1px solid #3fb618; +} +.nav-pills > li > a { + border-radius: 0; +} +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus { + background-image: none; +} +.close { + text-decoration: none; + text-shadow: none; + opacity: 0.4; +} +.close:hover, +.close:focus { + opacity: 1; +} +.alert { + border: none; +} +.alert .alert-link { + text-decoration: underline; + color: #fff; +} +.label { + border-radius: 0; +} +.progress { + height: 8px; + -webkit-box-shadow: none; + box-shadow: none; +} +.progress .progress-bar { + font-size: 8px; + line-height: 8px; +} +.panel-heading, +.panel-footer { + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.panel-default .close { + color: #333333; +} +.modal .close { + color: #333333; +} +.popover { + color: #333333; +} diff --git a/public/css/bootstrap.min.css b/public/css/bootstrap.min.css new file mode 100644 index 00000000..84c5494e --- /dev/null +++ b/public/css/bootstrap.min.css @@ -0,0 +1,7 @@ +/*! + * bootswatch v3.2.0 + * Homepage: http://bootswatch.com + * Copyright 2012-2014 Thomas Park + * Licensed under MIT + * Based on Bootstrap +*//*! normalize.css v3.0.1 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,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:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}@media print{*{text-shadow:none !important;color:#000 !important;background:transparent !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^="javascript:"]:after,a[href^="#"]: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}.table td,.table th{background-color:#fff !important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000 !important}.label{border:1px solid #000}.table{border-collapse:collapse !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:normal;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{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:"Segoe UI",Segoe,"Segoe WP",Calibri,Candara,Tahoma,Verdana,Arial,sans-serif;font-size:15px;line-height:1.42857143;color:#333333;background-color:#ffffff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#0072c6;text-decoration:none}a:hover,a:focus{color:#00467a;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;width:100% \9;max-width:100%;height:auto}.img-rounded{border-radius:0}.img-thumbnail{padding:4px;line-height:1.42857143;background-color:#ffffff;border:1px solid #dddddd;border-radius:0;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;width:100% \9;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:21px;margin-bottom:21px;border:0;border-top:1px solid #e6e6e6}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:"Segoe UI",Segoe,"Segoe WP",Calibri,Candara,Tahoma,Verdana,Arial,sans-serif;font-weight:300;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:#999999}h1,.h1,h2,.h2,h3,.h3{margin-top:21px;margin-bottom:10.5px}h1 small,.h1 small,h2 small,.h2 small,h3 small,.h3 small,h1 .small,.h1 .small,h2 .small,.h2 .small,h3 .small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:10.5px;margin-bottom:10.5px}h4 small,.h4 small,h5 small,.h5 small,h6 small,.h6 small,h4 .small,.h4 .small,h5 .small,.h5 .small,h6 .small,.h6 .small{font-size:75%}h1,.h1{font-size:39px}h2,.h2{font-size:32px}h3,.h3{font-size:26px}h4,.h4{font-size:19px}h5,.h5{font-size:15px}h6,.h6{font-size:13px}p{margin:0 0 10.5px}.lead{margin-bottom:21px;font-size:17px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:22.5px}}small,.small{font-size:86%}cite{font-style:normal}mark,.mark{background-color:#ff7518;padding:.2em}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#999999}.text-primary{color:#0072c6}a.text-primary:hover{color:#005593}.text-success{color:#ffffff}a.text-success:hover{color:#e6e6e6}.text-info{color:#ffffff}a.text-info:hover{color:#e6e6e6}.text-warning{color:#ffffff}a.text-warning:hover{color:#e6e6e6}.text-danger{color:#ffffff}a.text-danger:hover{color:#e6e6e6}.bg-primary{color:#fff;background-color:#0072c6}a.bg-primary:hover{background-color:#005593}.bg-success{background-color:#3fb618}a.bg-success:hover{background-color:#2f8912}.bg-info{background-color:#9954bb}a.bg-info:hover{background-color:#7e3f9d}.bg-warning{background-color:#ff7518}a.bg-warning:hover{background-color:#e45c00}.bg-danger{background-color:#ff0039}a.bg-danger:hover{background-color:#cc002e}.page-header{padding-bottom:9.5px;margin:42px 0 21px;border-bottom:1px solid #e6e6e6}ul,ol{margin-top:0;margin-bottom:10.5px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none;margin-left:-5px}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px}dl{margin-top:0;margin-bottom:21px}dt,dd{line-height:1.42857143}dt{font-weight:bold}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999999}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10.5px 21px;margin:0 0 21px;font-size:18.75px;border-left:5px solid #e6e6e6}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:#999999}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #e6e6e6;border-left:0;text-align:right}.blockquote-reverse footer:before,blockquote.pull-right footer:before,.blockquote-reverse small:before,blockquote.pull-right small:before,.blockquote-reverse .small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,blockquote.pull-right footer:after,.blockquote-reverse small:after,blockquote.pull-right small:after,.blockquote-reverse .small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}blockquote:before,blockquote:after{content:""}address{margin-bottom:21px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:0}kbd{padding:2px 4px;font-size:90%;color:#ffffff;background-color:#333333;border-radius:0;box-shadow:inset 0 -1px 0 rgba(0,0,0,0.25)}kbd kbd{padding:0;font-size:100%;box-shadow:none}pre{display:block;padding:10px;margin:0 0 10.5px;font-size:14px;line-height:1.42857143;word-break:break-all;word-wrap:break-word;color:#333333;background-color:#f5f5f5;border:1px solid #cccccc;border-radius:0}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.row{margin-left:-15px;margin-right:-15px}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0%}@media (min-width:768px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0%}}@media (min-width:992px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0%}}@media (min-width:1200px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0%}}table{background-color:transparent}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:21px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #dddddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #dddddd}.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 #dddddd}.table .table{background-color:#ffffff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #dddddd}.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 #dddddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*="col-"]{position:static;float:none;display:table-column}table td[class*="col-"],table th[class*="col-"]{position:static;float:none;display:table-cell}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#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:#3fb618}.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:#379f15}.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:#9954bb}.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:#8d46b0}.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:#ff7518}.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:#fe6600}.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:#ff0039}.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:#e60033}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15.75px;overflow-y:hidden;overflow-x:auto;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #dddddd;-webkit-overflow-scrolling:touch}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0;min-width:0}legend{display:block;width:100%;padding:0;margin-bottom:21px;font-size:22.5px;line-height:inherit;color:#333333;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:11px;font-size:15px;line-height:1.42857143;color:#333333}.form-control{display:block;width:100%;height:43px;padding:10px 18px;font-size:15px;line-height:1.42857143;color:#333333;background-color:#ffffff;background-image:none;border:1px solid #cccccc;border-radius:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border-color ease-in-out .15s,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,0.075),0 0 8px rgba(102,175,233,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6)}.form-control::-moz-placeholder{color:#999999;opacity:1}.form-control:-ms-input-placeholder{color:#999999}.form-control::-webkit-input-placeholder{color:#999999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#e6e6e6;opacity:1}textarea.form-control{height:auto}input[type="search"]{-webkit-appearance:none}input[type="date"],input[type="time"],input[type="datetime-local"],input[type="month"]{line-height:43px;line-height:1.42857143 \0}input[type="date"].input-sm,input[type="time"].input-sm,input[type="datetime-local"].input-sm,input[type="month"].input-sm{line-height:31px}input[type="date"].input-lg,input[type="time"].input-lg,input[type="datetime-local"].input-lg,input[type="month"].input-lg{line-height:64px}.form-group{margin-bottom:15px}.radio,.checkbox{position:relative;display:block;min-height:21px;margin-top:10px;margin-bottom:10px}.radio label,.checkbox label{padding-left:20px;margin-bottom:0;font-weight:normal;cursor:pointer}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{position:absolute;margin-left:-20px;margin-top:4px \9}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;vertical-align:middle;font-weight:normal;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"].disabled,input[type="checkbox"].disabled,fieldset[disabled] input[type="radio"],fieldset[disabled] input[type="checkbox"]{cursor:not-allowed}.radio-inline.disabled,.checkbox-inline.disabled,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.radio.disabled label,.checkbox.disabled label,fieldset[disabled] .radio label,fieldset[disabled] .checkbox label{cursor:not-allowed}.form-control-static{padding-top:11px;padding-bottom:11px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-left:0;padding-right:0}.input-sm,.form-horizontal .form-group-sm .form-control{height:31px;padding:5px 10px;font-size:13px;line-height:1.5;border-radius:0}select.input-sm{height:31px;line-height:31px}textarea.input-sm,select[multiple].input-sm{height:auto}.input-lg,.form-horizontal .form-group-lg .form-control{height:64px;padding:18px 30px;font-size:19px;line-height:1.33;border-radius:0}select.input-lg{height:64px;line-height:64px}textarea.input-lg,select[multiple].input-lg{height:auto}.has-feedback{position:relative}.has-feedback .form-control{padding-right:53.75px}.form-control-feedback{position:absolute;top:26px;right:0;z-index:2;display:block;width:43px;height:43px;line-height:43px;text-align:center}.input-lg+.form-control-feedback{width:64px;height:64px;line-height:64px}.input-sm+.form-control-feedback{width:31px;height:31px;line-height:31px}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline{color:#ffffff}.has-success .form-control{border-color:#ffffff;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-success .form-control:focus{border-color:#e6e6e6;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff}.has-success .input-group-addon{color:#ffffff;border-color:#ffffff;background-color:#3fb618}.has-success .form-control-feedback{color:#ffffff}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline{color:#ffffff}.has-warning .form-control{border-color:#ffffff;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-warning .form-control:focus{border-color:#e6e6e6;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff}.has-warning .input-group-addon{color:#ffffff;border-color:#ffffff;background-color:#ff7518}.has-warning .form-control-feedback{color:#ffffff}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline{color:#ffffff}.has-error .form-control{border-color:#ffffff;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-error .form-control:focus{border-color:#e6e6e6;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff}.has-error .input-group-addon{color:#ffffff;border-color:#ffffff;background-color:#ff0039}.has-error .form-control-feedback{color:#ffffff}.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 .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn,.form-inline .input-group .form-control{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .radio,.form-inline .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .radio label,.form-inline .checkbox label{padding-left:0}.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{margin-top:0;margin-bottom:0;padding-top:11px}.form-horizontal .radio,.form-horizontal .checkbox{min-height:32px}.form-horizontal .form-group{margin-left:-15px;margin-right:-15px}@media (min-width:768px){.form-horizontal .control-label{text-align:right;margin-bottom:0;padding-top:11px}}.form-horizontal .has-feedback .form-control-feedback{top:0;right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:24.94px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px}}.btn{display:inline-block;margin-bottom:0;font-weight:normal;text-align:center;vertical-align:middle;cursor:pointer;background-image:none;border:1px solid transparent;white-space:nowrap;padding:10px 18px;font-size:15px;line-height:1.42857143;border-radius:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.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{color:#ffffff;text-decoration:none}.btn:active,.btn.active{outline:0;background-image:none;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;pointer-events:none;opacity:0.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#ffffff;background-color:#222222;border-color:#222222}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{color:#ffffff;background-color:#090909;border-color:#040404}.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: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:#222222;border-color:#222222}.btn-default .badge{color:#222222;background-color:#ffffff}.btn-primary{color:#ffffff;background-color:#0072c6;border-color:#0072c6}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{color:#ffffff;background-color:#005593;border-color:#004f89}.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: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:#0072c6;border-color:#0072c6}.btn-primary .badge{color:#0072c6;background-color:#ffffff}.btn-success{color:#ffffff;background-color:#3fb618;border-color:#3fb618}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{color:#ffffff;background-color:#2f8912;border-color:#2c8011}.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: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:#3fb618;border-color:#3fb618}.btn-success .badge{color:#3fb618;background-color:#ffffff}.btn-info{color:#ffffff;background-color:#9954bb;border-color:#9954bb}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{color:#ffffff;background-color:#7e3f9d;border-color:#783c96}.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: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:#9954bb;border-color:#9954bb}.btn-info .badge{color:#9954bb;background-color:#ffffff}.btn-warning{color:#ffffff;background-color:#ff7518;border-color:#ff7518}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{color:#ffffff;background-color:#e45c00;border-color:#da5800}.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: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:#ff7518;border-color:#ff7518}.btn-warning .badge{color:#ff7518;background-color:#ffffff}.btn-danger{color:#ffffff;background-color:#ff0039;border-color:#ff0039}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{color:#ffffff;background-color:#cc002e;border-color:#c2002b}.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: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:#ff0039;border-color:#ff0039}.btn-danger .badge{color:#ff0039;background-color:#ffffff}.btn-link{color:#0072c6;font-weight:normal;cursor:pointer;border-radius:0}.btn-link,.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:#00467a;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:#999999;text-decoration:none}.btn-lg,.btn-group-lg>.btn{padding:18px 30px;font-size:19px;line-height:1.33;border-radius:0}.btn-sm,.btn-group-sm>.btn{padding:5px 10px;font-size:13px;line-height:1.5;border-radius:0}.btn-xs,.btn-group-xs>.btn{padding:1px 5px;font-size:13px;line-height:1.5;border-radius:0}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height 0.35s ease;-o-transition:height 0.35s ease;transition:height 0.35s ease}.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;list-style:none;font-size:15px;text-align:left;background-color:#ffffff;border:1px solid #cccccc;border:1px solid rgba(0,0,0,0.15);border-radius:0;-webkit-box-shadow:0 6px 12px rgba(0,0,0,0.175);box-shadow:0 6px 12px rgba(0,0,0,0.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9.5px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.42857143;color:#333333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{text-decoration:none;color:#ffffff;background-color:#0072c6}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#ffffff;text-decoration:none;outline:0;background-color:#0072c6}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);cursor:not-allowed}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{left:auto;right:0}.dropdown-menu-left{left:0;right:auto}.dropdown-header{display:block;padding:3px 20px;font-size:13px;line-height:1.42857143;color:#999999;white-space:nowrap}.dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media (min-width:768px){.navbar-right .dropdown-menu{left:auto;right:0}.navbar-right .dropdown-menu-left{left:0;right:auto}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:0}.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-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-left:12px;padding-right:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-bottom-left-radius:0;border-top-right-radius:0;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{float:none;display:table-cell;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle="buttons"]>.btn>input[type="radio"],[data-toggle="buttons"]>.btn>input[type="checkbox"]{position:absolute;z-index:-1;opacity:0;filter:alpha(opacity=0)}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*="col-"]{float:none;padding-left:0;padding-right:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:64px;padding:18px 30px;font-size:19px;line-height:1.33;border-radius:0}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:64px;line-height:64px}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:31px;padding:5px 10px;font-size:13px;line-height:1.5;border-radius:0}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:31px;line-height:31px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn,select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:10px 18px;font-size:15px;font-weight:normal;line-height:1;color:#333333;text-align:center;background-color:#e6e6e6;border:1px solid #cccccc;border-radius:0}.input-group-addon.input-sm{padding:5px 10px;font-size:13px;border-radius:0}.input-group-addon.input-lg{padding:18px 30px;font-size:19px;border-radius:0}.input-group-addon input[type="radio"],.input-group-addon input[type="checkbox"]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:last-child>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:0;border-top-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:first-child>.btn-group:not(:first-child)>.btn{border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:hover,.input-group-btn>.btn:focus,.input-group-btn>.btn:active{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-left:-1px}.nav{margin-bottom:0;padding-left:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#e6e6e6}.nav>li.disabled>a{color:#999999}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#999999;text-decoration:none;background-color:transparent;cursor:not-allowed}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#e6e6e6;border-color:#0072c6}.nav .nav-divider{height:1px;margin:9.5px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #dddddd}.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:0 0 0 0}.nav-tabs>li>a:hover{border-color:#e6e6e6 #e6e6e6 #dddddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555555;background-color:#ffffff;border:1px solid #dddddd;border-bottom-color:transparent;cursor:default}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #dddddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #dddddd;border-radius:0 0 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#ffffff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:0}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#ffffff;background-color:#0072c6}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #dddddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #dddddd;border-radius:0 0 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#ffffff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:21px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:0}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{overflow-x:visible;padding-right:15px;padding-left:15px;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);-webkit-overflow-scrolling:touch}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block !important;height:auto !important;padding-bottom:0;overflow:visible !important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{padding-left:0;padding-right:0}}.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:340px}@media (max-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;-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0)}@media (min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:14.5px 15px;font-size:19px;line-height:21px;height:50px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;margin-right:15px;padding:9px 10px;margin-top:8px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:0}.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.25px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:21px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:21px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:14.5px;padding-bottom:14.5px}.navbar-nav.navbar-right:last-child{margin-right:-15px}}@media (min-width:768px){.navbar-left{float:left !important}.navbar-right{float:right !important}}.navbar-form{margin-left:-15px;margin-right:-15px;padding:10px 15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);margin-top:3.5px;margin-bottom:3.5px}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .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}}@media (min-width:768px){.navbar-form{width:auto;border:0;margin-left:0;margin-right:0;padding-top:0;padding-bottom:0;-webkit-box-shadow:none;box-shadow:none}.navbar-form.navbar-right:last-child{margin-right:-15px}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:3.5px;margin-bottom:3.5px}.navbar-btn.btn-sm{margin-top:9.5px;margin-bottom:9.5px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:14.5px;margin-bottom:14.5px}@media (min-width:768px){.navbar-text{float:left;margin-left:15px;margin-right:15px}.navbar-text.navbar-right:last-child{margin-right:0}}.navbar-default{background-color:#222222;border-color:#121212}.navbar-default .navbar-brand{color:#ffffff}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#ffffff;background-color:none}.navbar-default .navbar-text{color:#ffffff}.navbar-default .navbar-nav>li>a{color:#ffffff}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#ffffff;background-color:#090909}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#ffffff;background-color:#090909}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#cccccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:transparent}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#090909}.navbar-default .navbar-toggle .icon-bar{background-color:#ffffff}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#121212}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{background-color:#090909;color:#ffffff}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#ffffff}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#ffffff;background-color:#090909}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#ffffff;background-color:#090909}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#cccccc;background-color:transparent}}.navbar-default .navbar-link{color:#ffffff}.navbar-default .navbar-link:hover{color:#ffffff}.navbar-default .btn-link{color:#ffffff}.navbar-default .btn-link:hover,.navbar-default .btn-link:focus{color:#ffffff}.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:hover,.navbar-default .btn-link[disabled]:focus,fieldset[disabled] .navbar-default .btn-link:focus{color:#cccccc}.navbar-inverse{background-color:#0072c6;border-color:#005593}.navbar-inverse .navbar-brand{color:#ffffff}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#ffffff;background-color:none}.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:#ffffff;background-color:#005593}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#ffffff;background-color:#005593}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#ffffff;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:transparent}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#005593}.navbar-inverse .navbar-toggle .icon-bar{background-color:#ffffff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#005da2}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{background-color:#005593;color:#ffffff}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#005593}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#005593}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#ffffff}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#ffffff;background-color:#005593}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#ffffff;background-color:#005593}.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:#ffffff;background-color:transparent}}.navbar-inverse .navbar-link{color:#ffffff}.navbar-inverse .navbar-link:hover{color:#ffffff}.navbar-inverse .btn-link{color:#ffffff}.navbar-inverse .btn-link:hover,.navbar-inverse .btn-link:focus{color:#ffffff}.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:#ffffff}.breadcrumb{padding:8px 15px;margin-bottom:21px;list-style:none;background-color:#f5f5f5;border-radius:0}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{content:"/\00a0";padding:0 5px;color:#cccccc}.breadcrumb>.active{color:#999999}.pagination{display:inline-block;padding-left:0;margin:21px 0;border-radius:0}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:10px 18px;line-height:1.42857143;text-decoration:none;color:#0072c6;background-color:#ffffff;border:1px solid #dddddd;margin-left:-1px}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:0;border-top-left-radius:0}.pagination>li:last-child>a,.pagination>li:last-child>span{border-bottom-right-radius:0;border-top-right-radius:0}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{color:#00467a;background-color:#e6e6e6;border-color:#dddddd}.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:#999999;background-color:#f5f5f5;border-color:#dddddd;cursor:default}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#999999;background-color:#ffffff;border-color:#dddddd;cursor:not-allowed}.pagination-lg>li>a,.pagination-lg>li>span{padding:18px 30px;font-size:19px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:0;border-top-left-radius:0}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-bottom-right-radius:0;border-top-right-radius:0}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:13px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:0;border-top-left-radius:0}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-bottom-right-radius:0;border-top-right-radius:0}.pager{padding-left:0;margin:21px 0;list-style:none;text-align:center}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#ffffff;border:1px solid #dddddd;border-radius:0}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#e6e6e6}.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:#999999;background-color:#ffffff;cursor:not-allowed}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#ffffff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:hover,a.label:focus{color:#ffffff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#222222}.label-default[href]:hover,.label-default[href]:focus{background-color:#090909}.label-primary{background-color:#0072c6}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#005593}.label-success{background-color:#3fb618}.label-success[href]:hover,.label-success[href]:focus{background-color:#2f8912}.label-info{background-color:#9954bb}.label-info[href]:hover,.label-info[href]:focus{background-color:#7e3f9d}.label-warning{background-color:#ff7518}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#e45c00}.label-danger{background-color:#ff0039}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#cc002e}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:13px;font-weight:bold;color:#ffffff;line-height:1;vertical-align:baseline;white-space:nowrap;text-align:center;background-color:#0072c6;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:#ffffff;text-decoration:none;cursor:pointer}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#0072c6;background-color:#ffffff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;color:inherit;background-color:#e6e6e6}.jumbotron h1,.jumbotron .h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:23px;font-weight:200}.jumbotron>hr{border-top-color:#cccccc}.container .jumbotron{border-radius:0}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-left:60px;padding-right:60px}.jumbotron h1,.jumbotron .h1{font-size:67.5px}}.thumbnail{display:block;padding:4px;margin-bottom:21px;line-height:1.42857143;background-color:#ffffff;border:1px solid #dddddd;border-radius:0;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img,.thumbnail a>img{margin-left:auto;margin-right:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#0072c6}.thumbnail .caption{padding:9px;color:#333333}.alert{padding:15px;margin-bottom:21px;border:1px solid transparent;border-radius:0}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{background-color:#3fb618;border-color:#4e9f15;color:#ffffff}.alert-success hr{border-top-color:#438912}.alert-success .alert-link{color:#e6e6e6}.alert-info{background-color:#9954bb;border-color:#7643a8;color:#ffffff}.alert-info hr{border-top-color:#693c96}.alert-info .alert-link{color:#e6e6e6}.alert-warning{background-color:#ff7518;border-color:#ff4309;color:#ffffff}.alert-warning hr{border-top-color:#ee3800}.alert-warning .alert-link{color:#e6e6e6}.alert-danger{background-color:#ff0039;border-color:#f0005e;color:#ffffff}.alert-danger hr{border-top-color:#d60054}.alert-danger .alert-link{color:#e6e6e6}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{overflow:hidden;height:21px;margin-bottom:21px;background-color:#cccccc;border-radius:0;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress-bar{float:left;width:0%;height:100%;font-size:13px;line-height:21px;color:#ffffff;text-align:center;background-color:#0072c6;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width 0.6s ease;-o-transition:width 0.6s ease;transition:width 0.6s ease}.progress-striped .progress-bar,.progress-bar-striped{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);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[aria-valuenow="1"],.progress-bar[aria-valuenow="2"]{min-width:30px}.progress-bar[aria-valuenow="0"]{color:#999999;min-width:30px;background-color:transparent;background-image:none;box-shadow:none}.progress-bar-success{background-color:#3fb618}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-info{background-color:#9954bb}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-warning{background-color:#ff7518}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-danger{background-color:#ff0039}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{margin-bottom:20px;padding-left:0}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#ffffff;border:1px solid #dddddd}.list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555555}a.list-group-item .list-group-item-heading{color:#333333}a.list-group-item:hover,a.list-group-item:focus{text-decoration:none;color:#555555;background-color:#f5f5f5}.list-group-item.disabled,.list-group-item.disabled:hover,.list-group-item.disabled:focus{background-color:#e6e6e6;color:#999999}.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:#999999}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{z-index:2;color:#ffffff;background-color:#0072c6;border-color:#0072c6}.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:#93d1ff}.list-group-item-success{color:#ffffff;background-color:#3fb618}a.list-group-item-success{color:#ffffff}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:hover,a.list-group-item-success:focus{color:#ffffff;background-color:#379f15}a.list-group-item-success.active,a.list-group-item-success.active:hover,a.list-group-item-success.active:focus{color:#fff;background-color:#ffffff;border-color:#ffffff}.list-group-item-info{color:#ffffff;background-color:#9954bb}a.list-group-item-info{color:#ffffff}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:hover,a.list-group-item-info:focus{color:#ffffff;background-color:#8d46b0}a.list-group-item-info.active,a.list-group-item-info.active:hover,a.list-group-item-info.active:focus{color:#fff;background-color:#ffffff;border-color:#ffffff}.list-group-item-warning{color:#ffffff;background-color:#ff7518}a.list-group-item-warning{color:#ffffff}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:hover,a.list-group-item-warning:focus{color:#ffffff;background-color:#fe6600}a.list-group-item-warning.active,a.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus{color:#fff;background-color:#ffffff;border-color:#ffffff}.list-group-item-danger{color:#ffffff;background-color:#ff0039}a.list-group-item-danger{color:#ffffff}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:hover,a.list-group-item-danger:focus{color:#ffffff;background-color:#e60033}a.list-group-item-danger.active,a.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus{color:#fff;background-color:#ffffff;border-color:#ffffff}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:21px;background-color:#ffffff;border:1px solid transparent;border-radius:0;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:-1;border-top-left-radius:-1}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:17px;color:inherit}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #dddddd;border-bottom-right-radius:-1;border-bottom-left-radius:-1}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-right-radius:-1;border-top-left-radius:-1}.panel>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:-1;border-bottom-left-radius:-1}.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:first-child,.panel>.table-responsive:first-child>.table:first-child{border-top-right-radius:-1;border-top-left-radius:-1}.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:-1}.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:-1}.panel>.table:last-child,.panel>.table-responsive:last-child>.table:last-child{border-bottom-right-radius:-1;border-bottom-left-radius:-1}.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:-1}.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:-1}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive{border-top:1px solid #dddddd}.panel>.table>tbody:first-child>tr:first-child th,.panel>.table>tbody:first-child>tr:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{border:0;margin-bottom:0}.panel-group{margin-bottom:21px}.panel-group .panel{margin-bottom:0;border-radius:0}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #dddddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #dddddd}.panel-default{border-color:#dddddd}.panel-default>.panel-heading{color:#333333;background-color:#f5f5f5;border-color:#dddddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#dddddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#dddddd}.panel-primary{border-color:#0072c6}.panel-primary>.panel-heading{color:#ffffff;background-color:#0072c6;border-color:#0072c6}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#0072c6}.panel-primary>.panel-heading .badge{color:#0072c6;background-color:#ffffff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#0072c6}.panel-success{border-color:#4e9f15}.panel-success>.panel-heading{color:#ffffff;background-color:#3fb618;border-color:#4e9f15}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#4e9f15}.panel-success>.panel-heading .badge{color:#3fb618;background-color:#ffffff}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#4e9f15}.panel-info{border-color:#7643a8}.panel-info>.panel-heading{color:#ffffff;background-color:#9954bb;border-color:#7643a8}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#7643a8}.panel-info>.panel-heading .badge{color:#9954bb;background-color:#ffffff}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#7643a8}.panel-warning{border-color:#ff4309}.panel-warning>.panel-heading{color:#ffffff;background-color:#ff7518;border-color:#ff4309}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ff4309}.panel-warning>.panel-heading .badge{color:#ff7518;background-color:#ffffff}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ff4309}.panel-danger{border-color:#f0005e}.panel-danger>.panel-heading{color:#ffffff;background-color:#ff0039;border-color:#f0005e}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#f0005e}.panel-danger>.panel-heading .badge{color:#ff0039;background-color:#ffffff}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#f0005e}.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{position:absolute;top:0;left:0;bottom:0;height:100%;width: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:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-lg{padding:24px;border-radius:0}.well-sm{padding:9px;border-radius:0}.close{float:right;font-size:22.5px;font-weight:bold;line-height:1;color:#ffffff;text-shadow:0 1px 0 #ffffff;opacity:0.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#ffffff;text-decoration:none;cursor:pointer;opacity:0.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{display:none;overflow:hidden;position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transform:translate3d(0, -25%, 0);transform:translate3d(0, -25%, 0);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#ffffff;border:1px solid #999999;border:1px solid transparent;border-radius:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5);box-shadow:0 3px 9px rgba(0,0,0,0.5);background-clip:padding-box;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:0.5;filter:alpha(opacity=50)}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5;min-height:16.42857143px}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:20px}.modal-footer{padding:20px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;visibility:visible;font-size:13px;line-height:1.4;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:0.9;filter:alpha(opacity=90)}.tooltip.top{margin-top:-3px;padding:5px 0}.tooltip.right{margin-left:3px;padding:0 5px}.tooltip.bottom{margin-top:3px;padding:5px 0}.tooltip.left{margin-left:-3px;padding:0 5px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#ffffff;text-align:center;text-decoration:none;background-color:rgba(0,0,0,0.9);border-radius:0}.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:rgba(0,0,0,0.9)}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-width:5px 5px 0;border-top-color:rgba(0,0,0,0.9)}.tooltip.top-right .tooltip-arrow{bottom:0;right:5px;border-width:5px 5px 0;border-top-color:rgba(0,0,0,0.9)}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:rgba(0,0,0,0.9)}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:rgba(0,0,0,0.9)}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:rgba(0,0,0,0.9)}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-width:0 5px 5px;border-bottom-color:rgba(0,0,0,0.9)}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-width:0 5px 5px;border-bottom-color:rgba(0,0,0,0.9)}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;text-align:left;background-color:#ffffff;background-clip:padding-box;border:1px solid #cccccc;border:1px solid rgba(0,0,0,0.2);border-radius:0;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);white-space:normal}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{margin:0;padding:8px 14px;font-size:15px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:-1 -1 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{border-width:10px;content:""}.popover.top>.arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999999;border-top-color:rgba(0,0,0,0.25);bottom:-11px}.popover.top>.arrow:after{content:" ";bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#ffffff}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999999;border-right-color:rgba(0,0,0,0.25)}.popover.right>.arrow:after{content:" ";left:1px;bottom:-10px;border-left-width:0;border-right-color:#ffffff}.popover.bottom>.arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999999;border-bottom-color:rgba(0,0,0,0.25);top:-11px}.popover.bottom>.arrow:after{content:" ";top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#ffffff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999999;border-left-color:rgba(0,0,0,0.25)}.popover.left>.arrow:after{content:" ";right:1px;border-right-width:0;border-left-color:#ffffff;bottom:-10px}.carousel{position:relative}.carousel-inner{position:relative;overflow:hidden;width:100%}.carousel-inner>.item{display:none;position:relative;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;left:0;bottom:0;width:15%;opacity:0.5;filter:alpha(opacity=50);font-size:20px;color:#ffffff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-control.left{background-image:-webkit-linear-gradient(left, rgba(0,0,0,0.5) 0, rgba(0,0,0,0.0001) 100%);background-image:-o-linear-gradient(left, rgba(0,0,0,0.5) 0, rgba(0,0,0,0.0001) 100%);background-image:linear-gradient(to right, rgba(0,0,0,0.5) 0, rgba(0,0,0,0.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1)}.carousel-control.right{left:auto;right:0;background-image:-webkit-linear-gradient(left, rgba(0,0,0,0.0001) 0, rgba(0,0,0,0.5) 100%);background-image:-o-linear-gradient(left, rgba(0,0,0,0.0001) 0, rgba(0,0,0,0.5) 100%);background-image:linear-gradient(to right, rgba(0,0,0,0.0001) 0, rgba(0,0,0,0.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1)}.carousel-control:hover,.carousel-control:focus{outline:0;color:#ffffff;text-decoration:none;opacity:0.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;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%;margin-left:-30%;padding-left:0;list-style:none;text-align:center}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;border:1px solid #ffffff;border-radius:10px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0)}.carousel-indicators .active{margin:0;width:12px;height:12px;background-color:#ffffff}.carousel-caption{position:absolute;left:15%;right:15%;bottom:20px;z-index:10;padding-top:20px;padding-bottom:20px;color:#ffffff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-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{left:20%;right:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after,.dl-horizontal dd:before,.dl-horizontal dd:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after,.form-horizontal .form-group:before,.form-horizontal .form-group:after,.btn-toolbar:before,.btn-toolbar:after,.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after,.nav:before,.nav:after,.navbar:before,.navbar:after,.navbar-header:before,.navbar-header:after,.navbar-collapse:before,.navbar-collapse:after,.pager:before,.pager:after,.panel-body:before,.panel-body:after,.modal-footer:before,.modal-footer:after{content:" ";display:table}.clearfix:after,.dl-horizontal dd:after,.container:after,.container-fluid:after,.row:after,.form-horizontal .form-group:after,.btn-toolbar:after,.btn-group-vertical>.btn-group:after,.nav:after,.navbar:after,.navbar-header:after,.navbar-collapse:after,.pager:after,.panel-body:after,.modal-footer:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right !important}.pull-left{float:left !important}.hide{display:none !important}.show{display:block !important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none !important;visibility:hidden !important}.affix{position:fixed;-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0)}@-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}}.navbar-inverse .badge{background-color:#fff;color:#0072c6}body{-webkit-font-smoothing:antialiased}.text-primary,.text-primary:hover{color:#0072c6}.text-success,.text-success:hover{color:#3fb618}.text-danger,.text-danger:hover{color:#ff0039}.text-warning,.text-warning:hover{color:#ff7518}.text-info,.text-info:hover{color:#9954bb}table a:not(.btn),.table a:not(.btn){text-decoration:underline}table .success,.table .success,table .warning,.table .warning,table .danger,.table .danger,table .info,.table .info{color:#fff}table .success a,.table .success a,table .warning a,.table .warning a,table .danger a,.table .danger a,table .info a,.table .info a{color:#fff}.has-warning .help-block,.has-warning .control-label,.has-warning .form-control-feedback{color:#ff7518}.has-warning .form-control,.has-warning .form-control:focus,.has-warning .input-group-addon{border:1px solid #ff7518}.has-error .help-block,.has-error .control-label,.has-error .form-control-feedback{color:#ff0039}.has-error .form-control,.has-error .form-control:focus,.has-error .input-group-addon{border:1px solid #ff0039}.has-success .help-block,.has-success .control-label,.has-success .form-control-feedback{color:#3fb618}.has-success .form-control,.has-success .form-control:focus,.has-success .input-group-addon{border:1px solid #3fb618}.nav-pills>li>a{border-radius:0}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-image:none}.close{text-decoration:none;text-shadow:none;opacity:0.4}.close:hover,.close:focus{opacity:1}.alert{border:none}.alert .alert-link{text-decoration:underline;color:#fff}.label{border-radius:0}.progress{height:8px;-webkit-box-shadow:none;box-shadow:none}.progress .progress-bar{font-size:8px;line-height:8px}.panel-heading,.panel-footer{border-top-right-radius:0;border-top-left-radius:0}.panel-default .close{color:#333333}.modal .close{color:#333333}.popover{color:#333333} \ No newline at end of file diff --git a/public/css/oss.css b/public/css/oss.css new file mode 100644 index 00000000..b4359535 --- /dev/null +++ b/public/css/oss.css @@ -0,0 +1,548 @@ +/* +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +*/ + +body { + position: relative; +} + +div#wiki-toolbar { + margin-top:12px; +} + +.general-margin-left { + margin-left:12px; +} + +div#content { + margin-top:24px; +} + +.container-pad { + margin-top:20px; +} + +.person-tile { + display: inline-block; + padding: 4px; + margin: 6px; +} + +.capitalize { + text-transform:capitalize; +} + +.breadcrumb { + background-color: #fff; + padding-left: 0; +} + +.a-unstyled { color: #333; } +.a-unstyled:link { color: #333; } +.a-unstyled:visited { color: #333; } +.a-unstyled:hover { color: #000; text-decoration: none; } +.a-unstyled:active { color: #333; } + +/* first row navigation styling */ +.first-row-nav { + background-color: #fff; + color: #111; + border: 0; +} +.first-row-nav a.navbar-brand { + color: #333; +} +.first-row-nav a.navbar-brand:hover { + color: #444; +} +.first-row-nav .navbar-nav > li > a { + color: #555; +} +.first-row-nav .navbar-nav > li > a:hover, +.first-row-nav .navbar-nav > .active > a, +.first-row-nav .navbar-nav > .active > a:hover { + color: #000; + background-color: #fff; +} +.first-row-nav .navbar-toggle .icon-bar { + background-color: #555; +} +.first-row-nav .navbar-header .navbar-toggle { + border-color: #fff; +} +.first-row-nav .navbar-header .navbar-toggle:hover, +.first-row-nav .navbar-header .navbar-toggle:focus { + background-color: #f9f9f9; + border-color: #f9f9f9; +} + +/* second row sub navigation for the portal */ +.navbar.second-row-nav { + margin-top: -21px; + padding-bottom: 2px; + padding-top: 2px; +} +.second-row-nav { + background-color: #eee; + color: #111; + border: 0; +} +.second-row-nav a.navbar-brand { + color: #333; +} +.second-row-nav a.navbar-brand:hover { + color: #444; +} +.second-row-nav .navbar-nav > li > a { + color: #555; +} +.second-row-nav .navbar-nav > li > a:hover, +.second-row-nav .navbar-nav > .active > a, +.second-row-nav .navbar-nav > .active > a:hover { + color: #000; + background-color: #fff; +} +.second-row-nav .navbar-toggle .icon-bar { + background-color: #555; +} +.second-row-nav .navbar-header .navbar-toggle { + border-color: #fff; +} +.second-row-nav .navbar-header .navbar-toggle:hover, +.second-row-nav .navbar-header .navbar-toggle:focus { + background-color: #f9f9f9; + border-color: #f9f9f9; +} + +.btn-huge { + margin:24px 0px; + padding:24px 36px; + font-size:32pt; +} + +h1.huge { + font-size: 68px; +} + +h2 strong { + font-family: "Segoe UI Semibold", Segoe, "Segoe WP", Calibri, Candara, Tahoma, Verdana, Arial, sans-serif; + font-weight: normal; +} + +/* custom color button for a more muted appearance */ +.btn-default { + color:#fff; + background-color: #444; + border-color: #444; +} + +.btn-muted { + color:#333; + background-color: #bbb; + border-color: #bbb; +} +.btn-muted:hover, +.btn-muted:focus, +.btn-muted:active, +.btn-muted.active, +.open > .dropdown-toggle.btn-default { + color: #000; + background-color: #999; + border-color: #999; +} + +.btn-muted-more { + color:#777; + background-color: #ddd; + border-color: #ddd; +} +.btn-muted-more:hover, +.btn-muted-more:focus, +.btn-muted-more:active, +.btn-muted-more.active, +.open > .dropdown-toggle.btn-default { + color: #000; + background-color: #ccc; + border-color: #ccc; +} + +.btn-white { + color:#333; + background-color: #fff; + border-color: #fff; +} +.btn-white:hover, +.btnd-white:focus, +.btnd-white:active, +.btnd-white.active, +.open > .dropdown-toggle.btn-default { + color: #fff; + background-color: #0078d7; + border-color: #0078d7; +} + +/* wiki editing tools */ +textarea#editor-body { + margin-top: 24px; + margin-bottom: 24px; + width: 100%; + min-height: 480px; + font-family: Consolas, Courier, "Courier New"; +} + +/* general styling for the wiki */ +footer { + margin-top: 36px; + margin-bottom: 24px; +} + +code { + color: #333; +} + +.alert-gray { + background-color: #eee; + border-color: #ddd; + color: #777; +} +.alert-gray hr { + border-top-color: #999; +} +.alert-gray .alert-link { + color: #999; +} + +input#search-box { + padding-top: 1px; + padding-bottom: 1px; + height: 36px; + margin-top: 4px; + max-width:160px; +} + +.sevenpercent { + width:7%; +} +.fivepercent { + width:5%; +} +.tenpercent { + width:10%; +} +.fifteenpercent { + width:15%; +} +.twentypercent { + width:20%; +} +.twentyfivepercent { + width:25%; +} +.thirtypercent { + width:30%; +} + +div.alert { + margin-bottom: 0; + padding-bottom: 24px; +} + +div.alerts { + margin: 0; + padding-bottom: 20px; +} + +/* theme colors and components */ +div.metro-box { + position:relative; + margin:0px; + width:100%; +} +.metro-box a { + padding:1.4em 25px; + display: inline-block; + color:#fff; + font-size: .9em; + position:relative; + width:100%; +} +.metro-box a h3 { + color: #fff; +} +.metro-box a p { + color: #fff; +} +.metro-box a:hover { + text-decoration: none; +} + +div.link-box { + position:relative; + margin:0px; + width:100%; +} +.link-box a { + padding:.4em 25px; + display: inline-block; + position:relative; + width:100%; +} +.link-box a:hover { + text-decoration: none; + background-color: #efefef; +} +.link-box p.lead { + color: #444; +} + +/* Brand box coloring v1 */ +.metro-blue { + background:#0072C6; +} +.metro-purple { + background:#68217A; +} +.metro-gray { + background:#666; +} +.metro-orange { + background:#fa6800; +} + +/* Core brand-related colors */ +.ms-yellow { + background:#ffb900; +} +.ms-orange { + background:#d83b01; +} +.ms-red { + background:#e81123; +} +.ms-magenta { + background:#b4009e; +} +.ms-purple { + background:#5c2d91; +} +.ms-blue { + background:#0078d7; +} +.ms-teal { + background:#008272; +} +.ms-green { + background:#107c10; +} +/* Additional brand colors */ +.ms-light-orange { + background:#ff8c00; +} +.ms-light-magenta { + background:#e3008c; +} +.ms-light-purple { + background:#b4a0ff; +} +.ms-light-blue { + background:#00bcf2; +} +.ms-light-teal { + background:#00b294; +} +.ms-light-green { + background:#bad80a; +} +.ms-light-yellow { + background:#fff100; +} +.ms-dark-red { + background:#a80000; +} +.ms-dark-magenta { + background:#5c005c; +} +.ms-dark-purple { + background:#32145a; +} +.ms-mid-blue { + background:#002050; +} +.ms-dark-blue { + background:#002050; +} +.ms-dark-teal { + background:#004b50; +} +.ms-dark-green { + background:#004b1c; +} +.ms-white { + background:#fff; +} +.ms-light-gray { + background:#d2d2d2; +} +.ms-mid-gray { + background:#737373; +} +.ms-dark-gray { + background:#505050; +} +.ms-rich-black { + background:#000; +} +/* lighter boxes need dark foreground colors */ +.ms-yellow a, .ms-light-orange a, .ms-light-magenta a, .ms-light-purple a, .ms-light-blue a, +.ms-light-teal a, .ms-light-green a, .ms-light-yellow a, .ms-white a, .ms-light-gray a { + color:#000; +} +.ms-yellow a h3, .ms-light-orange a h3, .ms-light-magenta a h3, .ms-light-purple a h3, .ms-light-blue a h3, +.ms-light-teal a h3, .ms-light-green a h3, .ms-light-yellow a h3, .ms-white a h3, .ms-light-gray a h3 { + color:#000; +} +.ms-yellow a p, .ms-light-orange a p, .ms-light-magenta a p, .ms-light-purple a p, .ms-light-blue a p, +.ms-light-teal a p, .ms-light-green a p, .ms-light-yellow a p, .ms-white a p, .ms-light-gray a p { + color:#000; +} + +/* table width modifiers */ +th.w-25, td.w-25 { + width:30%; +} +th.w-20, td.w-20 { + width:20%; +} +td.w-15, th.w-15 { + width:15%; +} +td.w-10, th.w-10 { + width:10%; +} + +/* By default it's not affixed in mobile views, so undo that */ +.wiki-sidebar.affix { + position: static; +} +@media (min-width: 768px) { + .wiki-sidebar { + padding-left: 20px; + } +} + +/* First level of nav */ +.wiki-sidenav { + margin-top: 20px; + margin-bottom: 20px; +} + +/* All levels of nav */ +.wiki-sidebar .nav > li > a { + display: block; + padding: 4px 20px; + font-size: 13px; + font-weight: 500; + color: #999; +} +.wiki-sidebar .nav > li > a:hover, +.wiki-sidebar .nav > li > a:focus { + padding-left: 19px; + color: #0072C6; + text-decoration: none; + background-color: transparent; + border-left: 1px solid #0072C6; +} +.wiki-sidebar .nav > .active > a, +.wiki-sidebar .nav > .active:hover > a, +.wiki-sidebar .nav > .active:focus > a { + padding-left: 18px; + font-weight: bold; + color: #0072C6; + background-color: transparent; + border-left: 2px solid #0072C6; +} + +/* Nav: second level (shown on .active) */ +.wiki-sidebar .nav .nav { + display: none; /* Hide by default, but at >768px, show it */ + padding-bottom: 10px; +} +.wiki-sidebar .nav .nav > li > a { + padding-top: 1px; + padding-bottom: 1px; + padding-left: 30px; + font-size: 12px; + font-weight: normal; +} +.wiki-sidebar .nav .nav > li > a:hover, +.wiki-sidebar .nav .nav > li > a:focus { + padding-left: 29px; +} +.wiki-sidebar .nav .nav > .active > a, +.wiki-sidebar .nav .nav > .active:hover > a, +.wiki-sidebar .nav .nav > .active:focus > a { + padding-left: 28px; + font-weight: 500; +} + +/* Back to top (hidden on mobile) */ +.back-to-top { + display: none; + padding: 4px 10px; + margin-top: 10px; + margin-left: 10px; + font-size: 12px; + font-weight: 500; + color: #999; +} +.back-to-top:hover { + color: #0072C6; + text-decoration: none; +} + +@media (min-width: 768px) { + .back-to-top { + display: block; + } +} + +/* Show and affix the side nav when space allows it */ +@media (min-width: 992px) { + .wiki-sidebar .nav > .active > ul { + display: block; + } + /* Widen the fixed sidebar */ + .wiki-sidebar.affix, + .wiki-sidebar.affix-bottom { + width: 213px; + } + .wiki-sidebar.affix { + position: fixed; /* Undo the static from mobile first approach */ + top: 20px; + } + .wiki-sidebar.affix-bottom { + position: absolute; /* Undo the static from mobile first approach */ + } + .wiki-sidebar.affix-bottom .wiki-sidenav, + .wiki-sidebar.affix .wiki-sidenav { + margin-top: 0; + margin-bottom: 0; + } +} +@media (min-width: 1200px) { + /* Widen the fixed sidebar again */ + .wiki-sidebar.affix-bottom, + .wiki-sidebar.affix { + width: 263px; + } +} + +/* IE10 bugs */ +@-webkit-viewport { width: device-width; } +@-moz-viewport { width: device-width; } +@-ms-viewport { width: device-width; } +@-o-viewport { width: device-width; } +@viewport { width: device-width; } diff --git a/public/favicon-144.png b/public/favicon-144.png new file mode 100644 index 00000000..05a3c2ee Binary files /dev/null and b/public/favicon-144.png differ diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 00000000..25518e0c Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/fonts/BOOTSTRAP-LICENSE.txt b/public/fonts/BOOTSTRAP-LICENSE.txt new file mode 100644 index 00000000..5a3367c6 --- /dev/null +++ b/public/fonts/BOOTSTRAP-LICENSE.txt @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2011-2015 Twitter, Inc + +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/public/fonts/glyphicons-halflings-regular.eot b/public/fonts/glyphicons-halflings-regular.eot new file mode 100644 index 00000000..4a4ca865 Binary files /dev/null and b/public/fonts/glyphicons-halflings-regular.eot differ diff --git a/public/fonts/glyphicons-halflings-regular.svg b/public/fonts/glyphicons-halflings-regular.svg new file mode 100644 index 00000000..e3e2dc73 --- /dev/null +++ b/public/fonts/glyphicons-halflings-regular.svg @@ -0,0 +1,229 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/fonts/glyphicons-halflings-regular.ttf b/public/fonts/glyphicons-halflings-regular.ttf new file mode 100644 index 00000000..67fa00bf Binary files /dev/null and b/public/fonts/glyphicons-halflings-regular.ttf differ diff --git a/public/fonts/glyphicons-halflings-regular.woff b/public/fonts/glyphicons-halflings-regular.woff new file mode 100644 index 00000000..8c54182a Binary files /dev/null and b/public/fonts/glyphicons-halflings-regular.woff differ diff --git a/public/img/BOOTSTRAP-LICENSE.txt b/public/img/BOOTSTRAP-LICENSE.txt new file mode 100644 index 00000000..5a3367c6 --- /dev/null +++ b/public/img/BOOTSTRAP-LICENSE.txt @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2011-2015 Twitter, Inc + +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/public/img/GitHubInvitation.png b/public/img/GitHubInvitation.png new file mode 100644 index 00000000..6bed6b21 Binary files /dev/null and b/public/img/GitHubInvitation.png differ diff --git a/public/img/glyphicons-halflings-white.png b/public/img/glyphicons-halflings-white.png new file mode 100644 index 00000000..3bf6484a Binary files /dev/null and b/public/img/glyphicons-halflings-white.png differ diff --git a/public/img/glyphicons-halflings.png b/public/img/glyphicons-halflings.png new file mode 100644 index 00000000..a9969993 Binary files /dev/null and b/public/img/glyphicons-halflings.png differ diff --git a/public/img/rainycloud.png b/public/img/rainycloud.png new file mode 100644 index 00000000..6b8eee0c Binary files /dev/null and b/public/img/rainycloud.png differ diff --git a/public/js/BOOTSTRAP-LICENSE.txt b/public/js/BOOTSTRAP-LICENSE.txt new file mode 100644 index 00000000..5a3367c6 --- /dev/null +++ b/public/js/BOOTSTRAP-LICENSE.txt @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2011-2015 Twitter, Inc + +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/public/js/BOOTSWATCH-LICENSE.txt b/public/js/BOOTSWATCH-LICENSE.txt new file mode 100644 index 00000000..b6a62f9f --- /dev/null +++ b/public/js/BOOTSWATCH-LICENSE.txt @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2013 Thomas Park + +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/public/js/HTML5SHIV-LICENSES.md b/public/js/HTML5SHIV-LICENSES.md new file mode 100644 index 00000000..402bd0ae --- /dev/null +++ b/public/js/HTML5SHIV-LICENSES.md @@ -0,0 +1,372 @@ +Copyright (c) 2014 Alexander Farkas (aFarkas). + +This software is licensed under a dual license system (MIT or GPL version 2). +This means you are free to choose with which of both licenses (MIT or +GPL version 2) you want to use this library. + +The license texts of the MIT license and the GPL version 2 are as follows: + + +## MIT License + + 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. + + + +## GNU GENERAL PUBLIC LICENSE Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) 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 +this service 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 make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. 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. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +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 +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE 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. + + 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 +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 2014 Alexander Farkas (aFarkas) + + 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 2014 Alexander Farkas (aFarkas) + Gnomovision 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, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This 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 Library General +Public License instead of this License. diff --git a/public/js/JQUERY-LICENSE.txt b/public/js/JQUERY-LICENSE.txt new file mode 100644 index 00000000..1c73c81d --- /dev/null +++ b/public/js/JQUERY-LICENSE.txt @@ -0,0 +1,37 @@ +Copyright jQuery Foundation and other contributors, https://jquery.org/ + +This software consists of voluntary contributions made by many +individuals. For exact contribution history, see the revision history +available at https://github.com/jquery/jquery + +The following license applies to all parts of this software except as +documented below: + +==== + +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. + +==== + +All files located in the node_modules and external directories are +externally maintained libraries used by this software which have their +own licenses; we recommend you read them, as their terms may differ from +the terms above. + diff --git a/public/js/TIMEAGO-LICENSE.txt b/public/js/TIMEAGO-LICENSE.txt new file mode 100644 index 00000000..2974d734 --- /dev/null +++ b/public/js/TIMEAGO-LICENSE.txt @@ -0,0 +1,23 @@ +Copyright (c) 2008-2015 Ryan McGeary + +MIT License + +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/public/js/UITABLEFILTER-LICENSE.txt b/public/js/UITABLEFILTER-LICENSE.txt new file mode 100644 index 00000000..4267a03f --- /dev/null +++ b/public/js/UITABLEFILTER-LICENSE.txt @@ -0,0 +1,22 @@ +Copyright 2013 jQuery Foundation and other contributors +http://jquery.com/ + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/public/js/bootstrap.js b/public/js/bootstrap.js new file mode 100644 index 00000000..53da1c77 --- /dev/null +++ b/public/js/bootstrap.js @@ -0,0 +1,2114 @@ +/*! + * Bootstrap v3.2.0 (http://getbootstrap.com) + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript requires jQuery') } + +/* ======================================================================== + * Bootstrap: transition.js v3.2.0 + * http://getbootstrap.com/javascript/#transitions + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) + // ============================================================ + + function transitionEnd() { + var el = document.createElement('bootstrap') + + var transEndEventNames = { + WebkitTransition : 'webkitTransitionEnd', + MozTransition : 'transitionend', + OTransition : 'oTransitionEnd otransitionend', + transition : 'transitionend' + } + + for (var name in transEndEventNames) { + if (el.style[name] !== undefined) { + return { end: transEndEventNames[name] } + } + } + + return false // explicit for ie8 ( ._.) + } + + // http://blog.alexmaccaw.com/css-transitions + $.fn.emulateTransitionEnd = function (duration) { + var called = false + var $el = this + $(this).one('bsTransitionEnd', function () { called = true }) + var callback = function () { if (!called) $($el).trigger($.support.transition.end) } + setTimeout(callback, duration) + return this + } + + $(function () { + $.support.transition = transitionEnd() + + if (!$.support.transition) return + + $.event.special.bsTransitionEnd = { + bindType: $.support.transition.end, + delegateType: $.support.transition.end, + handle: function (e) { + if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments) + } + } + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: alert.js v3.2.0 + * http://getbootstrap.com/javascript/#alerts + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // ALERT CLASS DEFINITION + // ====================== + + var dismiss = '[data-dismiss="alert"]' + var Alert = function (el) { + $(el).on('click', dismiss, this.close) + } + + Alert.VERSION = '3.2.0' + + Alert.prototype.close = function (e) { + var $this = $(this) + var selector = $this.attr('data-target') + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 + } + + var $parent = $(selector) + + if (e) e.preventDefault() + + if (!$parent.length) { + $parent = $this.hasClass('alert') ? $this : $this.parent() + } + + $parent.trigger(e = $.Event('close.bs.alert')) + + if (e.isDefaultPrevented()) return + + $parent.removeClass('in') + + function removeElement() { + // detach from parent, fire event then clean up data + $parent.detach().trigger('closed.bs.alert').remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent + .one('bsTransitionEnd', removeElement) + .emulateTransitionEnd(150) : + removeElement() + } + + + // ALERT PLUGIN DEFINITION + // ======================= + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.alert') + + if (!data) $this.data('bs.alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + var old = $.fn.alert + + $.fn.alert = Plugin + $.fn.alert.Constructor = Alert + + + // ALERT NO CONFLICT + // ================= + + $.fn.alert.noConflict = function () { + $.fn.alert = old + return this + } + + + // ALERT DATA-API + // ============== + + $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: button.js v3.2.0 + * http://getbootstrap.com/javascript/#buttons + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // BUTTON PUBLIC CLASS DEFINITION + // ============================== + + var Button = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Button.DEFAULTS, options) + this.isLoading = false + } + + Button.VERSION = '3.2.0' + + Button.DEFAULTS = { + loadingText: 'loading...' + } + + Button.prototype.setState = function (state) { + var d = 'disabled' + var $el = this.$element + var val = $el.is('input') ? 'val' : 'html' + var data = $el.data() + + state = state + 'Text' + + if (data.resetText == null) $el.data('resetText', $el[val]()) + + $el[val](data[state] == null ? this.options[state] : data[state]) + + // push to event loop to allow forms to submit + setTimeout($.proxy(function () { + if (state == 'loadingText') { + this.isLoading = true + $el.addClass(d).attr(d, d) + } else if (this.isLoading) { + this.isLoading = false + $el.removeClass(d).removeAttr(d) + } + }, this), 0) + } + + Button.prototype.toggle = function () { + var changed = true + var $parent = this.$element.closest('[data-toggle="buttons"]') + + if ($parent.length) { + var $input = this.$element.find('input') + if ($input.prop('type') == 'radio') { + if ($input.prop('checked') && this.$element.hasClass('active')) changed = false + else $parent.find('.active').removeClass('active') + } + if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change') + } + + if (changed) this.$element.toggleClass('active') + } + + + // BUTTON PLUGIN DEFINITION + // ======================== + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.button') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.button', (data = new Button(this, options))) + + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + var old = $.fn.button + + $.fn.button = Plugin + $.fn.button.Constructor = Button + + + // BUTTON NO CONFLICT + // ================== + + $.fn.button.noConflict = function () { + $.fn.button = old + return this + } + + + // BUTTON DATA-API + // =============== + + $(document).on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + Plugin.call($btn, 'toggle') + e.preventDefault() + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: carousel.js v3.2.0 + * http://getbootstrap.com/javascript/#carousel + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // CAROUSEL CLASS DEFINITION + // ========================= + + var Carousel = function (element, options) { + this.$element = $(element).on('keydown.bs.carousel', $.proxy(this.keydown, this)) + this.$indicators = this.$element.find('.carousel-indicators') + this.options = options + this.paused = + this.sliding = + this.interval = + this.$active = + this.$items = null + + this.options.pause == 'hover' && this.$element + .on('mouseenter.bs.carousel', $.proxy(this.pause, this)) + .on('mouseleave.bs.carousel', $.proxy(this.cycle, this)) + } + + Carousel.VERSION = '3.2.0' + + Carousel.DEFAULTS = { + interval: 5000, + pause: 'hover', + wrap: true + } + + Carousel.prototype.keydown = function (e) { + switch (e.which) { + case 37: this.prev(); break + case 39: this.next(); break + default: return + } + + e.preventDefault() + } + + Carousel.prototype.cycle = function (e) { + e || (this.paused = false) + + this.interval && clearInterval(this.interval) + + this.options.interval + && !this.paused + && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) + + return this + } + + Carousel.prototype.getItemIndex = function (item) { + this.$items = item.parent().children('.item') + return this.$items.index(item || this.$active) + } + + Carousel.prototype.to = function (pos) { + var that = this + var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active')) + + if (pos > (this.$items.length - 1) || pos < 0) return + + if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid" + if (activeIndex == pos) return this.pause().cycle() + + return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos])) + } + + Carousel.prototype.pause = function (e) { + e || (this.paused = true) + + if (this.$element.find('.next, .prev').length && $.support.transition) { + this.$element.trigger($.support.transition.end) + this.cycle(true) + } + + this.interval = clearInterval(this.interval) + + return this + } + + Carousel.prototype.next = function () { + if (this.sliding) return + return this.slide('next') + } + + Carousel.prototype.prev = function () { + if (this.sliding) return + return this.slide('prev') + } + + Carousel.prototype.slide = function (type, next) { + var $active = this.$element.find('.item.active') + var $next = next || $active[type]() + var isCycling = this.interval + var direction = type == 'next' ? 'left' : 'right' + var fallback = type == 'next' ? 'first' : 'last' + var that = this + + if (!$next.length) { + if (!this.options.wrap) return + $next = this.$element.find('.item')[fallback]() + } + + if ($next.hasClass('active')) return (this.sliding = false) + + var relatedTarget = $next[0] + var slideEvent = $.Event('slide.bs.carousel', { + relatedTarget: relatedTarget, + direction: direction + }) + this.$element.trigger(slideEvent) + if (slideEvent.isDefaultPrevented()) return + + this.sliding = true + + isCycling && this.pause() + + if (this.$indicators.length) { + this.$indicators.find('.active').removeClass('active') + var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)]) + $nextIndicator && $nextIndicator.addClass('active') + } + + var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid" + if ($.support.transition && this.$element.hasClass('slide')) { + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + $active + .one('bsTransitionEnd', function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { + that.$element.trigger(slidEvent) + }, 0) + }) + .emulateTransitionEnd($active.css('transition-duration').slice(0, -1) * 1000) + } else { + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger(slidEvent) + } + + isCycling && this.cycle() + + return this + } + + + // CAROUSEL PLUGIN DEFINITION + // ========================== + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.carousel') + var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) + var action = typeof option == 'string' ? option : options.slide + + if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (action) data[action]() + else if (options.interval) data.pause().cycle() + }) + } + + var old = $.fn.carousel + + $.fn.carousel = Plugin + $.fn.carousel.Constructor = Carousel + + + // CAROUSEL NO CONFLICT + // ==================== + + $.fn.carousel.noConflict = function () { + $.fn.carousel = old + return this + } + + + // CAROUSEL DATA-API + // ================= + + $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) { + var href + var $this = $(this) + var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7 + if (!$target.hasClass('carousel')) return + var options = $.extend({}, $target.data(), $this.data()) + var slideIndex = $this.attr('data-slide-to') + if (slideIndex) options.interval = false + + Plugin.call($target, options) + + if (slideIndex) { + $target.data('bs.carousel').to(slideIndex) + } + + e.preventDefault() + }) + + $(window).on('load', function () { + $('[data-ride="carousel"]').each(function () { + var $carousel = $(this) + Plugin.call($carousel, $carousel.data()) + }) + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: collapse.js v3.2.0 + * http://getbootstrap.com/javascript/#collapse + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // COLLAPSE PUBLIC CLASS DEFINITION + // ================================ + + var Collapse = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Collapse.DEFAULTS, options) + this.transitioning = null + + if (this.options.parent) this.$parent = $(this.options.parent) + if (this.options.toggle) this.toggle() + } + + Collapse.VERSION = '3.2.0' + + Collapse.DEFAULTS = { + toggle: true + } + + Collapse.prototype.dimension = function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + Collapse.prototype.show = function () { + if (this.transitioning || this.$element.hasClass('in')) return + + var startEvent = $.Event('show.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) return + + var actives = this.$parent && this.$parent.find('> .panel > .in') + + if (actives && actives.length) { + var hasData = actives.data('bs.collapse') + if (hasData && hasData.transitioning) return + Plugin.call(actives, 'hide') + hasData || actives.data('bs.collapse', null) + } + + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + .addClass('collapsing')[dimension](0) + + this.transitioning = 1 + + var complete = function () { + this.$element + .removeClass('collapsing') + .addClass('collapse in')[dimension]('') + this.transitioning = 0 + this.$element + .trigger('shown.bs.collapse') + } + + if (!$.support.transition) return complete.call(this) + + var scrollSize = $.camelCase(['scroll', dimension].join('-')) + + this.$element + .one('bsTransitionEnd', $.proxy(complete, this)) + .emulateTransitionEnd(350)[dimension](this.$element[0][scrollSize]) + } + + Collapse.prototype.hide = function () { + if (this.transitioning || !this.$element.hasClass('in')) return + + var startEvent = $.Event('hide.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) return + + var dimension = this.dimension() + + this.$element[dimension](this.$element[dimension]())[0].offsetHeight + + this.$element + .addClass('collapsing') + .removeClass('collapse') + .removeClass('in') + + this.transitioning = 1 + + var complete = function () { + this.transitioning = 0 + this.$element + .trigger('hidden.bs.collapse') + .removeClass('collapsing') + .addClass('collapse') + } + + if (!$.support.transition) return complete.call(this) + + this.$element + [dimension](0) + .one('bsTransitionEnd', $.proxy(complete, this)) + .emulateTransitionEnd(350) + } + + Collapse.prototype.toggle = function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + + // COLLAPSE PLUGIN DEFINITION + // ========================== + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.collapse') + var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) + + if (!data && options.toggle && option == 'show') option = !option + if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + var old = $.fn.collapse + + $.fn.collapse = Plugin + $.fn.collapse.Constructor = Collapse + + + // COLLAPSE NO CONFLICT + // ==================== + + $.fn.collapse.noConflict = function () { + $.fn.collapse = old + return this + } + + + // COLLAPSE DATA-API + // ================= + + $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) { + var href + var $this = $(this) + var target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7 + var $target = $(target) + var data = $target.data('bs.collapse') + var option = data ? 'toggle' : $this.data() + var parent = $this.attr('data-parent') + var $parent = parent && $(parent) + + if (!data || !data.transitioning) { + if ($parent) $parent.find('[data-toggle="collapse"][data-parent="' + parent + '"]').not($this).addClass('collapsed') + $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed') + } + + Plugin.call($target, option) + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: dropdown.js v3.2.0 + * http://getbootstrap.com/javascript/#dropdowns + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // DROPDOWN CLASS DEFINITION + // ========================= + + var backdrop = '.dropdown-backdrop' + var toggle = '[data-toggle="dropdown"]' + var Dropdown = function (element) { + $(element).on('click.bs.dropdown', this.toggle) + } + + Dropdown.VERSION = '3.2.0' + + Dropdown.prototype.toggle = function (e) { + var $this = $(this) + + if ($this.is('.disabled, :disabled')) return + + var $parent = getParent($this) + var isActive = $parent.hasClass('open') + + clearMenus() + + if (!isActive) { + if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { + // if mobile we use a backdrop because click events don't delegate + $('