aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/twbs/bootstrap/build
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/twbs/bootstrap/build')
-rw-r--r--vendor/twbs/bootstrap/build/.eslintrc.json20
-rw-r--r--vendor/twbs/bootstrap/build/.htmllintrc44
-rw-r--r--vendor/twbs/bootstrap/build/build-plugins.js81
-rw-r--r--vendor/twbs/bootstrap/build/change-version.js104
-rw-r--r--vendor/twbs/bootstrap/build/gcp-key.json.encbin0 -> 2304 bytes
-rw-r--r--vendor/twbs/bootstrap/build/generate-sri.js60
-rw-r--r--vendor/twbs/bootstrap/build/lint-vars.js82
-rw-r--r--vendor/twbs/bootstrap/build/postcss.config.js14
-rw-r--r--vendor/twbs/bootstrap/build/rollup.config.js53
-rw-r--r--vendor/twbs/bootstrap/build/sauce_browsers.json65
-rw-r--r--vendor/twbs/bootstrap/build/saucelabs-unit-test.js116
-rw-r--r--vendor/twbs/bootstrap/build/ship.sh70
-rw-r--r--vendor/twbs/bootstrap/build/vnu-jar.js68
-rw-r--r--vendor/twbs/bootstrap/build/workbox.config.json8
-rw-r--r--vendor/twbs/bootstrap/build/workbox.js58
15 files changed, 843 insertions, 0 deletions
diff --git a/vendor/twbs/bootstrap/build/.eslintrc.json b/vendor/twbs/bootstrap/build/.eslintrc.json
new file mode 100644
index 000000000..76e7f37b6
--- /dev/null
+++ b/vendor/twbs/bootstrap/build/.eslintrc.json
@@ -0,0 +1,20 @@
+{
+ "env": {
+ "browser": false,
+ "node": true
+ },
+ "parserOptions": {
+ "sourceType": "script"
+ },
+ "extends": "../.eslintrc.json",
+ "rules": {
+ "consistent-return": "off",
+ "func-style": "off",
+ "no-console": "off",
+ "no-magic-numbers": "off",
+ "no-process-env": "off",
+ "no-process-exit": "off",
+ "no-sync": "off",
+ "spaced-comment": "off"
+ }
+}
diff --git a/vendor/twbs/bootstrap/build/.htmllintrc b/vendor/twbs/bootstrap/build/.htmllintrc
new file mode 100644
index 000000000..d5cf54f5b
--- /dev/null
+++ b/vendor/twbs/bootstrap/build/.htmllintrc
@@ -0,0 +1,44 @@
+{
+ "attr-bans": ["align", "background", "bgcolor", "border", "frameborder", "longdesc", "marginwidth", "marginheight", "scrolling"],
+ "attr-name-style": false,
+ "attr-no-dup": true,
+ "attr-no-unsafe-char": true,
+ "attr-quote-style": "double",
+ "attr-req-value": true,
+ "attr-validate": false,
+ "class-no-dup": true,
+ "class-style": "none",
+ "doctype-first": true,
+ "doctype-html5": true,
+ "fig-req-figcaption": false,
+ "focusable-tabindex-style": true,
+ "head-req-title": true,
+ "head-valid-content-model": false,
+ "href-style": false,
+ "html-req-lang": true,
+ "html-valid-content-model": false,
+ "id-class-ignore-regex": "(onclick|content|[a-z]+([A-Z][a-z])+)",
+ "id-class-no-ad": true,
+ "id-class-style": false,
+ "id-no-dup": true,
+ "img-req-alt": "allownull",
+ "img-req-src": false,
+ "indent-style": "spaces",
+ "indent-width": 2,
+ "input-radio-req-name": false,
+ "input-req-label": false,
+ "label-req-for": true,
+ "lang-style": "case",
+ "line-no-trailing-whitespace": false,
+ "line-end-style": "lf",
+ "spec-char-escape": false,
+ "table-req-header": false,
+ "tag-bans": ["b", "i"],
+ "tag-close": true,
+ "tag-name-lowercase": true,
+ "tag-name-match": true,
+ "tag-self-close": false,
+ "text-ignore-regex": false,
+ "title-max-len": 70,
+ "title-no-dup": true
+}
diff --git a/vendor/twbs/bootstrap/build/build-plugins.js b/vendor/twbs/bootstrap/build/build-plugins.js
new file mode 100644
index 000000000..22a179066
--- /dev/null
+++ b/vendor/twbs/bootstrap/build/build-plugins.js
@@ -0,0 +1,81 @@
+/*!
+ * Script to build our plugins to use them separately.
+ * Copyright 2018 The Bootstrap Authors
+ * Copyright 2018 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+
+'use strict'
+
+const rollup = require('rollup')
+const path = require('path')
+const babel = require('rollup-plugin-babel')
+const TEST = process.env.NODE_ENV === 'test'
+
+const plugins = [
+ babel({
+ exclude: 'node_modules/**', // Only transpile our source code
+ externalHelpersWhitelist: [ // Include only required helpers
+ 'defineProperties',
+ 'createClass',
+ 'inheritsLoose',
+ 'defineProperty',
+ 'objectSpread'
+ ]
+ })
+]
+
+const format = 'umd'
+const rootPath = !TEST ? '../js/dist/' : '../js/coverage/dist/'
+const bsPlugins = {
+ Alert: path.resolve(__dirname, '../js/src/alert.js'),
+ Button: path.resolve(__dirname, '../js/src/button.js'),
+ Carousel: path.resolve(__dirname, '../js/src/carousel.js'),
+ Collapse: path.resolve(__dirname, '../js/src/collapse.js'),
+ Dropdown: path.resolve(__dirname, '../js/src/dropdown.js'),
+ Modal: path.resolve(__dirname, '../js/src/modal.js'),
+ Popover: path.resolve(__dirname, '../js/src/popover.js'),
+ ScrollSpy: path.resolve(__dirname, '../js/src/scrollspy.js'),
+ Tab: path.resolve(__dirname, '../js/src/tab.js'),
+ Tooltip: path.resolve(__dirname, '../js/src/tooltip.js'),
+ Util: path.resolve(__dirname, '../js/src/util.js')
+}
+
+Object.keys(bsPlugins)
+ .forEach((pluginKey) => {
+ console.log(`Building ${pluginKey} plugin...`)
+
+ const external = ['jquery', 'popper.js']
+ const globals = {
+ jquery: 'jQuery', // Ensure we use jQuery which is always available even in noConflict mode
+ 'popper.js': 'Popper'
+ }
+
+ // Do not bundle Util in plugins
+ if (pluginKey !== 'Util') {
+ external.push(bsPlugins.Util)
+ globals[bsPlugins.Util] = 'Util'
+ }
+
+ // Do not bundle Tooltip in Popover
+ if (pluginKey === 'Popover') {
+ external.push(bsPlugins.Tooltip)
+ globals[bsPlugins.Tooltip] = 'Tooltip'
+ }
+
+ rollup.rollup({
+ input: bsPlugins[pluginKey],
+ plugins,
+ external
+ }).then((bundle) => {
+ bundle.write({
+ format,
+ name: pluginKey,
+ sourcemap: true,
+ globals,
+ file: path.resolve(__dirname, `${rootPath}${pluginKey.toLowerCase()}.js`)
+ })
+ .then(() => console.log(`Building ${pluginKey} plugin... Done !`))
+ .catch((err) => console.error(`${pluginKey}: ${err}`))
+ })
+ })
diff --git a/vendor/twbs/bootstrap/build/change-version.js b/vendor/twbs/bootstrap/build/change-version.js
new file mode 100644
index 000000000..7102dc083
--- /dev/null
+++ b/vendor/twbs/bootstrap/build/change-version.js
@@ -0,0 +1,104 @@
+#!/usr/bin/env node
+
+/*!
+ * Script to update version number references in the project.
+ * Copyright 2017-2018 The Bootstrap Authors
+ * Copyright 2017-2018 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+
+'use strict'
+
+const fs = require('fs')
+const path = require('path')
+const sh = require('shelljs')
+
+sh.config.fatal = true
+
+// Blame TC39... https://github.com/benjamingr/RegExp.escape/issues/37
+function regExpQuote(string) {
+ return string.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&')
+}
+
+function regExpQuoteReplacement(string) {
+ return string.replace(/[$]/g, '$$')
+}
+
+const DRY_RUN = false
+
+function walkAsync(directory, excludedDirectories, fileCallback, errback) {
+ if (excludedDirectories.has(path.parse(directory).base)) {
+ return
+ }
+ fs.readdir(directory, (err, names) => {
+ if (err) {
+ errback(err)
+ return
+ }
+ names.forEach((name) => {
+ const filepath = path.join(directory, name)
+ fs.lstat(filepath, (err, stats) => {
+ if (err) {
+ process.nextTick(errback, err)
+ return
+ }
+ if (stats.isDirectory()) {
+ process.nextTick(walkAsync, filepath, excludedDirectories, fileCallback, errback)
+ } else if (stats.isFile()) {
+ process.nextTick(fileCallback, filepath)
+ }
+ })
+ })
+ })
+}
+
+function replaceRecursively(directory, excludedDirectories, allowedExtensions, original, replacement) {
+ original = new RegExp(regExpQuote(original), 'g')
+ replacement = regExpQuoteReplacement(replacement)
+ const updateFile = DRY_RUN ? (filepath) => {
+ if (allowedExtensions.has(path.parse(filepath).ext)) {
+ console.log(`FILE: ${filepath}`)
+ } else {
+ console.log(`EXCLUDED:${filepath}`)
+ }
+ } : (filepath) => {
+ if (allowedExtensions.has(path.parse(filepath).ext)) {
+ sh.sed('-i', original, replacement, filepath)
+ }
+ }
+ walkAsync(directory, excludedDirectories, updateFile, (err) => {
+ console.error('ERROR while traversing directory!:')
+ console.error(err)
+ process.exit(1)
+ })
+}
+
+function main(args) {
+ if (args.length !== 2) {
+ console.error('USAGE: change-version old_version new_version')
+ console.error('Got arguments:', args)
+ process.exit(1)
+ }
+ const oldVersion = args[0]
+ const newVersion = args[1]
+ const EXCLUDED_DIRS = new Set([
+ '.git',
+ 'node_modules',
+ 'vendor'
+ ])
+ const INCLUDED_EXTENSIONS = new Set([
+ // This extension whitelist is how we avoid modifying binary files
+ '',
+ '.css',
+ '.html',
+ '.js',
+ '.json',
+ '.md',
+ '.scss',
+ '.txt',
+ '.yml'
+ ])
+ replaceRecursively('.', EXCLUDED_DIRS, INCLUDED_EXTENSIONS, oldVersion, newVersion)
+}
+
+main(process.argv.slice(2))
diff --git a/vendor/twbs/bootstrap/build/gcp-key.json.enc b/vendor/twbs/bootstrap/build/gcp-key.json.enc
new file mode 100644
index 000000000..6e1856a2f
--- /dev/null
+++ b/vendor/twbs/bootstrap/build/gcp-key.json.enc
Binary files differ
diff --git a/vendor/twbs/bootstrap/build/generate-sri.js b/vendor/twbs/bootstrap/build/generate-sri.js
new file mode 100644
index 000000000..10936e8a1
--- /dev/null
+++ b/vendor/twbs/bootstrap/build/generate-sri.js
@@ -0,0 +1,60 @@
+#!/usr/bin/env node
+
+/*!
+ * Script to generate SRI hashes for use in our docs.
+ * Remember to use the same vendor files as the CDN ones,
+ * otherwise the hashes won't match!
+ *
+ * Copyright 2017-2018 The Bootstrap Authors
+ * Copyright 2017-2018 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+
+'use strict'
+
+const fs = require('fs')
+const path = require('path')
+const sriToolbox = require('sri-toolbox')
+const sh = require('shelljs')
+
+sh.config.fatal = true
+
+const configFile = path.join(__dirname, '../_config.yml')
+
+// Array of objects which holds the files to generate SRI hashes for.
+// `file` is the path from the root folder
+// `configPropertyName` is the _config.yml variable's name of the file
+const files = [
+ {
+ file: 'dist/css/bootstrap.min.css',
+ configPropertyName: 'css_hash'
+ },
+ {
+ file: 'dist/js/bootstrap.min.js',
+ configPropertyName: 'js_hash'
+ },
+ {
+ file: 'site/docs/4.1/assets/js/vendor/jquery-slim.min.js',
+ configPropertyName: 'jquery_hash'
+ },
+ {
+ file: 'site/docs/4.1/assets/js/vendor/popper.min.js',
+ configPropertyName: 'popper_hash'
+ }
+]
+
+files.forEach((file) => {
+ fs.readFile(file.file, 'utf8', (err, data) => {
+ if (err) {
+ throw err
+ }
+
+ const integrity = sriToolbox.generate({
+ algorithms: ['sha384']
+ }, data)
+
+ console.log(`${file.configPropertyName}: ${integrity}`)
+
+ sh.sed('-i', new RegExp(`(\\s${file.configPropertyName}:\\s+"|')(\\S+)("|')`), `$1${integrity}$3`, configFile)
+ })
+})
diff --git a/vendor/twbs/bootstrap/build/lint-vars.js b/vendor/twbs/bootstrap/build/lint-vars.js
new file mode 100644
index 000000000..1b8d71cc6
--- /dev/null
+++ b/vendor/twbs/bootstrap/build/lint-vars.js
@@ -0,0 +1,82 @@
+#!/usr/bin/env node
+
+/*!
+ * Script to find unused Sass variables.
+ * Copyright 2017-2018 The Bootstrap Authors
+ * Copyright 2017-2018 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+
+'use strict'
+
+const fs = require('fs')
+const path = require('path')
+const glob = require('glob')
+
+// Blame TC39... https://github.com/benjamingr/RegExp.escape/issues/37
+function regExpQuote(str) {
+ return str.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&')
+}
+
+let globalSuccess = true
+
+function findUnusedVars(dir) {
+ if (!(fs.existsSync(dir) && fs.statSync(dir).isDirectory())) {
+ console.log(`"${dir}": Not a valid directory!`)
+ process.exit(1)
+ }
+
+ console.log(`Finding unused variables in "${dir}"...`)
+
+ // A variable to handle success/failure message in this function
+ let unusedVarsFound = false
+
+ // Array of all Sass files' content
+ const sassFiles = glob.sync(path.join(dir, '**/*.scss'))
+ // String of all Sass files' content
+ let sassFilesString = ''
+
+ sassFiles.forEach((file) => {
+ sassFilesString += fs.readFileSync(file, 'utf8')
+ })
+
+ // Array of all Sass variables
+ const variables = sassFilesString.match(/(^\$[a-zA-Z0-9_-]+[^:])/gm)
+
+ console.log(`Found ${variables.length} total variables.`)
+
+ // Loop through each variable
+ variables.forEach((variable) => {
+ const re = new RegExp(regExpQuote(variable), 'g')
+ const count = (sassFilesString.match(re) || []).length
+
+ if (count === 1) {
+ console.log(`Variable "${variable}" is not being used.`)
+ unusedVarsFound = true
+ globalSuccess = false
+ }
+ })
+
+ if (unusedVarsFound === false) {
+ console.log(`No unused variables found in "${dir}".`)
+ }
+}
+
+function main(args) {
+ if (args.length < 1) {
+ console.log('Wrong arguments!')
+ console.log('Usage: lint-vars.js folder [, folder2...]')
+ process.exit(1)
+ }
+
+ args.forEach((arg) => {
+ findUnusedVars(arg)
+ })
+
+ if (globalSuccess === false) {
+ process.exit(1)
+ }
+}
+
+// The first and second args are: path/to/node script.js
+main(process.argv.slice(2))
diff --git a/vendor/twbs/bootstrap/build/postcss.config.js b/vendor/twbs/bootstrap/build/postcss.config.js
new file mode 100644
index 000000000..157291ffd
--- /dev/null
+++ b/vendor/twbs/bootstrap/build/postcss.config.js
@@ -0,0 +1,14 @@
+'use strict'
+
+module.exports = (ctx) => ({
+ map: ctx.file.dirname.includes('examples') ? false : {
+ inline: false,
+ annotation: true,
+ sourcesContent: true
+ },
+ plugins: {
+ autoprefixer: {
+ cascade: false
+ }
+ }
+})
diff --git a/vendor/twbs/bootstrap/build/rollup.config.js b/vendor/twbs/bootstrap/build/rollup.config.js
new file mode 100644
index 000000000..93370d31d
--- /dev/null
+++ b/vendor/twbs/bootstrap/build/rollup.config.js
@@ -0,0 +1,53 @@
+'use strict'
+
+const path = require('path')
+const babel = require('rollup-plugin-babel')
+const resolve = require('rollup-plugin-node-resolve')
+
+const pkg = require(path.resolve(__dirname, '../package.json'))
+const BUNDLE = process.env.BUNDLE === 'true'
+const year = new Date().getFullYear()
+
+let fileDest = 'bootstrap.js'
+const external = ['jquery', 'popper.js']
+const plugins = [
+ babel({
+ exclude: 'node_modules/**', // Only transpile our source code
+ externalHelpersWhitelist: [ // Include only required helpers
+ 'defineProperties',
+ 'createClass',
+ 'inheritsLoose',
+ 'defineProperty',
+ 'objectSpread'
+ ]
+ })
+]
+const globals = {
+ jquery: 'jQuery', // Ensure we use jQuery which is always available even in noConflict mode
+ 'popper.js': 'Popper'
+}
+
+if (BUNDLE) {
+ fileDest = 'bootstrap.bundle.js'
+ // Remove last entry in external array to bundle Popper
+ external.pop()
+ delete globals['popper.js']
+ plugins.push(resolve())
+}
+
+module.exports = {
+ input: path.resolve(__dirname, '../js/src/index.js'),
+ output: {
+ banner: `/*!
+ * Bootstrap v${pkg.version} (${pkg.homepage})
+ * Copyright 2011-${year} ${pkg.author}
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */`,
+ file: path.resolve(__dirname, `../dist/js/${fileDest}`),
+ format: 'umd',
+ globals,
+ name: 'bootstrap'
+ },
+ external,
+ plugins
+}
diff --git a/vendor/twbs/bootstrap/build/sauce_browsers.json b/vendor/twbs/bootstrap/build/sauce_browsers.json
new file mode 100644
index 000000000..b112d9c5b
--- /dev/null
+++ b/vendor/twbs/bootstrap/build/sauce_browsers.json
@@ -0,0 +1,65 @@
+[
+ {
+ "browserName": "safari",
+ "platform": "OS X 10.11",
+ "version": "latest"
+ },
+ {
+ "browserName": "chrome",
+ "platform": "OS X 10.11",
+ "version": "latest"
+ },
+ {
+ "browserName": "firefox",
+ "platform": "OS X 10.11",
+ "version": "latest"
+ },
+ {
+ "browserName": "MicrosoftEdge",
+ "platform": "Windows 10",
+ "version": "latest"
+ },
+ {
+ "browserName": "internet explorer",
+ "version": "11",
+ "platform": "Windows 8.1"
+ },
+ {
+ "browserName": "internet explorer",
+ "version": "10",
+ "platform": "Windows 8"
+ },
+ {
+ "browserName": "chrome",
+ "platform": "Windows 10",
+ "version": "latest"
+ },
+ {
+ "browserName": "firefox",
+ "platform": "Windows 10",
+ "version": "latest"
+ },
+ {
+ "browserName": "iphone",
+ "deviceName": "iPhone Simulator",
+ "platformName": "OS X 10.11",
+ "version": "9.3"
+ },
+ {
+ "browserName": "chrome",
+ "platform": "Linux",
+ "version": "latest"
+ },
+ {
+ "browserName": "firefox",
+ "platform": "Linux",
+ "version": "latest"
+ },
+ {
+ "platform": "Linux",
+ "browserName": "android",
+ "deviceName": "Android Emulator",
+ "version": "latest",
+ "deviceType": "phone"
+ }
+]
diff --git a/vendor/twbs/bootstrap/build/saucelabs-unit-test.js b/vendor/twbs/bootstrap/build/saucelabs-unit-test.js
new file mode 100644
index 000000000..b4d952536
--- /dev/null
+++ b/vendor/twbs/bootstrap/build/saucelabs-unit-test.js
@@ -0,0 +1,116 @@
+/*!
+ * Script to run our Sauce Labs tests.
+ * Copyright 2017-2018 The Bootstrap Authors
+ * Copyright 2017-2018 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+
+/*
+Docs: https://wiki.saucelabs.com/display/DOCS/Platform+Configurator
+Mac Opera is not currently supported by Sauce Labs
+Win Opera 15+ is not currently supported by Sauce Labs
+iOS Chrome is not currently supported by Sauce Labs
+*/
+
+'use strict'
+
+const path = require('path')
+const JSUnitSaucelabs = require('jsunitsaucelabs')
+
+const jsUnitSaucelabs = new JSUnitSaucelabs({
+ username: process.env.SAUCE_USERNAME,
+ password: process.env.SAUCE_ACCESS_KEY,
+ build: process.env.TRAVIS_JOB_ID
+})
+
+const testURL = 'http://localhost:3000/js/tests/index.html?hidepassed'
+const browsersFile = require(path.resolve(__dirname, './sauce_browsers.json'))
+const errorMessages = [
+ 'Test exceeded maximum duration',
+ 'Test exceeded maximum duration after 180 seconds'
+]
+let jobsDone = 0
+let jobsSucceeded = 0
+
+const waitingCallback = (error, body, id) => {
+ if (error) {
+ console.error(error)
+ process.exit(1)
+ }
+
+ if (typeof body !== 'undefined') {
+ if (!body.completed) {
+ setTimeout(() => {
+ jsUnitSaucelabs.getStatus(id, (error, body) => {
+ waitingCallback(error, body, id)
+ })
+ }, 2000)
+ } else {
+ const test = body['js tests'][0]
+ const platform = test.platform.join(', ')
+ let passed = false
+ let errorStr = false
+
+ if (test.result !== null) {
+ if (typeof test.result === 'string' && errorMessages.includes(test.result)) {
+ errorStr = test.result
+ } else {
+ passed = test.result.total === test.result.passed
+ }
+ }
+
+ console.log(`Tested ${testURL}`)
+ console.log(`Platform: ${platform}`)
+ console.log(`Passed: ${passed}`)
+ console.log(`URL: ${test.url}\n`)
+
+ if (errorStr) {
+ console.error(`${platform}: ${errorStr}`)
+ }
+
+ if (passed) {
+ jobsSucceeded++
+ }
+ jobsDone++
+
+ // Exit
+ if (jobsDone === browsersFile.length - 1) {
+ jsUnitSaucelabs.stop()
+ if (jobsDone > jobsSucceeded) {
+ const failedTests = jobsDone - jobsSucceeded
+ throw new Error(`${failedTests} test${failedTests > 1 ? 's' : ''} failed.`)
+ }
+
+ console.log('All tests passed')
+ process.exit(0)
+ }
+ }
+ }
+}
+
+jsUnitSaucelabs.on('tunnelCreated', () => {
+ browsersFile.forEach((tmpBrowser) => {
+ const browsersPlatform = typeof tmpBrowser.platform === 'undefined' ? tmpBrowser.platformName : tmpBrowser.platform
+ const browsersArray = [browsersPlatform, tmpBrowser.browserName, tmpBrowser.version]
+
+ jsUnitSaucelabs.start([browsersArray], testURL, 'qunit', (error, success) => {
+ if (typeof success !== 'undefined') {
+ const taskIds = success['js tests']
+
+ if (!taskIds || taskIds.length === 0) {
+ throw new Error('Error starting tests through Sauce Labs API')
+ }
+
+ taskIds.forEach((id) => {
+ jsUnitSaucelabs.getStatus(id, (error, body) => {
+ waitingCallback(error, body, id)
+ })
+ })
+ } else {
+ console.error(error)
+ }
+ })
+ })
+})
+
+jsUnitSaucelabs.initTunnel()
diff --git a/vendor/twbs/bootstrap/build/ship.sh b/vendor/twbs/bootstrap/build/ship.sh
new file mode 100644
index 000000000..e3b256e91
--- /dev/null
+++ b/vendor/twbs/bootstrap/build/ship.sh
@@ -0,0 +1,70 @@
+#!/usr/bin/env bash
+#
+# Usage
+# ---------------
+# 1. Clone second version of Bootstrap in sibling directory named `bs-docs`.
+# 2. Within `bs-docs` copy, switch to `gh-pages` branch.
+# 3. Pull latest, re-bundle, re-npm.
+# 4. Run script.
+
+red=$'\e[1;31m'
+green=$'\e[1;32m'
+#blue=$'\e[1;34m'
+magenta=$'\e[1;35m'
+#cyan=$'\e[1;36m'
+end=$'\e[0m'
+
+# Get current version from package.json
+current_version=$(node -p "require('./package.json').version")
+
+if [[ $# -lt 1 ]]; then
+ printf "\n%s⚠️ Shipping aborted. You must specify a version.\n%s" $red $end
+ exit 1
+fi
+
+# Pulling latest changes, just to be sure
+printf "\n%s=======================================================%s" $magenta $end
+printf "\n%sPulling latest changes...%s" $magenta $end
+printf "\n%s=======================================================\n\n%s" $magenta $end
+git pull origin v4-dev
+
+# Update version number
+printf "\n%s=======================================================%s" $magenta $end
+printf "\n%sUpdating version number...%s" $magenta $end
+printf "\n%s=======================================================\n%s" $magenta $end
+npm run release-version "$current_version" "$1"
+
+# Compile latest CSS and JS
+printf "\n%s=======================================================%s" $magenta $end
+printf "\n%sCompile latest CSS and JS...%s" $magenta $end
+printf "\n%s=======================================================\n%s" $magenta $end
+npm run dist
+
+# Generate the SRI hashes
+printf "\n%s=======================================================%s" $magenta $end
+printf "\n%sGenerate the SRI hashes...%s" $magenta $end
+printf "\n%s=======================================================\n%s" $magenta $end
+npm run release-sri
+
+# Compress the dist files
+printf "\n%s=======================================================%s" $magenta $end
+printf "\n%sCompressing the dist files...%s" $magenta $end
+printf "\n%s=======================================================\n%s" $magenta $end
+npm run release-zip
+
+# Compile the docs
+printf "\n%s=======================================================%s" $magenta $end
+printf "\n%sCompile hosted documentation...%s" $magenta $end
+printf "\n%s=======================================================\n%s" $magenta $end
+npm run docs-github
+
+# Copy the contents of the built docs site over to `bs-docs` repo
+printf "\n%s=======================================================%s" $magenta $end
+printf "\n%sCopy it over...%s" $magenta $end
+printf "\n%s=======================================================\n%s" $magenta $end
+cp -rf _gh_pages/. ../bs-docs/
+printf "\nDone!\n"
+
+printf "\n%s=======================================================%s" $green $end
+printf "\n%sSuccess, $1 is ready to review and publish.%s" $green $end
+printf "\n%s=======================================================\n\n%s" $green $end
diff --git a/vendor/twbs/bootstrap/build/vnu-jar.js b/vendor/twbs/bootstrap/build/vnu-jar.js
new file mode 100644
index 000000000..111e03409
--- /dev/null
+++ b/vendor/twbs/bootstrap/build/vnu-jar.js
@@ -0,0 +1,68 @@
+#!/usr/bin/env node
+
+/*!
+ * Script to run vnu-jar if Java is available.
+ * Copyright 2017-2018 The Bootstrap Authors
+ * Copyright 2017-2018 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+
+'use strict'
+
+const childProcess = require('child_process')
+const vnu = require('vnu-jar')
+
+childProcess.exec('java -version', (error, stdout, stderr) => {
+ if (error) {
+ console.error('Skipping vnu-jar test; Java is missing.')
+ return
+ }
+
+ const is32bitJava = !stderr.match(/64-Bit/)
+
+ // vnu-jar accepts multiple ignores joined with a `|`.
+ // Also note that the ignores are regular expressions.
+ const ignores = [
+ // "autocomplete" is included in <button> and checkboxes and radio <input>s due to
+ // Firefox's non-standard autocomplete behavior - see https://bugzilla.mozilla.org/show_bug.cgi?id=654072
+ 'Attribute “autocomplete” is only allowed when the input type is.*',
+ 'Attribute “autocomplete” not allowed on element “button” at this point.',
+ // We use holder.js with `data-src` and no `src` to avoid 404 errors;
+ // we could work around this, but I'm not sure it's worth it.
+ 'Element “img” is missing required attribute “src”.',
+ // Markup used in Components → Forms → Layout → Form grid → Horizontal form is currently invalid,
+ // but used this way due to lack of support for flexbox layout on <fieldset> element in most browsers
+ 'Element “legend” not allowed as child of element “div” in this context.*',
+ // Content → Reboot uses various date/time inputs as a visual example.
+ // Documentation does not rely on them being usable.
+ 'The “date” input type is not supported in all browsers.*',
+ 'The “time” input type is not supported in all browsers.*',
+ // IE11 doesn't recognise <main> / give the element an implicit "main" landmark.
+ // Explicit role="main" is redundant for other modern browsers, but still valid.
+ 'The “main” role is unnecessary for element “main”.',
+ // Ignore the wrong lanuage code warnings for now; they happen randomly.
+ 'This document appears to be written in.*'
+ ].join('|')
+
+ const args = [
+ '-jar',
+ vnu,
+ '--asciiquotes',
+ '--skip-non-html',
+ '--Werror',
+ `--filterpattern "${ignores}"`,
+ '_gh_pages/',
+ 'js/tests/'
+ ]
+
+ // For the 32-bit Java we need to pass `-Xss512k`
+ if (is32bitJava) {
+ args.splice(0, 0, '-Xss512k')
+ }
+
+ return childProcess.spawn('java', args, {
+ shell: true,
+ stdio: 'inherit'
+ })
+ .on('exit', process.exit)
+})
diff --git a/vendor/twbs/bootstrap/build/workbox.config.json b/vendor/twbs/bootstrap/build/workbox.config.json
new file mode 100644
index 000000000..a649431ed
--- /dev/null
+++ b/vendor/twbs/bootstrap/build/workbox.config.json
@@ -0,0 +1,8 @@
+{
+ "globDirectory": "./",
+ "globPatterns": [
+ "_gh_pages/**/*.{html,css,js,json,png,svg}"
+ ],
+ "swSrc": "./site/sw.js",
+ "swDest": "./_gh_pages/sw.js"
+}
diff --git a/vendor/twbs/bootstrap/build/workbox.js b/vendor/twbs/bootstrap/build/workbox.js
new file mode 100644
index 000000000..3a7ba450a
--- /dev/null
+++ b/vendor/twbs/bootstrap/build/workbox.js
@@ -0,0 +1,58 @@
+/*!
+ * Script to generate our docs service worker.
+ * Copyright 2017-2018 The Bootstrap Authors
+ * Copyright 2017-2018 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+
+'use strict'
+
+const fs = require('fs')
+const path = require('path')
+const swBuild = require('workbox-build')
+const config = require('./workbox.config.json')
+
+const buildPrefix = '_gh_pages/'
+
+const workboxSWSrcPath = require.resolve('workbox-sw')
+const wbFileName = path.basename(workboxSWSrcPath)
+const workboxSWDestPath = `${buildPrefix}docs/4.1/assets/js/vendor/${wbFileName}`
+const workboxSWSrcMapPath = `${workboxSWSrcPath}.map`
+const workboxSWDestMapPath = `${workboxSWDestPath}.map`
+
+fs.createReadStream(workboxSWSrcPath).pipe(fs.createWriteStream(workboxSWDestPath))
+fs.createReadStream(workboxSWSrcMapPath).pipe(fs.createWriteStream(workboxSWDestMapPath))
+
+const updateUrl = (manifestEntries) => {
+ const manifest = manifestEntries.map((entry) => {
+ if (entry.url.startsWith(buildPrefix)) {
+ const regex = new RegExp(buildPrefix, 'g')
+ entry.url = entry.url.replace(regex, '')
+ }
+ return entry
+ })
+ return {
+ manifest,
+ warnings: []
+ }
+}
+
+config.manifestTransforms = [updateUrl]
+
+swBuild.injectManifest(config).then(({
+ count,
+ size
+}) => {
+ const wbSwRegex = /{fileName}/g
+ fs.readFile(config.swDest, 'utf8', (err, data) => {
+ if (err) {
+ throw err
+ }
+ const swFileContents = data.replace(wbSwRegex, wbFileName)
+ fs.writeFile(config.swDest, swFileContents, () => {
+ console.log(`Pre-cache Manifest generated. Pre-cached ${count} files, totalling ${size} bytes.`)
+ })
+ })
+}).catch((error) => {
+ console.error(`Something went wrong: ${error}`)
+})