├── favicon.ico ├── backdrop.jpg ├── og-image.jpg ├── favicon-16x16.png ├── favicon-32x32.png ├── mstile-150x150.png ├── team-photos ├── DD.jpg ├── DU.jpg ├── JC.jpg ├── PT.jpg └── CBH.jpg ├── apple-touch-icon.png ├── android-chrome-192x192.png ├── fontawesome ├── webfonts │ ├── fa-brands-400.eot │ ├── fa-brands-400.ttf │ ├── fa-solid-900.eot │ ├── fa-solid-900.ttf │ ├── fa-solid-900.woff │ ├── fa-brands-400.woff │ ├── fa-brands-400.woff2 │ ├── fa-regular-400.eot │ ├── fa-regular-400.ttf │ ├── fa-regular-400.woff │ ├── fa-regular-400.woff2 │ └── fa-solid-900.woff2 └── LICENSE.txt ├── fonts ├── comfortaa-v12-latin-regular.eot ├── comfortaa-v12-latin-regular.ttf ├── comfortaa-v12-latin-regular.woff └── comfortaa-v12-latin-regular.woff2 ├── browserconfig.xml ├── footer.php ├── site.webmanifest ├── .htaccess ├── app.yaml ├── LICENSE ├── web.config ├── viewResources.php ├── checkResourceLinks.php ├── devops-maturity-csv.php ├── renderAdvice.php ├── README.md ├── safari-pinned-tab.svg ├── collectResponses.php ├── survey.php ├── header.php ├── viewResults.php ├── about.php ├── js ├── popper.min.js └── bootstrap.min.js ├── questions.json └── advice.json /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atosorigin/DevOpsMaturityAssessment/HEAD/favicon.ico -------------------------------------------------------------------------------- /backdrop.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atosorigin/DevOpsMaturityAssessment/HEAD/backdrop.jpg -------------------------------------------------------------------------------- /og-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atosorigin/DevOpsMaturityAssessment/HEAD/og-image.jpg -------------------------------------------------------------------------------- /favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atosorigin/DevOpsMaturityAssessment/HEAD/favicon-16x16.png -------------------------------------------------------------------------------- /favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atosorigin/DevOpsMaturityAssessment/HEAD/favicon-32x32.png -------------------------------------------------------------------------------- /mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atosorigin/DevOpsMaturityAssessment/HEAD/mstile-150x150.png -------------------------------------------------------------------------------- /team-photos/DD.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atosorigin/DevOpsMaturityAssessment/HEAD/team-photos/DD.jpg -------------------------------------------------------------------------------- /team-photos/DU.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atosorigin/DevOpsMaturityAssessment/HEAD/team-photos/DU.jpg -------------------------------------------------------------------------------- /team-photos/JC.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atosorigin/DevOpsMaturityAssessment/HEAD/team-photos/JC.jpg -------------------------------------------------------------------------------- /team-photos/PT.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atosorigin/DevOpsMaturityAssessment/HEAD/team-photos/PT.jpg -------------------------------------------------------------------------------- /apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atosorigin/DevOpsMaturityAssessment/HEAD/apple-touch-icon.png -------------------------------------------------------------------------------- /team-photos/CBH.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atosorigin/DevOpsMaturityAssessment/HEAD/team-photos/CBH.jpg -------------------------------------------------------------------------------- /android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atosorigin/DevOpsMaturityAssessment/HEAD/android-chrome-192x192.png -------------------------------------------------------------------------------- /fontawesome/webfonts/fa-brands-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atosorigin/DevOpsMaturityAssessment/HEAD/fontawesome/webfonts/fa-brands-400.eot -------------------------------------------------------------------------------- /fontawesome/webfonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atosorigin/DevOpsMaturityAssessment/HEAD/fontawesome/webfonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /fontawesome/webfonts/fa-solid-900.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atosorigin/DevOpsMaturityAssessment/HEAD/fontawesome/webfonts/fa-solid-900.eot -------------------------------------------------------------------------------- /fontawesome/webfonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atosorigin/DevOpsMaturityAssessment/HEAD/fontawesome/webfonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /fontawesome/webfonts/fa-solid-900.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atosorigin/DevOpsMaturityAssessment/HEAD/fontawesome/webfonts/fa-solid-900.woff -------------------------------------------------------------------------------- /fonts/comfortaa-v12-latin-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atosorigin/DevOpsMaturityAssessment/HEAD/fonts/comfortaa-v12-latin-regular.eot -------------------------------------------------------------------------------- /fonts/comfortaa-v12-latin-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atosorigin/DevOpsMaturityAssessment/HEAD/fonts/comfortaa-v12-latin-regular.ttf -------------------------------------------------------------------------------- /fonts/comfortaa-v12-latin-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atosorigin/DevOpsMaturityAssessment/HEAD/fonts/comfortaa-v12-latin-regular.woff -------------------------------------------------------------------------------- /fontawesome/webfonts/fa-brands-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atosorigin/DevOpsMaturityAssessment/HEAD/fontawesome/webfonts/fa-brands-400.woff -------------------------------------------------------------------------------- /fontawesome/webfonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atosorigin/DevOpsMaturityAssessment/HEAD/fontawesome/webfonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /fontawesome/webfonts/fa-regular-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atosorigin/DevOpsMaturityAssessment/HEAD/fontawesome/webfonts/fa-regular-400.eot -------------------------------------------------------------------------------- /fontawesome/webfonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atosorigin/DevOpsMaturityAssessment/HEAD/fontawesome/webfonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /fontawesome/webfonts/fa-regular-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atosorigin/DevOpsMaturityAssessment/HEAD/fontawesome/webfonts/fa-regular-400.woff -------------------------------------------------------------------------------- /fontawesome/webfonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atosorigin/DevOpsMaturityAssessment/HEAD/fontawesome/webfonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /fontawesome/webfonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atosorigin/DevOpsMaturityAssessment/HEAD/fontawesome/webfonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /fonts/comfortaa-v12-latin-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atosorigin/DevOpsMaturityAssessment/HEAD/fonts/comfortaa-v12-latin-regular.woff2 -------------------------------------------------------------------------------- /browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #2d89ef 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /footer.php: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "DevOps Maturity", 3 | "short_name": "DevOps Maturity", 4 | "icons": [ 5 | { 6 | "src": "android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "theme_color": "#ffffff", 12 | "background_color": "#ffffff", 13 | "display": "standalone" 14 | } 15 | -------------------------------------------------------------------------------- /.htaccess: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Atos SE and Worldline 2 | # Licensed under MIT (https://github.com/atosorigin/DevOpsMaturityAssessment/blob/master/LICENSE) 3 | 4 | RewriteEngine On # Turn on the rewriting engine 5 | RewriteRule ^$ about.php [NC,L] 6 | RewriteRule ^section-.*$ collectResponses.php [NC,L] 7 | RewriteRule ^results.*$ viewResults.php [NC,L] 8 | RewriteRule ^about$ about.php [NC,L] 9 | RewriteRule ^resources$ viewResources.php [NC,L] -------------------------------------------------------------------------------- /app.yaml: -------------------------------------------------------------------------------- 1 | runtime: php55 2 | 3 | handlers: 4 | # Serve images as static resources. 5 | - url: /(.+\.(eot|svg|ttf|woff|woff2|css|js|gif|png|jpg|xml|ico|webmanifest))$ 6 | static_files: \1 7 | upload: .+\.(eot|svg|ttf|woff|woff2|css|js|gif|png|jpg|xml|ico|webmanifest)$ 8 | 9 | # Serve php scripts. 10 | - url: / 11 | script: about.php 12 | secure: always 13 | redirect_http_response_code: 301 14 | 15 | - url: /about 16 | script: about.php 17 | secure: always 18 | redirect_http_response_code: 301 19 | 20 | - url: /resources 21 | script: viewResources.php 22 | secure: always 23 | redirect_http_response_code: 301 24 | 25 | - url: /section-.*$ 26 | script: collectResponses.php 27 | secure: always 28 | redirect_http_response_code: 301 29 | 30 | - url: /results.*$ 31 | script: viewResults.php 32 | secure: always 33 | redirect_http_response_code: 301 34 | 35 | - url: /devops-maturity-csv.php 36 | script: devops-maturity-csv.php 37 | secure: always 38 | redirect_http_response_code: 301 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Atos SE and Worldline 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /viewResources.php: -------------------------------------------------------------------------------- 1 | 13 | 14 |
15 | 16 |
17 |
18 |
19 | 20 | $adviceSection) 23 | { 24 | if ( $adviceIndex != '//' ) { 25 | ?> 26 | 27 |
28 |
29 |
30 |
31 | 32 |
33 |
34 | 35 |
36 |
37 |
38 | 39 | 40 |
41 | 42 | 45 |
46 |
47 | 48 | 49 | 50 |
51 | 52 |
53 | 54 | 59 | 60 | -------------------------------------------------------------------------------- /fontawesome/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Font Awesome Free License 2 | ------------------------- 3 | 4 | Font Awesome Free is free, open source, and GPL friendly. You can use it for 5 | commercial projects, open source projects, or really almost whatever you want. 6 | Full Font Awesome Free license: https://fontawesome.com/license/free. 7 | 8 | # Icons: CC BY 4.0 License (https://creativecommons.org/licenses/by/4.0/) 9 | In the Font Awesome Free download, the CC BY 4.0 license applies to all icons 10 | packaged as SVG and JS file types. 11 | 12 | # Fonts: SIL OFL 1.1 License (https://scripts.sil.org/OFL) 13 | In the Font Awesome Free download, the SIL OLF license applies to all icons 14 | packaged as web and desktop font files. 15 | 16 | # Code: MIT License (https://opensource.org/licenses/MIT) 17 | In the Font Awesome Free download, the MIT license applies to all non-font and 18 | non-icon files. 19 | 20 | # Attribution 21 | Attribution is required by MIT, SIL OLF, and CC BY licenses. Downloaded Font 22 | Awesome Free files already contain embedded comments with sufficient 23 | attribution, so you shouldn't need to do anything additional when using these 24 | files normally. 25 | 26 | We've kept attribution comments terse, so we ask that you do not actively work 27 | to remove them from files, especially code. They're a great way for folks to 28 | learn about Font Awesome. 29 | 30 | # Brand Icons 31 | All brand icons are trademarks of their respective owners. The use of these 32 | trademarks does not indicate endorsement of the trademark holder by Font 33 | Awesome, nor vice versa. **Please do not use brand logos for any purpose except 34 | to represent the company, product, or service to which they refer.** 35 | -------------------------------------------------------------------------------- /checkResourceLinks.php: -------------------------------------------------------------------------------- 1 | 28 | 29 |
30 | 31 |
32 |
33 |
34 | 35 | $adviceSection) 40 | { 41 | if ( $adviceIndex != "//" ) 42 | { 43 | foreach ( $adviceSection['Links'] as $link ) 44 | { 45 | $counter++; 46 | $testText = ''; 47 | if ( CheckURL($link['Href']) ) 48 | { 49 | $testText = 'OK'; 50 | } 51 | else 52 | { 53 | $testText = 'Not Available'; 54 | } 55 | ?> 56 | 57 |

.

58 | 59 | 63 |
64 |
65 | 66 | 67 | 68 |
69 | 70 |
71 | 72 | 73 | 78 | 79 | -------------------------------------------------------------------------------- /devops-maturity-csv.php: -------------------------------------------------------------------------------- 1 | sections as $section) 21 | { 22 | foreach ( $section['Questions'] as $question) 23 | { 24 | // Only export questions that have at least one possible answer 25 | if ( isset($question['Answers']) ) 26 | { 27 | $subCategory = ''; 28 | if ( isset($question['SubCategory']) ) 29 | { 30 | $subCategory = $question['SubCategory']; 31 | } 32 | 33 | $answers = ''; 34 | $possibleAnswers = ''; 35 | switch ( $question['Type'] ) 36 | { 37 | case 'Option': 38 | $possibleAnswers = "Choose one of:\n"; 39 | break; 40 | case 'Checkbox': 41 | $possibleAnswers = "Choose all that apply:\n"; 42 | break; 43 | } 44 | 45 | foreach ( $question['Answers'] as $answer ) 46 | { 47 | $possibleAnswers .= $answer['Answer'] . ' (' . $answer['Score'] . ")\n"; // Show score for each answer in brackets 48 | if ( $answer['Value'] == 'checked' ) 49 | { 50 | $answers .= $answer['Answer'] . "\n"; 51 | } 52 | } 53 | // Remove trailing new lines 54 | $possibleAnswers = substr($possibleAnswers, 0, -1); 55 | $answers = substr($answers, 0, -1); 56 | 57 | $row = array( $section['SectionName'], 58 | $subCategory, 59 | $question['QuestionText'], 60 | $possibleAnswers, 61 | $survey->GetQuestionMaxScore($question), 62 | $answers, 63 | $survey->GetQuestionScore($question) 64 | ); 65 | fputcsv($output, $row); 66 | } 67 | } 68 | } 69 | 70 | ?> -------------------------------------------------------------------------------- /renderAdvice.php: -------------------------------------------------------------------------------- 1 | sections[$survey->SectionNameToIndex($sectionName)]['HasSubCategories'] ) 20 | { 21 | $detailedReportLink = '

See also detailed report for ' . 22 | $sectionName . '.'; 23 | } 24 | } 25 | 26 | // If there is "ReadMore" advice included, create a link for this 27 | $readMoreLink = ''; 28 | if ( isset($advice[$sectionName]['ReadMore']) ) 29 | { 30 | $readMoreAdvice = str_replace('"', '"', $advice[$sectionName]['ReadMore']); 31 | $readMoreAdvice = str_replace("'", '‘', $readMoreAdvice); 32 | $sectionNameNoSpace = str_replace(' ', '', $sectionName); 33 | $readMoreJS = "onclick=\"$('#$sectionNameNoSpace').html('$readMoreAdvice');\""; 34 | $readMoreLink = '

Show more advice >>'; 35 | } 36 | 37 | ?> 38 | 39 |

70 | 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DevOps Maturity Assessment 2 | 3 | ## Overview 4 | 5 | This is a simple, survey-based tool, to help teams assess where they currently are on their DevOps journey and to help them identify next steps for further improvement. 6 | 7 | ## Installation 8 | 9 | This is a PHP application that should run on any server that supports PHP 5.5 or higher with Mod_Rewrite enabled. We have also provided an [app.yaml](https://github.com/atosorigin/DevOpsMaturityAssessment/blob/master/app.yaml) for deployment into [Google App Engine](https://cloud.google.com/appengine/). 10 | 11 | ## How to Contribute 12 | 13 | Fork us and submit a pull request! If you are updating [questions.json](https://github.com/atosorigin/DevOpsMaturityAssessment/blob/master/questions.json) or [advice.json](https://github.com/atosorigin/DevOpsMaturityAssessment/blob/master/advice.json), please check that it passes a JSON validator (such as [JSONLint](https://jsonlint.com/)). 14 | 15 | If you would like to adjust colours/branding for your own purpose, please do this in a separate branch. For example, we maintain the atos-colours branch, but changes to the main code are always merged into atos-colours from master. 16 | 17 | ## Technical Overview 18 | 19 | * Survey questions are configured in [questions.json](https://github.com/atosorigin/DevOpsMaturityAssessment/blob/master/questions.json) 20 | * When a user first accesses the survey, all the questions are loaded into session storage 21 | * As the user completes the survey, their responses are saved in session storage 22 | * Loading questions, processing responses, and generating summary results is all managed by the Survey class defined in [survey.php](https://github.com/atosorigin/DevOpsMaturityAssessment/blob/master/survey.php) 23 | * Rendering of the survey is performed by [collectResponses.php](https://github.com/atosorigin/DevOpsMaturityAssessment/blob/master/collectResponses.php) 24 | * Rendering of the survey results is performed by [viewResults.php](https://github.com/atosorigin/DevOpsMaturityAssessment/blob/master/viewResults.php) 25 | * Layout uses customised [Bootstrap](http://getbootstrap.com/) 4.1.3 26 | * Rendering charts uses [Chart.js](https://www.chartjs.org/) 2.7.2 27 | * Icons from [Font Awesome Free](https://fontawesome.com/free) 5.3.1 28 | 29 | ## License 30 | 31 | This source code is released under the [MIT license](https://github.com/atosorigin/DevOpsMaturityAssessment/blob/master/LICENSE). Bootstrap and Chart.js are also released under the [MIT license](https://github.com/atosorigin/DevOpsMaturityAssessment/blob/master/LICENSE). Font Awesome Free and Comfortaa is provided under the [SIL OFL 1.1 License](https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL) 32 | 33 | ## Credits 34 | 35 | * Atos and Worldline experts who have contributed to formulation of the questions and creation of the application 36 | * [Bootstrap](http://getbootstrap.com/) 37 | * [Chart.js](https://www.chartjs.org/) 38 | * [Font Awesome Free](https://fontawesome.com/free) 39 | * [Comfortaa Font](https://github.com/alexeiva/comfortaa) 40 | * [Markus Spiske](https://unsplash.com/@markusspiske) for background image, published on [Unsplash](https://unsplash.com/) 41 | * [Vojtech Bruzek](https://unsplash.com/@vojtechbruzek) for og-image.jpg, published on [Unsplash](https://unsplash.com/) -------------------------------------------------------------------------------- /safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.11, written by Peter Selinger 2001-2013 9 | 10 | 12 | 19 | 22 | 24 | 34 | 47 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /collectResponses.php: -------------------------------------------------------------------------------- 1 | 9 | 10 |
11 |
12 | 13 | sections as $index=>$section) 22 | { 23 | if ( SectionnameToURLName($section['SectionName']) == $currentSection ) 24 | { 25 | $sectionIndex = $index; 26 | } 27 | } 28 | 29 | // Determine the URL names for the next and previous sections 30 | $nextSection = ''; 31 | if ( $sectionIndexsections)-1 ) 32 | { 33 | $nextSection = SectionnameToURLName($survey->sections[$sectionIndex + 1]['SectionName']); 34 | } 35 | $previousSection = ''; 36 | if ( $sectionIndex>0 ) 37 | { 38 | $previousSection = SectionnameToURLName($survey->sections[$sectionIndex - 1]['SectionName']); 39 | } 40 | ?> 41 | 42 |
43 |
44 |

sections[$sectionIndex]['SectionName']?>

45 | 46 | 47 | sections[$sectionIndex]['Questions'] as $index=>$question) 50 | { 51 | renderQuestion($question, $index); 52 | } 53 | ?> 54 | 55 |
56 | 57 |
58 | 59 |
60 |
61 |
62 | 63 |
64 | 65 |
66 | 67 | 68 |
69 | 70 |
71 | 72 |
73 | 74 | 75 | 76 | 77 |
78 |
79 | 80 | 81 |
82 | 83 | 90 | 91 |
92 | 93 |
94 | 95 |
96 | 108 | 109 |
110 |
111 | 112 | 113 | $answer) { ?> 120 |
121 | > 122 | 123 | 124 |
125 | $answer) { ?> 132 |
133 | > 134 | 135 |
136 | 140 | 141 | -------------------------------------------------------------------------------- /survey.php: -------------------------------------------------------------------------------- 1 | sections = &$_SESSION['Sections']; 23 | $this->SetupAnswerIDs(); // TODO: This should only be called first time we setup the Sections sesssion variable 24 | $this->SaveResponses(); 25 | } 26 | 27 | public function GenerateResultsSummary() 28 | { 29 | foreach ($this->sections as $section) 30 | { 31 | $summaryResults[$section['SectionName']] = array('MaxScore'=>0, 'Score'=>0, 'ScorePercentage'=>0); 32 | if ( isset($section['SpiderPos']) ) 33 | { 34 | $summaryResults[$section['SectionName']]['SpiderPos'] = $section['SpiderPos']; 35 | } 36 | 37 | foreach ($section['Questions'] as $question) 38 | { 39 | $summaryResults[$section['SectionName']]['MaxScore'] += $this->GetQuestionMaxScore($question); 40 | $summaryResults[$section['SectionName']]['Score'] += $this->GetQuestionScore($question); 41 | } 42 | 43 | if ( $summaryResults[$section['SectionName']]['MaxScore'] != 0 ) 44 | { 45 | $summaryResults[$section['SectionName']]['ScorePercentage'] = 46 | round( $summaryResults[$section['SectionName']]['Score'] / 47 | $summaryResults[$section['SectionName']]['MaxScore'] * 100); 48 | } 49 | 50 | // Do not include sections where you cannot score (i.e. MaxScore == 0) 51 | if ( $summaryResults[$section['SectionName']]['MaxScore'] == 0 ) 52 | { 53 | unset($summaryResults[$section['SectionName']]); 54 | } 55 | } 56 | 57 | return $summaryResults; 58 | } 59 | 60 | // returns summary results for the sub-categories in a specified section 61 | public function GenerateSubCategorySummary($sectionName) 62 | { 63 | foreach ($this->sections as $section) 64 | { 65 | if ( $section['SectionName'] == $sectionName ) 66 | { 67 | foreach ($section['Questions'] as $question) 68 | { 69 | if ( isset($question['SubCategory']) ) 70 | { 71 | if ( !isset($summaryResults[$question['SubCategory']]) ) 72 | { 73 | // If we haven't yet added an entry into the summary results for this sub-category, then add one 74 | $summaryResults[$question['SubCategory']] = array('MaxScore'=>0, 'Score'=>0, 'ScorePercentage'=>0); 75 | } 76 | 77 | $summaryResults[$question['SubCategory']]['MaxScore'] += $this->GetQuestionMaxScore($question); 78 | $summaryResults[$question['SubCategory']]['Score'] += $this->GetQuestionScore($question); 79 | } 80 | } 81 | } 82 | } 83 | 84 | foreach ($summaryResults as &$subCategory) 85 | { 86 | $subCategory['ScorePercentage'] = 87 | round( $subCategory['Score'] / $subCategory['MaxScore'] * 100); 88 | } 89 | 90 | return $summaryResults; 91 | } 92 | 93 | public function GetQuestionMaxScore($question) 94 | { 95 | $maxScore = 0; 96 | if ($question['Type'] != 'Banner') 97 | { 98 | foreach ($question['Answers'] as $answer) 99 | { 100 | if ($question['Type'] == 'Option') 101 | { 102 | if ($answer['Score'] > $maxScore) 103 | { 104 | $maxScore = $answer['Score']; 105 | } 106 | } 107 | if ($question['Type'] == 'Checkbox') 108 | { 109 | $maxScore += $answer['Score']; 110 | } 111 | } 112 | } 113 | 114 | return $maxScore; 115 | } 116 | 117 | public function GetQuestionScore($question) 118 | { 119 | $score = 0; 120 | if ($question['Type'] != 'Banner') 121 | { 122 | foreach ($question['Answers'] as $answer) 123 | { 124 | if ($answer['Value'] == 'checked') 125 | { 126 | $score += $answer['Score']; 127 | } 128 | } 129 | } 130 | 131 | return $score; 132 | } 133 | 134 | public function SectionNameToIndex($sectionName) 135 | { 136 | $sectionIndex = 0; 137 | foreach ($this->sections as $index=>$section) 138 | { 139 | if ( $section['SectionName'] == $sectionName ) 140 | { 141 | $sectionIndex = $index; 142 | break; 143 | } 144 | } 145 | return $sectionIndex; 146 | } 147 | 148 | private function SetupAnswerIDs() 149 | { 150 | // Loop through the model and assign a unique ID to each question and answer to assist with form rendering and submission 151 | foreach ($this->sections as $sectionIndex=>&$section) 152 | { 153 | if ( !isset($section['HasSubCategories']) ) 154 | { 155 | $section['HasSubCategories'] = FALSE; 156 | } 157 | foreach ($section['Questions'] as $questionIndex=>&$question) 158 | { 159 | if ( $question['Type'] != 'Banner') 160 | { 161 | $question['ID'] = 'S' . ($sectionIndex + 1) . '-Q' . ($questionIndex + 1); 162 | 163 | if ( !isset($question['Answers']) ) 164 | { 165 | // Add default yes/no answers 166 | $question['Answers'] = array( array('Answer' => 'Yes', 'Score' => 1), array('Answer' => 'No', 'Score' => 0) ); 167 | } 168 | 169 | foreach ($question['Answers'] as $answerIndex=>&$answer) 170 | { 171 | $answer['ID'] = 'S' . ($sectionIndex + 1) . '-Q' . ($questionIndex + 1) . '-A' . ($answerIndex + 1); 172 | if (!isset($answer['Value'])) 173 | { 174 | $answer['Value'] = ''; 175 | } 176 | } 177 | } 178 | if ( isset($question['SubCategory']) ) 179 | { 180 | $section['HasSubCategories'] = TRUE; 181 | } 182 | } 183 | } 184 | } 185 | 186 | private function SaveResponses() 187 | { 188 | // Loop through each question in our session storage and, if we find post variable matching the question ID, then save the answer 189 | foreach ($this->sections as $sectionIndex=>&$section) 190 | { 191 | foreach ($section['Questions'] as $questionIndex=>&$question) 192 | { 193 | if ( $question['Type'] == 'Option' ) 194 | { 195 | if ( isset($_POST[$question['ID']]) ) 196 | { 197 | foreach ($question['Answers'] as $answerIndex=>&$answer) 198 | { 199 | if ( $answer['ID'] == $_POST[$question['ID']] ) 200 | { 201 | $answer['Value'] = 'checked'; 202 | } 203 | else 204 | { 205 | $answer['Value'] = ''; 206 | } 207 | } 208 | } 209 | } 210 | 211 | if ( $question['Type'] == 'Checkbox' ) 212 | { 213 | foreach ($question['Answers'] as $answerIndex=>&$answer) 214 | { 215 | // If hidden field is there then we can use the presense of the non-hidden field to determine if the checkbox was checked 216 | if ( isset($_POST[$answer['ID'] . '-hidden']) ) 217 | { 218 | if ( isset($_POST[$answer['ID']] ) ) 219 | { 220 | $answer['Value'] = 'checked'; 221 | } 222 | else 223 | { 224 | $answer['Value'] = ''; 225 | } 226 | } 227 | } 228 | } 229 | } 230 | } 231 | } 232 | 233 | } 234 | 235 | ?> -------------------------------------------------------------------------------- /header.php: -------------------------------------------------------------------------------- 1 | array ('Url' => 'section-' . SectionNameToURLName($survey->sections[0]['SectionName']), 'Type' => 'Standard'), 12 | 'Sections' => array ('Type' => 'Dropdown' ), 13 | // Sub-menus for each page are added here (see below) 14 | 'Results' => array ('Url' => 'results', 'Type' => 'Standard' ), 15 | 'Detailed Reports' => array ('Type' => 'Dropdown', 'Items' => array ( 16 | 'Download CSV' => array('Url' => 'devops-maturity-csv.php', 'Type' => 'Standard'), 17 | 'Divider1' => array('Type' =>'Divider') ) ), 18 | // Sub-menus for detailed reports are added here, see below 19 | 'Resources' => array ('Url' => 'resources', 'Type' => 'Standard' ), 20 | 'About' => array ('Url' => 'about', 'Type' => 'Standard' ) ); 21 | 22 | // Add the sub-menus for each page of the survey, and also for the detailed reports 23 | foreach ($survey->sections as $section) 24 | { 25 | $navBar['Sections']['Items'][$section['SectionName']]['Url'] = 'section-' . SectionNameToURLName($section['SectionName']); 26 | $navBar['Sections']['Items'][$section['SectionName']]['Type'] = 'Standard'; 27 | if ( $section['HasSubCategories'] ) 28 | { 29 | $navBar['Detailed Reports']['Items'][$section['SectionName']]['Url'] = 'results-' . SectionNameToURLName($section['SectionName']); 30 | $navBar['Detailed Reports']['Items'][$section['SectionName']]['Type'] = 'Standard'; 31 | } 32 | } 33 | 34 | function GetBaseURL() 35 | { 36 | // Routine based on https://wp-mix.com/php-absolute-path-document-root-base-url/ 37 | 38 | $doc_root = str_replace($_SERVER['SCRIPT_NAME'], '', $_SERVER['SCRIPT_FILENAME']); 39 | //$doc_root = str_replace($doc_root, "\\", "\\"); 40 | 41 | // base directory 42 | $base_dir = __DIR__; 43 | $base_dir = str_replace("\\", "/", $base_dir); 44 | 45 | // server protocol 46 | $protocol = empty($_SERVER['HTTPS']) ? 'http' : 'https'; 47 | 48 | // domain name 49 | $domain = $_SERVER['SERVER_NAME']; 50 | 51 | // base url 52 | $base_url = str_replace($doc_root, '', $base_dir); 53 | 54 | // server port 55 | $port = $_SERVER['SERVER_PORT']; 56 | $disp_port = ($protocol == 'http' && $port == 80 || $protocol == 'https' && $port == 443) ? '' : ":$port"; 57 | 58 | // put em all together to get the complete base URL 59 | return $protocol . "://" . $domain . $disp_port . $base_url; 60 | 61 | } 62 | 63 | function SectionNameToURLName($sectionName) { 64 | return strtolower(str_replace(',', '', str_replace(' ', '-', $sectionName))); 65 | } 66 | 67 | function RenderNavBarButtons($navBar) 68 | { 69 | foreach ($navBar as $index=>$navBarButton) 70 | { 71 | switch ( $navBarButton['Type'] ) { 72 | case 'Standard': 73 | RenderStandardNavBarButton($index, $navBarButton['Url']); 74 | break; 75 | case 'Dropdown': 76 | RenderDropdownNavBarButton($index, $navBarButton); 77 | break; 78 | } 79 | } 80 | } 81 | 82 | function OnClickHandler($url) 83 | { 84 | global $isForm; 85 | if ( $isForm ) 86 | { 87 | // If the page contains a form then we need to set the form action and submit 88 | return "$('form').attr('action', '$url'); $('form').submit();"; 89 | } 90 | else 91 | { 92 | // If the page is not a form then just navigate to the right URL 93 | return "window.location = '$url';"; 94 | } 95 | } 96 | 97 | function RenderStandardNavBarButton($buttonText, $url) 98 | { 99 | // Check if this is the button for the current page, and if so style it accordingly 100 | global $activePage; 101 | $active = ''; 102 | if ($activePage == $buttonText) 103 | { 104 | $active = ' active'; 105 | } 106 | ?> 107 |
  • 108 | 109 |
  • 110 | 123 | 140 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | DevOps Maturity Assessment 174 | 175 | 176 | 192 | 193 | 194 | 195 | 196 | 197 | 208 | 209 | -------------------------------------------------------------------------------- /viewResults.php: -------------------------------------------------------------------------------- 1 | GenerateResultsSummary(); 25 | // Sort into the order they should be displayed on the spider diagram 26 | uasort( $resultsSummary, function($a, $b) { return $a['SpiderPos'] - $b['SpiderPos']; } ); 27 | $chartTitle = 'DevOps Maturity by Area'; 28 | } 29 | else 30 | { 31 | // Need to find the name of the section we want to view 32 | foreach ($survey->sections as $section) 33 | { 34 | if ( SectionnameToURLName($section['SectionName']) == $sectionURL ) 35 | { 36 | $sectionName = $section['SectionName']; 37 | } 38 | } 39 | $resultsSummary = $survey->GenerateSubCategorySummary($sectionName); 40 | $chartTitle = 'Breakdown for ' . $sectionName; 41 | } 42 | 43 | // Create one variable with the labels and one with the data 44 | $labels = '['; 45 | $data = '['; 46 | 47 | foreach ($resultsSummary as $sectionName=>$result) 48 | { 49 | $labels .= '"' . $sectionName . '",'; 50 | $data .= $result['ScorePercentage'] . ','; 51 | } 52 | 53 | // Replace trailing comma with closing square bracket 54 | $labels = substr($labels, 0, -1) . ']'; 55 | $data = substr($data, 0, -1) . ']'; 56 | 57 | // Now sort by highest to lowest score 58 | uasort( $resultsSummary, function($a, $b) { return $b['ScorePercentage'] - $a['ScorePercentage']; } ); 59 | 60 | // Now create the preamble, telling people about strengths and weaknesses 61 | $preAmble = ''; 62 | switch ( count($resultsSummary) ) 63 | { 64 | case 3: 65 | $preAmble = '

    Please find below links to resources that you may find useful for each of these areas.

    '; 66 | break; 67 | case 4: 68 | $preAmble = '

    The responses to the questionaire show that the area in which you are strongest is ' . array_keys($resultsSummary)[0] . 69 | '.

    The 3 areas where you have the most potential to improve are listed below, together with links to resources that you may find useful.

    '; 70 | break; 71 | case 5: 72 | $preAmble = '

    The responses to the questionaire show that the 2 areas in which you are strongest are ' . array_keys($resultsSummary)[0] . 73 | ' and ' . array_keys($resultsSummary)[1] . '.

    ' . 74 | '

    The 3 areas where you have the most potential to improve are listed below, together with links to resources that you may find useful.

    '; 75 | break; 76 | default: 77 | $preAmble = '

    The responses to the questionaire show that the 3 areas in which you are strongest are ' . array_keys($resultsSummary)[0] . 78 | ', ' . array_keys($resultsSummary)[1] . ' and ' . array_keys($resultsSummary)[2] . '.

    ' . 79 | '

    The 3 areas where you have the most potential to improve are listed below, together with links to resources that you may find useful.

    '; 80 | break; 81 | } 82 | 83 | ?> 84 | 85 |
    86 | 87 |
    88 |
    89 |
    90 | 91 |
    92 |
    93 |
    94 | 95 |
    96 |
    97 |
    98 |
    99 |
    100 | 101 |
    102 |
    103 | 104 | 108 | 109 |
    110 |
    111 |
    112 |
    113 |
    114 | 115 |
    116 |
    117 |
    118 | 119 |
    120 |
    121 | 124 |
    125 |
    126 |
    127 | 128 |
    129 |
    130 | 131 |
    132 | 135 |
    136 |
    137 |
    138 |
    139 | 140 |
    141 |
    142 |
    143 |
    144 | 145 |
    146 |
    147 | 148 |
    149 | 152 |
    153 |
    154 | 155 | 156 |
    157 | 158 |
    159 |
    160 | 161 | 162 | 163 |
    164 | 165 |
    166 | 167 | 233 | 234 | 239 | 240 | -------------------------------------------------------------------------------- /about.php: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 35 | 36 |
    37 |
    38 |
    39 | 40 | 41 |
    42 |
    43 |

    Improve Your DevOps Capability

    44 |

    This online DevOps Maturity Assessment questionnaire will help you understand your current strengths and weaknesses and then recommend resources that can support you in taking the next steps on your DevOps journey.

    45 |

    46 | Start the Questionnaire 47 | Fork us on GitHub 48 |

    49 |
    50 |
    51 | 52 | 53 |
    54 | 55 |
    56 | 57 | 58 | 59 | 60 |

    Understand Where You Are

    61 |

    Our set of carefully designed questions across 7 different areas will help you quickly establish your current level of DevOps maturity.

    62 |

    You can view the results online as well as downloading them in CSV format for more detailed analysis.

    63 |
    64 | 65 |
    66 | 67 | 68 | 69 | 70 |

    Identify Your Next Steps

    71 |

    For each area we have identified a range of free or commercially available books, videos, blog posts, white papers and websites that will help you take the next steps on your DevOps journey.

    72 |
    73 | 74 | 75 |
    76 | 77 | 78 | 79 | 80 |

    Free and Open Source

    81 |

    This tool is made available under the MIT License: you are free to use, adapt and redistribute it, both for commercial and non-commercial use. There is no obligation to share your changes, although we always appreciate feedback! Why not fork us on GitHub?

    82 | 83 |
    84 | 85 |
    86 | 87 |
    88 |
    89 |

    We do not harvest your data and we will not share your results with anyone else.

    90 |
    91 |
    92 | 93 |
    94 |
    95 |

    Meet The Team

    96 |

    This tool was created by members of the Atos Expert Community with contributions from many other practitioners across Atos and Worldline globally. You can find out more about the core team below.

    97 |
    98 |
    99 | 100 |
    101 | 102 |
    103 | 104 |
    105 | 106 |
    107 |
    108 | Generic placeholder image 109 |
    110 |
    111 |
    Chris Baynham-Hughes
    112 |

    Head of UK Business Development RedHat Emerging Technologies & DevOps at Atos

    113 |
    114 | 118 |
    119 | 120 | 121 |
    122 |
    123 | Generic placeholder image 124 |
    125 | 126 |
    127 |
    John Chatterton
    128 |

    Principal Enterprise Architect

    129 |
    130 | 133 |
    134 | 135 | 136 |
    137 |
    138 | Generic placeholder image 139 |
    140 |
    141 |
    David Daly
    142 |

    Global Deal Assurance Manager at Worldline

    143 |
    144 | 148 |
    149 | 150 | 151 |
    152 | 153 |
    154 |
    155 |
    156 | 157 |
    158 |
    159 | 160 |
    161 | 162 |
    163 |
    164 | Generic placeholder image 165 |
    166 |
    167 |
    Panagiotis Tamtamis
    168 |

    Senior Software Engineer at Atos

    169 |
    170 | 174 |
    175 | 176 | 177 |
    178 |
    179 | Generic placeholder image 180 |
    181 | 182 |
    183 |
    Dan Usher
    184 |

    Head of Transformation, Digital Self Service at Worldline UK&I

    185 |
    186 | 190 |
    191 | 192 | 193 |
    194 | 195 | 196 |
    197 |
    198 |
    199 | 200 | 201 | 202 |
    203 | 204 |
    205 | 206 |
    207 | 208 | 213 | 214 | -------------------------------------------------------------------------------- /js/popper.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) Federico Zivolo 2018 3 | Distributed under the MIT License (license terms are at http://opensource.org/licenses/MIT). 4 | */(function(e,t){'object'==typeof exports&&'undefined'!=typeof module?module.exports=t():'function'==typeof define&&define.amd?define(t):e.Popper=t()})(this,function(){'use strict';function e(e){return e&&'[object Function]'==={}.toString.call(e)}function t(e,t){if(1!==e.nodeType)return[];var o=getComputedStyle(e,null);return t?o[t]:o}function o(e){return'HTML'===e.nodeName?e:e.parentNode||e.host}function n(e){if(!e)return document.body;switch(e.nodeName){case'HTML':case'BODY':return e.ownerDocument.body;case'#document':return e.body;}var i=t(e),r=i.overflow,p=i.overflowX,s=i.overflowY;return /(auto|scroll|overlay)/.test(r+s+p)?e:n(o(e))}function r(e){return 11===e?re:10===e?pe:re||pe}function p(e){if(!e)return document.documentElement;for(var o=r(10)?document.body:null,n=e.offsetParent;n===o&&e.nextElementSibling;)n=(e=e.nextElementSibling).offsetParent;var i=n&&n.nodeName;return i&&'BODY'!==i&&'HTML'!==i?-1!==['TD','TABLE'].indexOf(n.nodeName)&&'static'===t(n,'position')?p(n):n:e?e.ownerDocument.documentElement:document.documentElement}function s(e){var t=e.nodeName;return'BODY'!==t&&('HTML'===t||p(e.firstElementChild)===e)}function d(e){return null===e.parentNode?e:d(e.parentNode)}function a(e,t){if(!e||!e.nodeType||!t||!t.nodeType)return document.documentElement;var o=e.compareDocumentPosition(t)&Node.DOCUMENT_POSITION_FOLLOWING,n=o?e:t,i=o?t:e,r=document.createRange();r.setStart(n,0),r.setEnd(i,0);var l=r.commonAncestorContainer;if(e!==l&&t!==l||n.contains(i))return s(l)?l:p(l);var f=d(e);return f.host?a(f.host,t):a(e,d(t).host)}function l(e){var t=1=o.clientWidth&&n>=o.clientHeight}),l=0a[e]&&!t.escapeWithReference&&(n=Q(f[o],a[e]-('right'===e?f.width:f.height))),ae({},o,n)}};return l.forEach(function(e){var t=-1===['left','top'].indexOf(e)?'secondary':'primary';f=le({},f,m[t](e))}),e.offsets.popper=f,e},priority:['left','right','top','bottom'],padding:5,boundariesElement:'scrollParent'},keepTogether:{order:400,enabled:!0,fn:function(e){var t=e.offsets,o=t.popper,n=t.reference,i=e.placement.split('-')[0],r=$,p=-1!==['top','bottom'].indexOf(i),s=p?'right':'bottom',d=p?'left':'top',a=p?'width':'height';return o[s]r(n[s])&&(e.offsets.popper[d]=r(n[s])),e}},arrow:{order:500,enabled:!0,fn:function(e,o){var n;if(!q(e.instance.modifiers,'arrow','keepTogether'))return e;var i=o.element;if('string'==typeof i){if(i=e.instance.popper.querySelector(i),!i)return e;}else if(!e.instance.popper.contains(i))return console.warn('WARNING: `arrow.element` must be child of its popper element!'),e;var r=e.placement.split('-')[0],p=e.offsets,s=p.popper,d=p.reference,a=-1!==['left','right'].indexOf(r),l=a?'height':'width',f=a?'Top':'Left',m=f.toLowerCase(),h=a?'left':'top',c=a?'bottom':'right',u=S(i)[l];d[c]-us[c]&&(e.offsets.popper[m]+=d[m]+u-s[c]),e.offsets.popper=g(e.offsets.popper);var b=d[m]+d[l]/2-u/2,y=t(e.instance.popper),w=parseFloat(y['margin'+f],10),E=parseFloat(y['border'+f+'Width'],10),v=b-e.offsets.popper[m]-w-E;return v=J(Q(s[l]-u,v),0),e.arrowElement=i,e.offsets.arrow=(n={},ae(n,m,Z(v)),ae(n,h,''),n),e},element:'[x-arrow]'},flip:{order:600,enabled:!0,fn:function(e,t){if(W(e.instance.modifiers,'inner'))return e;if(e.flipped&&e.placement===e.originalPlacement)return e;var o=v(e.instance.popper,e.instance.reference,t.padding,t.boundariesElement,e.positionFixed),n=e.placement.split('-')[0],i=T(n),r=e.placement.split('-')[1]||'',p=[];switch(t.behavior){case he.FLIP:p=[n,i];break;case he.CLOCKWISE:p=V(n);break;case he.COUNTERCLOCKWISE:p=V(n,!0);break;default:p=t.behavior;}return p.forEach(function(s,d){if(n!==s||p.length===d+1)return e;n=e.placement.split('-')[0],i=T(n);var a=e.offsets.popper,l=e.offsets.reference,f=$,m='left'===n&&f(a.right)>f(l.left)||'right'===n&&f(a.left)f(l.top)||'bottom'===n&&f(a.top)f(o.right),g=f(a.top)f(o.bottom),b='left'===n&&h||'right'===n&&c||'top'===n&&g||'bottom'===n&&u,y=-1!==['top','bottom'].indexOf(n),w=!!t.flipVariations&&(y&&'start'===r&&h||y&&'end'===r&&c||!y&&'start'===r&&g||!y&&'end'===r&&u);(m||b||w)&&(e.flipped=!0,(m||b)&&(n=p[d+1]),w&&(r=G(r)),e.placement=n+(r?'-'+r:''),e.offsets.popper=le({},e.offsets.popper,D(e.instance.popper,e.offsets.reference,e.placement)),e=P(e.instance.modifiers,e,'flip'))}),e},behavior:'flip',padding:5,boundariesElement:'viewport'},inner:{order:700,enabled:!1,fn:function(e){var t=e.placement,o=t.split('-')[0],n=e.offsets,i=n.popper,r=n.reference,p=-1!==['left','right'].indexOf(o),s=-1===['top','left'].indexOf(o);return i[p?'left':'top']=r[o]-(s?i[p?'width':'height']:0),e.placement=T(t),e.offsets.popper=g(i),e}},hide:{order:800,enabled:!0,fn:function(e){if(!q(e.instance.modifiers,'hide','preventOverflow'))return e;var t=e.offsets.reference,o=C(e.instance.modifiers,function(e){return'preventOverflow'===e.name}).boundaries;if(t.bottomo.right||t.top>o.bottom||t.right
    These questions are intended to be completed for one team (typically reporting to the same line manager and usually consisting of between 5 and 15 people)." 10 | } 11 | ] 12 | }, 13 | { 14 | "SectionName" : "Team Agility", 15 | "SpiderPos" : 2, 16 | "Questions" : [ 17 | { 18 | "Type" : "Option", 19 | "QuestionText" : "Does the team have a new, potentially shippable, version of the product available every 1-2 weeks?" 20 | }, 21 | { 22 | "Type" : "Checkbox", 23 | "QuestionText" : "Which of the following are measured by the team (tick all that apply)?", 24 | "Answers" : [ 25 | {"Answer" : "Elapsed lead time to deliver valuable changes (from initial request to production)", "Score" : 0.5}, 26 | {"Answer" : "Frequency of deployments into production", "Score" : 0.5}, 27 | {"Answer" : "Change failure rate", "Score" : 0.5}, 28 | {"Answer" : "Time to restore service after a failure", "Score" : 0.5} 29 | ] 30 | }, 31 | { 32 | "Type" : "Option", 33 | "QuestionText" : "Does the team regularly meet to discuss what is working well, what isn't working well and what they can improve, and the top improvement items are implemented?" 34 | }, 35 | { 36 | "Type" : "Option", 37 | "QuestionText" : "Does the team take actions to ensure that the team does not create or experience bottlenecks with/for other teams?", 38 | "Answers" : [ 39 | {"Answer" : "Yes, and the actions are effective", "Score" : 1}, 40 | {"Answer" : "Yes, but the actions are not always effective", "Score" : 0.5}, 41 | {"Answer" : "No", "Score" : 0} 42 | ] 43 | }, 44 | { 45 | "Type" : "Option", 46 | "QuestionText" : "Are any work items that are blocked swiftly identified and then people collaborate to rectify the situation?" 47 | }, 48 | { 49 | "Type" : "Option", 50 | "QuestionText" : "Is there a clearly defined mechanism for prioritising the backlog?" 51 | }, 52 | { 53 | "Type" : "Option", 54 | "QuestionText" : "Does the team work on the highest priority items in the backlog?" 55 | }, 56 | { 57 | "Type" : "Option", 58 | "QuestionText" : "Are the most experienced team members allocated last so they can help others develop cross functional skills and be free to focus on the most business critical or complex problems?" 59 | }, 60 | { 61 | "Type" : "Checkbox", 62 | "QuestionText" : "Does the team have fast feedback loops in place (tick all that apply)?", 63 | "Answers" : [ 64 | {"Answer" : "From testers: usually less than 1 day", "Score" : 0.5}, 65 | {"Answer" : "From the product owner: usually less than 3 days", "Score" : 0.5}, 66 | {"Answer" : "From customers: usually less than 2 weeks", "Score" : 0.5}, 67 | {"Answer" : "From end users: usually less than 2 weeks", "Score" : 0.5} 68 | ] 69 | }, 70 | { 71 | "Type" : "Option", 72 | "QuestionText" : "Are there proactive steps taken to ensure there is no major dependency on \"super heroes\" (e.g. pair programming, mob learning, real options)?" 73 | } 74 | ] 75 | }, 76 | { 77 | "SectionName" : "Collaboration", 78 | "SpiderPos" : 7, 79 | "Questions" : [ 80 | { 81 | "Type" : "Option", 82 | "QuestionText" : "Are knowledge and interests shared within the team and with other teams within the organisation (for example via communities of interest)?", 83 | "Answers" : [ 84 | {"Answer" : "Yes", "Score" : 1}, 85 | {"Answer" : "Yes, but only within the team", "Score" : 0.5}, 86 | {"Answer" : "No", "Score" : 1} 87 | ] 88 | }, 89 | { 90 | "Type" : "Option", 91 | "QuestionText" : "Does the team have methods in place for asynchronous communication (for example Kanban Board, JIRA, Slack, Circuit)?" 92 | }, 93 | { 94 | "Type" : "Option", 95 | "QuestionText" : "Do people on the team have mechanisms to collaborate with people outside of the team?" 96 | }, 97 | { 98 | "Type" : "Option", 99 | "QuestionText" : "Are people on the team willing to work outside their usual specialism?", 100 | "Answers" : [ 101 | {"Answer" : "Everyone on the team is willing to do this", "Score" : 1}, 102 | {"Answer" : "Some people on the team are willing to do this", "Score" : 0.5}, 103 | {"Answer" : "Generally people on the team prefer not to do this", "Score" : 0} 104 | ] 105 | }, 106 | { 107 | "Type" : "Option", 108 | "QuestionText" : "Do people on the team have a preference towards the most immediate (information rich) comunication method available (e.g. voice call rather than email)?", 109 | "Answers" : [ 110 | {"Answer" : "Everyone on the team does", "Score" : 1}, 111 | {"Answer" : "Most people on the team do", "Score" : 0.5}, 112 | {"Answer" : "Most people on the team do not", "Score" : 0} 113 | ] 114 | }, 115 | { 116 | "Type" : "Option", 117 | "QuestionText" : "Is there sufficient opportunity for people on the team to meet face to face?" 118 | }, 119 | { 120 | "Type" : "Option", 121 | "QuestionText" : "How frequently are there misunderstandings between members of the team?", 122 | "Answers" : [ 123 | {"Answer" : "Hardly ever", "Score" : 1}, 124 | {"Answer" : "Fairly frequently (at least once per week)", "Score" : 0.5}, 125 | {"Answer" : "Very frequently (at least once per day)", "Score" : 0} 126 | ] 127 | }, 128 | { 129 | "Type" : "Option", 130 | "QuestionText" : "Do people on the team share their ideas/concerns with the rest of the team and are they fairly represented?", 131 | "Answers" : [ 132 | {"Answer" : "Yes, always", "Score" : 1}, 133 | {"Answer" : "Yes, most of the time", "Score" : 0.5}, 134 | {"Answer" : "Hardly ever", "Score" : 0} 135 | ] 136 | } 137 | ] 138 | }, 139 | { 140 | "SectionName" : "Automation", 141 | "SpiderPos" : 3, 142 | "Questions" : [ 143 | { 144 | "Type" : "Option", 145 | "SubCategory" : "Environments", 146 | "QuestionText" : "Are development and test environments consistent with production environments?" 147 | }, 148 | { 149 | "Type" : "Option", 150 | "QuestionText" : "Is the provisioning, configuration and management of infrastructure (e.g. networks, storage, etc.) automated (for example by using Infrastructure as Code)?", 151 | "Answers" : [ 152 | {"Answer" : "Yes", "Score" : 1}, 153 | {"Answer" : "Partially", "Score" : 0.5}, 154 | {"Answer" : "No", "Score" : 0} 155 | ] 156 | }, 157 | { 158 | "Type" : "Checkbox", 159 | "SubCategory" : "Environments", 160 | "QuestionText" : "For which of these is the configuration and management of environments automated (tick all that apply)?", 161 | "Answers" : [ 162 | {"Answer" : "Virtual machines", "Score" : 0.5}, 163 | {"Answer" : "Networks", "Score" : 0.5}, 164 | {"Answer" : "Operating systems", "Score" : 0.5}, 165 | {"Answer" : "Security elements", "Score" : 0.5}, 166 | {"Answer" : "The application stacks", "Score" : 0.5}, 167 | {"Answer" : "The applications", "Score" : 0.5} 168 | ] 169 | }, 170 | { 171 | "Type" : "Option", 172 | "SubCategory" : "Environments", 173 | "QuestionText" : "Are the required environments (e.g. dev, test, integration) available in line with demand (i.e. at the right time or in a way that doesn’t incur delay to activity)?" 174 | }, 175 | { 176 | "Type" : "Option", 177 | "SubCategory" : "Environments", 178 | "QuestionText" : "Is the provisioning, configuration and management of environments automated?", 179 | "Answers" : [ 180 | {"Answer" : "Yes, and scaling is automatic", "Score" : 2}, 181 | {"Answer" : "Yes, but scaling is manual", "Score" : 1}, 182 | {"Answer" : "No", "Score" : 0} 183 | ] 184 | }, 185 | { 186 | "Type" : "Option", 187 | "SubCategory" : "Testing", 188 | "QuestionText" : "Does the team have a high degree of automated unit tests in place (testing individual modules)?", 189 | "Answers" : [ 190 | {"Answer" : "Yes, automated tests are in place and run on every build", "Score" : 1}, 191 | {"Answer" : "Yes, automated tests are in place", "Score" : 0.5}, 192 | {"Answer" : "No", "Score" : 0} 193 | ] 194 | }, 195 | { 196 | "Type" : "Option", 197 | "SubCategory" : "Testing", 198 | "QuestionText" : "Does the team have a high degree of automated integration tests in place (testing the interaction of modules with each other)?", 199 | "Answers" : [ 200 | {"Answer" : "Yes, automated tests are in place and run on every build", "Score" : 1}, 201 | {"Answer" : "Yes, automated tests are in place", "Score" : 0.5}, 202 | {"Answer" : "No", "Score" : 0} 203 | ] 204 | }, 205 | { 206 | "Type" : "Option", 207 | "SubCategory" : "Testing", 208 | "QuestionText" : "Does the team have a high degree of automated system tests in place (confirming overall system functionality meets requirements)?", 209 | "Answers" : [ 210 | {"Answer" : "Yes, automated tests are in place and run on every build", "Score" : 1}, 211 | {"Answer" : "Yes, automated tests are in place", "Score" : 0.5}, 212 | {"Answer" : "No", "Score" : 0} 213 | ] 214 | }, 215 | { 216 | "Type" : "Option", 217 | "SubCategory" : "Testing", 218 | "QuestionText" : "Does the team have a high degree of automated performance tests in place?", 219 | "Answers" : [ 220 | {"Answer" : "Yes, automated tests are in place and run on every build", "Score" : 1}, 221 | {"Answer" : "Yes, automated tests are in place", "Score" : 0.5}, 222 | {"Answer" : "No", "Score" : 0} 223 | ] 224 | }, 225 | { 226 | "Type" : "Option", 227 | "SubCategory" : "Static Analysis", 228 | "QuestionText" : "Does the team complete automated scanning of source code assets?", 229 | "Answers" : [ 230 | {"Answer" : "Yes, automated scanning is in place and run on every build", "Score" : 1}, 231 | {"Answer" : "Yes, automated scanning is in place", "Score" : 0.5}, 232 | {"Answer" : "No", "Score" : 0} 233 | ] 234 | }, 235 | { 236 | "Type" : "Option", 237 | "SubCategory" : "Static Analysis", 238 | "QuestionText" : "Does the team complete automated scanning of binaries?", 239 | "Answers" : [ 240 | {"Answer" : "Yes, automated scanning is in place and run on every build", "Score" : 1}, 241 | {"Answer" : "Yes, automated scanning is in place", "Score" : 0.5}, 242 | {"Answer" : "No", "Score" : 0} 243 | ] 244 | }, 245 | { 246 | "Type" : "Option", 247 | "SubCategory" : "Static Analysis", 248 | "QuestionText" : "Is code automatically scanned for quality during a build?", 249 | "Answers" : [ 250 | {"Answer" : "Yes, automated scanning is in place and run on every build", "Score" : 1}, 251 | {"Answer" : "Yes, automated scanning is in place", "Score" : 0.5}, 252 | {"Answer" : "No", "Score" : 0} 253 | ] 254 | }, 255 | { 256 | "Type" : "Option", 257 | "QuestionText" : "Does failure to meet coding standards or security rules trigger a break in the build?" 258 | }, 259 | { 260 | "Type" : "Option", 261 | "QuestionText" : "Is automation code developed with the same rigor as product code (e.g. testing, source control)?" 262 | } 263 | ] 264 | }, 265 | { 266 | "SectionName" : "Architecture and Design", 267 | "SpiderPos" : 5, 268 | "Questions" : [ 269 | { 270 | "Type" : "Option", 271 | "QuestionText" : "Does the architecture of the application consist of loosely coupled components (choose the most accurate description)?", 272 | "Answers" : [ 273 | {"Answer" : "The application is built from a number of stateless components with scaling and resilience provided at the application layer (full MicroServices)", "Score" : 3}, 274 | {"Answer" : "The application is made up of several separate components but relies on external solutions to provide availability and scalability", "Score" : 2}, 275 | {"Answer" : "The application is largely monolithic but made up of code modules that can be worked on independently and then re-compiled into a single unit", "Score" : 1}, 276 | {"Answer" : "The application is built up of monolithic code and can only be changed in its entirety as part of a release schedule", "Score" : 0} 277 | ] 278 | }, 279 | { 280 | "Type" : "Checkbox", 281 | "QuestionText" : "Does the architecture enable development, testing and other QA activities to be representative and performed independently of each another without impacting production (tick all that apply)?", 282 | "Answers" : [ 283 | {"Answer" : "There are fully separate development, test and QA environments", "Score" : 0.5}, 284 | {"Answer" : "Environments are regularly re-built or synchronised (at least monthly)", "Score" : 0.5}, 285 | {"Answer" : "The 3 environments are similar at all levels (resilience, performance, security, dependencies)", "Score" : 0.5}, 286 | {"Answer" : "Each environment can be torn down and rebuilt without affecting other environments", "Score" : 0.5}, 287 | {"Answer" : " Environment specific configuration items are decoupled from the code in order to accelerate rebuilds", "Score" : 0.5} 288 | ] 289 | }, 290 | { 291 | "Type" : "Option", 292 | "QuestionText" : "Does the architecture enable the deployment of services independently of one another?", 293 | "Answers" : [ 294 | {"Answer" : "Yes, every element of functionality can be updated individually and applied to the application", "Score" : 2}, 295 | {"Answer" : "Partially, some elements can be updated independently, but there are certain core components that need to be updated together in order to maintain functionality", "Score" : 1}, 296 | {"Answer" : "No, updates to the system need to be performed together in a formal release cycle", "Score" : 0} 297 | ] 298 | }, 299 | { 300 | "Type" : "Option", 301 | "QuestionText" : "Are all application logs written to a central log repository automatically with the configuration included in the environment design to allow portability between environments?" 302 | } 303 | ] 304 | }, 305 | { 306 | "SectionName" : "DevOps Practices", 307 | "SpiderPos" : 6, 308 | "Questions" : [ 309 | { 310 | "Type" : "Checkbox", 311 | "SubCategory" : "CI", 312 | "QuestionText" : "Does the team manage their source code in a central source control system (tick all that apply)?", 313 | "Answers" : [ 314 | {"Answer" : "We have a common code repository (e.g. Git based repo)", "Score" : 0.5}, 315 | {"Answer" : "We have a defined branching structure", "Score" : 0.5}, 316 | {"Answer" : "We have defined repository structure", "Score" : 0.5}, 317 | {"Answer" : "Our structure and branching strategy are aligned to our Dev, Test, and Prod environments (enabling a smooth flow between environments)", "Score" : 0.5} 318 | ] 319 | }, 320 | { 321 | "Type" : "Option", 322 | "SubCategory" : "CI", 323 | "QuestionText" : "How frequently do developers integrate their changes into a shared mainline (trunk)?", 324 | "Answers" : [ 325 | {"Answer" : "Code is integrated at least once per day", "Score" : 2}, 326 | {"Answer" : "Code is integrated at least weekly", "Score" : 1}, 327 | {"Answer" : "Code is integrated infrequently but at least once a month", "Score" : 0.5}, 328 | {"Answer" : "Code is integrated on an ad hoc basis when the developer feels it is ready to share", "Score" : 0} 329 | ] 330 | }, 331 | { 332 | "Type" : "Option", 333 | "SubCategory" : "Code Review", 334 | "QuestionText" : "Is there a defined code review and approval process?", 335 | "Answers" : [ 336 | {"Answer" : "We have a targeted code review process that is appropriate and ensures code is published in a timely manner", "Score" : 1}, 337 | {"Answer" : "We have a code review process but the process incurs delays and hinders deployments", "Score" : 0.5}, 338 | {"Answer" : "We have no code review process and bugs can frequently be integrated into the mainline (trunk)", "Score" : 0} 339 | ] 340 | }, 341 | { 342 | "Type" : "Option", 343 | "SubCategory" : "CD", 344 | "QuestionText" : "Whenever code is integrated with a shared mainline (trunk), are automated processes triggered?", 345 | "Answers" : [ 346 | {"Answer" : "Yes, an automated build of the software is triggered into a production-like environment, automated tests are then triggered and software is available to be automatically deployed into production", "Score" : 2}, 347 | {"Answer" : "Yes, an automated build of the software is triggered into a production-like environment, manual tests are then performed before the release is manually deployed into production", "Score" : 1}, 348 | {"Answer" : "Yes, an automated build of the software is triggered, however this build is then manually deployed into the relevant environments (QA and Prod)", "Score" : 0.5}, 349 | {"Answer" : "No", "Score" : 0} 350 | ] 351 | }, 352 | { 353 | "Type" : "Option", 354 | "SubCategory" : "CI", 355 | "QuestionText" : "Is highest priority always given to fixing a broken build?", 356 | "Answers" : [ 357 | {"Answer" : "Yes, builds are fixed / rolled back within 10 minutes", "Score" : 2}, 358 | {"Answer" : "Yes, builds are fixed / rolled back within 1 hour", "Score" : 1}, 359 | {"Answer" : "Yes, builds are fixed / rolled back within a day", "Score" : 0.5}, 360 | {"Answer" : "No", "Score" : 0} 361 | ] 362 | }, 363 | { 364 | "Type" : "Option", 365 | "SubCategory" : "CI", 366 | "QuestionText" : "Are adequate notifications in place to communicate the build status and failures to the team (e.g. automated e-mails, slack, circuit)?" 367 | }, 368 | { 369 | "Type" : "Option", 370 | "SubCategory" : "CD", 371 | "QuestionText" : "Is it possible to roll back the application cleanly and reliably?" 372 | }, 373 | { 374 | "Type" : "Option", 375 | "SubCategory" : "Refactoring", 376 | "QuestionText" : "Does the team practice regular refactoring of their code?", 377 | "Answers" : [ 378 | {"Answer" : "Yes, code is often updated independently of new functions or features to ensure technical debt is minimised", "Score" : 1}, 379 | {"Answer" : "No, code is only updated to enable new features or functionality", "Score" : 0} 380 | ] 381 | }, 382 | { 383 | "Type" : "Option", 384 | "SubCategory" : "Refactoring", 385 | "QuestionText" : "Is time allocated/dedicated to refactoring in order to improve code quality and reduce technical debt?" 386 | }, 387 | { 388 | "Type" : "Option", 389 | "SubCategory" : "Refactoring", 390 | "QuestionText" : "Are there sufficient automated tests in place to enable developers to refactor with confidence?" 391 | }, 392 | { 393 | "Type" : "Option", 394 | "SubCategory" : "TDD", 395 | "QuestionText" : "How widely does the team practice Test Driven Development (TDD), ensuring that automated tests are developed in advance of new features?", 396 | "Answers" : [ 397 | {"Answer" : "All product code is developed using TDD", "Score" : 2}, 398 | {"Answer" : "Some product code is developed using TDD", "Score" : 1}, 399 | {"Answer" : "TDD is not used at all", "Score" : 0} 400 | ] 401 | }, 402 | { 403 | "Type" : "Option", 404 | "SubCategory" : "TDD", 405 | "QuestionText" : "Is a standard test framework (such as JUnit) used by the team?" 406 | }, 407 | { 408 | "Type" : "Option", 409 | "SubCategory" : "TDD", 410 | "QuestionText" : "Is the refactoring step of the TDD cycle usually applied?" 411 | }, 412 | { 413 | "Type" : "Option", 414 | "SubCategory" : "TDD", 415 | "QuestionText" : "Are mocks/stubs/simulators used to ensure that tests can be run quickly, frequently and repeatably?" 416 | } 417 | ] 418 | }, 419 | { 420 | "SectionName" : "Org Structure, Culture and Incentives", 421 | "SpiderPos" : 1, 422 | "Questions" : [ 423 | { 424 | "Type" : "Option", 425 | "SubCategory" : "Organisation Structure", 426 | "QuestionText" : "Is the team a cross functional delivery team comprising of development, testing and operations expertise?" 427 | }, 428 | { 429 | "Type" : "Option", 430 | "SubCategory" : "Incentivisation", 431 | "QuestionText" : "Are incentives for people on the team (both financial and non-financial) aligned to overall team results?" 432 | }, 433 | { 434 | "Type" : "Option", 435 | "SubCategory" : "Organisation Structure", 436 | "QuestionText" : "Are those responsible for designing, developing, testing and operating the application all part of the same team?" 437 | }, 438 | { 439 | "Type" : "Option", 440 | "QuestionText" : "Does the team have accountability for the product throughout its life-cycle (introduction, growth, maturity, decline)?" 441 | }, 442 | { 443 | "Type" : "Option", 444 | "SubCategory" : "Culture", 445 | "QuestionText" : "Does the team have a culture of experimentation and innovation?" 446 | }, 447 | { 448 | "Type" : "Option", 449 | "SubCategory" : "Culture", 450 | "QuestionText" : "Does the team have a high trust culture which enables autonomy?" 451 | }, 452 | { 453 | "Type" : "Option", 454 | "SubCategory" : "Incentivisation", 455 | "QuestionText" : "Do people involved in developing and running the application have aligned incentives and goals?" 456 | }, 457 | { 458 | "Type" : "Option", 459 | "QuestionText" : "Does the team have a say in what they work on (e.g. self selection days)?" 460 | }, 461 | { 462 | "Type" : "Option", 463 | "SubCategory" : "Organisation Structure", 464 | "QuestionText" : "Does the organisation's structure catalyse and support a DevOps approach?" 465 | }, 466 | { 467 | "Type" : "Option", 468 | "QuestionText" : "Is there a team charter that describes how the team behaves and works together?" 469 | }, 470 | { 471 | "Type" : "Option", 472 | "SubCategory" : "Incentivisation", 473 | "QuestionText" : "Is there a clear vision and purpose for the product?" 474 | }, 475 | { 476 | "Type" : "Option", 477 | "QuestionText" : "Are all the product's stakeholders identified and engaged?" 478 | }, 479 | { 480 | "Type" : "Option", 481 | "SubCategory" : "Incentivisation", 482 | "QuestionText" : "Is the team aligned and incentivised to a measurable business outcome?" 483 | }, 484 | { 485 | "Type" : "Option", 486 | "QuestionText" : "Do management and the wider organisation see the value in protecting time for continuous improvement?" 487 | }, 488 | { 489 | "Type" : "Option", 490 | "QuestionText" : "Does the team have enough time to learn new technologies, tools and practices?" 491 | }, 492 | { 493 | "Type" : "Option", 494 | "SubCategory" : "Organisation Structure", 495 | "QuestionText" : "How frequently is there interaction between the business and the development team?", 496 | "Answers" : [ 497 | {"Answer" : "Business users are embedded within the team", "Score" : 2}, 498 | {"Answer" : "The team meets with the business at least every week", "Score" : 1}, 499 | {"Answer" : "The team meets with the business at least every month", "Score" : 0.5}, 500 | {"Answer" : "Rarely or not at all", "Score" : 0} 501 | ] 502 | }, 503 | { 504 | "Type" : "Option", 505 | "SubCategory" : "Culture", 506 | "QuestionText" : "Do senior stakeholders buy into and support the DevOps approach?", 507 | "Answers" : [ 508 | {"Answer" : "Yes, we rarely have issues with business cases or bureaucratic processes", "Score" : 2}, 509 | {"Answer" : "Yes, there is buy-in and understanding, but business processes are still too rigid", "Score" : 1}, 510 | {"Answer" : "No", "Score" : 0} 511 | ] 512 | }, 513 | { 514 | "Type" : "Option", 515 | "SubCategory" : "Culture", 516 | "QuestionText" : "Do members of the team practice continuous learning?" 517 | }, 518 | { 519 | "Type" : "Option", 520 | "SubCategory" : "Culture", 521 | "QuestionText" : "Does the team have a feedback culture (where people are happy to quickly share negative and positive feedback)?" 522 | } 523 | ] 524 | }, 525 | { 526 | "SectionName" : "Standardisation", 527 | "SpiderPos" : 5, 528 | "Questions" : [ 529 | { 530 | "Type" : "Checkbox", 531 | "QuestionText" : "Has the organisation standardised on a set of tooling standards (tick all that apply)?", 532 | "Answers" : [ 533 | {"Answer" : "We have a defined set of CI/CD tooling that is universally used", "Score" : 1}, 534 | {"Answer" : "We have defined code repository tooling and standardised usage processes for them (e.g. branching pattern)", "Score" : 1}, 535 | {"Answer" : "We have defined monitoring tooling", "Score" : 1}, 536 | {"Answer" : "We have defined patching/upgrade tooling and processes (e.g. immutable vs. mutable)", "Score" : 1} 537 | ] 538 | }, 539 | { 540 | "Type" : "Option", 541 | "QuestionText" : "Has the organisation standardised on a set of application stacks/development languages?", 542 | "Answers" : [ 543 | {"Answer" : "Yes, with a sufficient portfolio of options to meet our development needs", "Score" : 2}, 544 | {"Answer" : "Yes, but with an insufficient portfolio of options to meet our development needs", "Score" : 1}, 545 | {"Answer" : "No, any team can choose any stack/language without constraint", "Score" : 0} 546 | ] 547 | }, 548 | { 549 | "Type" : "Option", 550 | "QuestionText" : "Do you make the best use of SaaS (Software as a Service) for utility applications (i.e. ones not used for competitive advantage such as version control)?" 551 | }, 552 | { 553 | "Type" : "Option", 554 | "QuestionText" : "As much as makes sense, do you use PaaS (Platform as a Service)?" 555 | }, 556 | { 557 | "Type" : "Option", 558 | "QuestionText" : "As much as makes sense, do you use IaaS (Infrastructure as a Service)?" 559 | } 560 | ] 561 | } 562 | ] -------------------------------------------------------------------------------- /advice.json: -------------------------------------------------------------------------------- 1 | { 2 | "//" : "Copyright 2018 Atos SE and Worldline", 3 | "//" : "Licensed under MIT (https://github.com/atosorigin/DevOpsMaturityAssessment/blob/master/LICENSE)", 4 | 5 | "Team Agility" : { 6 | "Advice" : "A great place to start is by reading the Agile Manifesto. Scrum is a popular Agile software development framework which is a great approach when setting up a new team if there isn't already an existing way of working. Kanban is an evolutionary method for improving a team's agility, and works well when the team already has an existing way of working in place.", 7 | "Links" : [ 8 | { 9 | "Type" : "Website", 10 | "Text" : "Agile Manifesto", 11 | "Href" : "http://agilemanifesto.org/" 12 | }, 13 | { 14 | "Type" : "Video", 15 | "Text" : "Explaining Agile - Martin Fowler and Neal Ford at USI (0:43)", 16 | "Href" : "https://www.youtube.com/watch?v=GE6lbPLEAzc" 17 | }, 18 | { 19 | "Type" : "Video", 20 | "Text" : "The Systems Thinking Approach to Introducing Kanban - David Anderson (1:31)", 21 | "Href" : "https://vimeo.com/46272041" 22 | }, 23 | { 24 | "Type" : "Book", 25 | "Text" : "The Scrum Guide by Ken Schwaber and Jeff Sutherland", 26 | "Href" : "http://www.scrumguides.org/index.html" 27 | }, 28 | { 29 | "Type" : "Book", 30 | "Text" : "Succeeding with Agile: Software Development Using Scrum by Mike Cohn", 31 | "Href" : "https://www.amazon.com/Succeeding-Agile-Software-Development-Using/dp/0321579364", 32 | "Paid" : "Yes" 33 | }, 34 | { 35 | "Type" : "Book", 36 | "Text" : "Kanban: Successful Evolutionary Change for Your Technology Business by David Anderson", 37 | "Href" : "https://www.amazon.com/Kanban-Successful-Evolutionary-Technology-Business/dp/0984521402", 38 | "Paid" : "Yes" 39 | } 40 | ] 41 | }, 42 | "Collaboration" : { 43 | "Advice" : "Consider whether you have the tools necessary to enable effective communication within and outside of the team. Also think about how effective the team's interpersonal habits are for enabling a fast, low-friction and precise exchange of ideas and emotions.", 44 | "Links" : [ 45 | { 46 | "Type" : "Blog", 47 | "Text" : "Cultivate Communities of Practice by Mike Cohn", 48 | "Href" : "https://www.mountaingoatsoftware.com/blog/cultivate-communities-of-practice" 49 | }, 50 | { 51 | "Type" : "Video", 52 | "Text" : "DevOpsChat: Collaboration Tools Interview with Ryan Bryers and Adrian Hepworth (0:22)", 53 | "Href" : "https://www.youtube.com/watch?v=pF8Y4amhBtA" 54 | }, 55 | { 56 | "Type" : "Video", 57 | "Text" : "DevOpsChat: Team = Product Interview with Jim and Michele McCarthy (0:39)", 58 | "Href" : "https://www.youtube.com/watch?v=Rs1tdql6Hb0" 59 | }, 60 | { 61 | "Type" : "Book", 62 | "Text" : "Software For Your Head by Jim and Michele McCarthy", 63 | "Href" : "https://liveingreatness.com/software-for-your-head-book/" 64 | } 65 | ] 66 | }, 67 | "Automation" : { 68 | "Advice" : "Automation is critical to shortening the lead time for software delivery. If quality and speed are to be transformed, automation is essential. Automation enables environments to be provisioned and configured identically every time. Automation enables application code to be built, tested, delivered, provisioned and configured easily. Automation also enables environments to be monitored and incidents (including security threats) to be responded to based upon a set of rules. Automation drives consistency, enforces quality, removes wastage and delivers speed; it is the technical backbone to any DevOps implementation.", 69 | 70 | "ReadMore" : "The general rule of thumb is to automate anything that you’re doing more than once, however there are diminishing returns that will be experienced and it produces a new code base to maintain. Surprisingly, adopting a clear and well communicated automation strategy is not necessarily key to successful adoption and buy-in from engineering teams, although it is certainly valuable to have one. The question is more about timing than anything else, but in certain areas (e.g. Infrastructure as Code) automation is one of those things that generally builds pace organically. Start small with engineering led experimentation as, generally, engineers see the value in automation. We suggest that you:

    - Encourage automation of the day to day (something that may save 20 minutes but is done several times per week, as once the benefits are seen, automating things becomes addictive)

    - Catalyse discussions of automation tooling choices via communities of interest, these will eventually generate standards in coding, practices, processes and principles

    - Continuously review automation as part of retrospectives

    - Communicate automation successes and failures (both can be learned from!)

    - Follow good engineering practices: for example, maintain automation code in a version controlled code repository

    When making the case for automation, it is not necessarily about the cost saving (almost certainly not based upon the status quo). For example, the business case for test automation based upon the current release frequency may not make sense, but if that release frequency shifts to once per day it would do. It’s not just about release frequency either, automation significantly reduces wastage within the system, measuring the mean time to recovery (MTTR) and the number of defects in production will display the benefit of automation here. Ultimately the benefits of automation are speed and consistency.", 71 | 72 | "Links" : [ 73 | { 74 | "Type" : "Book", 75 | "Text" : "Get started with Red Hat Ansible Tower", 76 | "Href" : "https://www.ansible.com/resources/ebooks/get-started-with-red-hat-ansible-tower" 77 | }, 78 | { 79 | "Type" : "Article", 80 | "Text" : "Various Ansible Whitepapers", 81 | "Href" : "https://www.ansible.com/resources/whitepapers" 82 | }, 83 | { 84 | "Type" : "Blog", 85 | "Text" : "DevOps: Don't create the haystack by Chris Baynham-Hughes", 86 | "Href" : "https://www.linkedin.com/pulse/devops-dont-create-haystack-chris-baynham-hughes/" 87 | }, 88 | { 89 | "Type" : "Blog", 90 | "Text" : "Putting The Dev Into DevOps: Why Your Developers Should Write Terraform Too by Luke Kysow", 91 | "Href" : "https://medium.com/runatlantis/putting-the-dev-into-devops-why-your-developers-should-write-terraform-too-d3c079dfc6a8" 92 | }, 93 | { 94 | "Type" : "Article", 95 | "Text" : "Data Center Automation (Atos Whitepaper)", 96 | "Href" : "https://atos.net/wp-content/uploads/2018/09/atos-wp-datacenter-automation.pdf" 97 | } 98 | ] 99 | }, 100 | "Environments" : { 101 | "Advice" : "Automation of the provisioning, configuration and management of environments (such as development, QA and Production) is a cornerstone of DevOps adoption. There are many tools and methodologies that can be adopted to automate the various layers involved: automated monitoring, patching, build and configuration management, as well as simple provisioning. The use of abstraction techniques, such as containerisation, is being widely adopted to simplify such automation.", 102 | "Links" : [ 103 | { 104 | "Type" : "Blog", 105 | "Text" : "One year using Kubernetes in production: Lessons learned by Paul Bakker", 106 | "Href" : "https://techbeacon.com/devops/one-year-using-kubernetes-production-lessons-learned" 107 | }, 108 | { 109 | "Type" : "Blog", 110 | "Text" : "10 automation tools your DevOps team can not live without Matt Shealy", 111 | "Href" : "https://bigdata-madesimple.com/10-automation-tools-your-devops-team-cant-live-without/" 112 | }, 113 | { 114 | "Type" : "Video", 115 | "Text" : "DevOpsChat: Containerisation for DevOps with Miska Kaipiainen (00:19)", 116 | "Href" : "https://www.youtube.com/watch?v=8mR4q-roSHk" 117 | }, 118 | { 119 | "Type" : "Blog", 120 | "Text" : "10 Devops Tools For Infrastructure Automation And Monitoring", 121 | "Href" : "https://devopscube.com/devops-tools-for-infrastructure-automation/" 122 | }, 123 | { 124 | "Type" : "Website", 125 | "Text" : "Continuous Delivery Foundation (CDF)", 126 | "Href" : "https://cd.foundation/about/" 127 | }, 128 | { 129 | "Type" : "Blog", 130 | "Text" : "8 CI/CD Best Practices for Your DevOps Journey by Kristin Baskett", 131 | "Href" : "https://www.cloudbees.com/blog/8-cicd-best-practices-your-devops-journey" 132 | }, 133 | { 134 | "Type" : "Blog", 135 | "Text" : "DevOps automation best practices: How much is too much? by David Linthicum", 136 | "Href" : "https://techbeacon.com/devops/devops-automation-best-practices-how-much-too-much" 137 | } 138 | ] 139 | }, 140 | "Testing" : { 141 | "Advice" : "Automated testing enables tests to be run quickly and frequently. It enables new features to be added with a high degree of confidence that existing functionality will not be broken. As such it is a key enabler for delivering software frequently in smaller increments.", 142 | "Links" : [ 143 | { 144 | "Type" : "Blog", 145 | "Text" : "TestPyramid by Martin Fowler", 146 | "Href" : "https://martinfowler.com/bliki/TestPyramid.html" 147 | }, 148 | { 149 | "Type" : "Article", 150 | "Text" : "The Practical Test Pyramid by Martin Fowler", 151 | "Href" : "https://martinfowler.com/articles/practical-test-pyramid.html" 152 | }, 153 | { 154 | "Type" : "Video", 155 | "Text" : "Automation Testing Tutorial for Beginners (0:07)", 156 | "Href" : "https://www.youtube.com/watch?v=RbSlW8jZFe8" 157 | }, 158 | { 159 | "Type" : "Video", 160 | "Text" : "Netflix Automation Talks - Test Automation at Scale (1:16)", 161 | "Href" : "https://www.youtube.com/watch?v=FrBN94gUn_I" 162 | }, 163 | { 164 | "Type" : "Book", 165 | "Text" : "Test-Driven Development: A Practical Guide by David Astels", 166 | "Href" : "https://www.amazon.com/Test-Driven-Development-Practical-Guide/dp/0131016490", 167 | "Paid" : "Yes" 168 | }, 169 | { 170 | "Type" : "Book", 171 | "Text" : "Working Effectively with Legacy Code by Michael Feathers", 172 | "Href" : "https://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052/", 173 | "Paid" : "Yes" 174 | } 175 | ] 176 | }, 177 | "Static Analysis" : { 178 | "Advice" : "Static code analysis is the analysis of software without executing the compiled program. In most cases the analysis is performed on a version of the source code but, in other cases, object code is used. Static analysis helps to improve code quality by reporting possible code bugs, code smells, memory leaks, software metrics and security vulnerabilities.", 179 | "Links" : [ 180 | { 181 | "Type" : "Video", 182 | "Text" : "Static Code Analysis: Scan All Your Code For Bugs - Dr. Jared DeMott (0:19)", 183 | "Href" : "https://www.youtube.com/watch?v=Heor8BVa4A0" 184 | }, 185 | { 186 | "Type" : "Website", 187 | "Text" : "SonarQube", 188 | "Href" : "https://www.sonarqube.org/" 189 | }, 190 | { 191 | "Type" : "Website", 192 | "Text" : "Coverity Scan", 193 | "Href" : "https://scan.coverity.com/" 194 | }, 195 | { 196 | "Type" : "Website", 197 | "Text" : "Klocwork", 198 | "Href" : "https://www.roguewave.com/products-services/klocwork" 199 | } 200 | ] 201 | }, 202 | "Architecture and Design": { 203 | "Advice" : "Navigating the many and various options for optimising architecture for DevOps can be bewildering! It is important to bear in mind that there are no \"right\" answers. The agility and functionality of Public Cloud environments make them ideal for building DevOps focused architectures and a good starting point for reading matter is the Cloud Providers’ own guides. Beyond that there are various books, videos and vendor tool documentation that are useful sources of information.", 204 | "Links" : [ 205 | { 206 | "Type" : "Book", 207 | "Text" : "Google Site Reliability Engineering Books", 208 | "Href" : "https://landing.google.com/sre/books/" 209 | }, 210 | { 211 | "Type" : "Website", 212 | "Text" : "DevOps and AWS", 213 | "Href" : "https://aws.amazon.com/devops/" 214 | }, 215 | { 216 | "Type" : "Website", 217 | "Text" : "Microsoft Azure DevOps Checklist", 218 | "Href" : "https://docs.microsoft.com/en-us/azure/architecture/checklist/dev-ops" 219 | }, 220 | { 221 | "Type" : "Website", 222 | "Text" : "Microsoft Azure for Architects", 223 | "Href" : "https://azure.microsoft.com/en-us/resources/azure-for-architects/" 224 | }, 225 | { 226 | "Type" : "Website", 227 | "Text" : "The Twelve-Factor App", 228 | "Href" : "https://12factor.net/" 229 | }, 230 | { 231 | "Type" : "Book", 232 | "Text" : "The DevOps Handbook: How to Create World-Class Agility, Reliability, and Security in Technology Organizations by Gene Kim, Jez Humble, Patrick Debois and John Willis", 233 | "Href" : "https://www.amazon.com/DevOps-Handbook-World-Class-Reliability-Organizations/dp/1942788002/", 234 | "Paid" : "Yes" 235 | }, 236 | { 237 | "Type" : "Book", 238 | "Text" : "The Practice of Cloud System Administration: DevOps and SRE Practices for Web Services by Thomas A. Limoncelli, Strata R. Chalup and Christina J. Hogan", 239 | "Href" : "https://www.amazon.com/Practice-Cloud-System-Administration-Practices/dp/032194318X/", 240 | "Paid" : "Yes" 241 | }, 242 | { 243 | "Type" : "Book", 244 | "Text" : "Practical DevOps: Implement DevOps in your organization by effectively building, deploying, testing, and monitoring code by Joakim Verona", 245 | "Href" : "https://www.amazon.com/Practical-DevOps-organization-effectively-monitoring/dp/1788392574/", 246 | "Paid" : "Yes" 247 | }, 248 | { 249 | "Type" : "Video", 250 | "Text" : "Rethinking enterprise architecture for DevOps, agile, & cloud native organizations - Michael Cote (0:48)", 251 | "Href" : "https://www.youtube.com/watch?v=2UquXJsbr9M" 252 | }, 253 | { 254 | "Type" : "Video", 255 | "Text" : "Mastering Chaos - A Netflix Guide to Microservices - Josh Evans (0:53)", 256 | "Href" : "https://www.youtube.com/watch?v=CZ3wIuvmHeM" 257 | }, 258 | { 259 | "Type" : "Book", 260 | "Text" : "Ansible: Up and Running: Automating Configuration Management and Deployment the Easy Way by Lorin Hochstein and Rene Moser", 261 | "Href" : "https://www.amazon.com/_/dp/1491979801", 262 | "Paid" : "Yes" 263 | }, 264 | { 265 | "Type" : "Website", 266 | "Text" : "Puppet: Infrastructure as code", 267 | "Href" : "https://puppet.com/solutions/infrastructure-as-code" 268 | } 269 | ] 270 | }, 271 | "DevOps Practices" : { 272 | "Advice" : "There are a number of technical practices that are core to DevOps: Continuous Integration, Continuous Deployment/Delivery, Test Driven Development, Refactoring, and Code Review. The resources here are good overviews. For more in depth results see the detailed report for DevOps Practices.", 273 | "Links" : [ 274 | { 275 | "Type" : "Article", 276 | "Text" : "Enterprise DevOps: Building a Service Oriented Organisation (Atos Whitepaper)", 277 | "Href" : "https://atos.net/wp-content/uploads/2017/01/DevOps_Building_a_Service_Oriented_Organization-White-Paper-web-FINAL-281116.pdf" 278 | }, 279 | { 280 | "Type" : "Blog", 281 | "Text" : "Continuous Integration by Martin Fowler", 282 | "Href" : "https://martinfowler.com/articles/continuousIntegration.html" 283 | }, 284 | { 285 | "Type" : "Website", 286 | "Text" : "Continuous Delivery", 287 | "Href" : "https://continuousdelivery.com/" 288 | }, 289 | { 290 | "Type" : "Video", 291 | "Text" : "Continuous Delivery - Jez Humble (0:46)", 292 | "Href" : "https://www.youtube.com/watch?v=skLJuksCRTw" 293 | }, 294 | { 295 | "Type" : "Blog", 296 | "Text" : "TestDrivenDevelopment by Martin Fowler", 297 | "Href" : "https://martinfowler.com/bliki/TestDrivenDevelopment.html" 298 | }, 299 | { 300 | "Type" : "Book", 301 | "Text" : "The Art of Agile Development: Test-Driven Development by James Shore", 302 | "Href" : "https://www.jamesshore.com/Agile-Book/test_driven_development.html" 303 | }, 304 | { 305 | "Type" : "Website", 306 | "Text" : "Refactoring.com", 307 | "Href" : "https://refactoring.com/" 308 | }, 309 | { 310 | "Type" : "Blog", 311 | "Text" : "Code Reviews: Just Do It by Jeff Atwood", 312 | "Href" : "https://blog.codinghorror.com/code-reviews-just-do-it/" 313 | } 314 | ] 315 | }, 316 | "CI" : { 317 | "Advice" : "Continuous Integration (CI) is the practice of merging changes back to the main branch (trunk) as often as possible, even several times a day. The developer's changes are validated by triggering a build and running automated tests against the build. By doing so, you avoid the integration hell that usually happens when people wait until \"release day\" to merge their changes into the trunk. Continuous Integration puts a great emphasis on test automation to check that the application is not broken whenever new commits are integrated into the main branch.", 318 | "Links" : [ 319 | { 320 | "Type" : "Article", 321 | "Text" : "Continuous Integration by Martin Fowler", 322 | "Href" : "https://martinfowler.com/articles/continuousIntegration.html" 323 | }, 324 | { 325 | "Type" : "Blog", 326 | "Text" : "FeatureBranch by Martin Fowler", 327 | "Href" : "https://martinfowler.com/bliki/FeatureBranch.html" 328 | }, 329 | { 330 | "Type" : "Book", 331 | "Text" : "Continuous Integration: Improving Software Quality and Reducing Risk by Paul M. Duvall", 332 | "Href" : "https://www.amazon.com/Continuous-Integration-Improving-Software-Reducing/dp/0321336380", 333 | "Paid" : "Yes" 334 | } 335 | ] 336 | }, 337 | "CD" : { 338 | "Advice" : "Continuous Delivery (CD) as an extension of Continuous Integration and is an approach where, after each build, the software is automatically delivered into a production-like quality assurance environment on which further automated testing is completed. Furthermore, the build can then be easily released into production if desired. Continuous Deployment goes one step further than Continuous Delivery. With this practice, every change that passes all stages of your delivery pipeline is automatically released into production. There is no human intervention, and only a failed test will prevent a new change being deployed.", 339 | "Links" : [ 340 | { 341 | "Type" : "Article", 342 | "Text" : "Continuous integration vs. continuous delivery vs. continuous deployment by Sten Pittet", 343 | "Href" : "https://www.atlassian.com/continuous-delivery/principles/continuous-integration-vs-delivery-vs-deployment" 344 | }, 345 | { 346 | "Type" : "Website", 347 | "Text" : "Continuous Delivery", 348 | "Href" : "https://continuousdelivery.com/" 349 | }, 350 | { 351 | "Type" : "Video", 352 | "Text" : "GitHub Professional Guides: Continuous Integration Continuous Delivery (0:06)", 353 | "Href" : "https://www.youtube.com/watch?v=xSv_m3KhUO8" 354 | }, 355 | { 356 | "Type" : "Video", 357 | "Text" : "CI/CD Introduction (0:04)", 358 | "Href" : "https://www.youtube.com/watch?v=AlrImm1T8Wg" 359 | }, 360 | { 361 | "Type" : "Book", 362 | "Text" : "Continuous Delivery: Reliable Software Releases through Build, Test, and Deployment Automation by Jez Humble", 363 | "Href" : "https://www.amazon.com/Continuous-Delivery-Deployment-Automation-Addison-Wesley/dp/0321601912", 364 | "Paid" : "Yes" 365 | } 366 | ] 367 | }, 368 | "TDD" : { 369 | "Advice" : "Test Driven Development (TDD) is an approach to developing software where automated tests are written before production code. This ensures that up-to-date automated tests are always maintained and makes it easier and less risky to make changes to software.", 370 | "Links" : [ 371 | { 372 | "Type" : "Blog", 373 | "Text" : "TestDrivenDevelopment by Martin Fowler", 374 | "Href" : "https://martinfowler.com/bliki/TestDrivenDevelopment.html" 375 | }, 376 | { 377 | "Type" : "Book", 378 | "Text" : "Test-Driven Development: A Practical Guide by David Astels", 379 | "Href" : "https://www.amazon.com/gp/product/0131016490/", 380 | "Paid" : "Yes" 381 | }, 382 | { 383 | "Type" : "Book", 384 | "Text" : "Refactoring: Improving the Design of Existing Code by Martin Fowler", 385 | "Href" : "https://www.amazon.com/Refactoring-Improving-Existing-Addison-Wesley-Signature/dp/0134757599/", 386 | "Paid" : "Yes" 387 | } 388 | ] 389 | }, 390 | "Code Review" : { 391 | "Advice" : "Code reviews are a very effective way of increasing software quality and also spreading knowledge accross the team.", 392 | "Links" : [ 393 | { 394 | "Type" : "Blog", 395 | "Text" : "Code Reviews: Just Do It by Jeff Atwood", 396 | "Href" : "https://blog.codinghorror.com/code-reviews-just-do-it/" 397 | }, 398 | { 399 | "Type" : "Book", 400 | "Text" : "Code Complete: A Practical Handbook of Software Construction by Steve McConnell", 401 | "Href" : "https://www.amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670/", 402 | "Paid" : "Yes" 403 | }, 404 | { 405 | "Type" : "Book", 406 | "Text" : "Clean Code: A Handbook of Agile Software Craftsmanship by Robert C. Martin", 407 | "Href" : "https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882/", 408 | "Paid" : "Yes" 409 | }, 410 | { 411 | "Type" : "Book", 412 | "Text" : "The Pragmatic Programmer: From Journeyman to Master by Andrew Hunt", 413 | "Href" : "https://www.amazon.com/Pragmatic-Programmer-Journeyman-Master/dp/020161622X/", 414 | "Paid" : "Yes" 415 | } 416 | ] 417 | }, 418 | "Refactoring" : { 419 | "Advice" : "Refactoring reduces technical debt and is the technical practice of improving the internal quality of code without changing its external functionality. As technical debt builds up, the speed at which new functionality can be released is drastically reduced, thus it is vital that technical debt is actively managed. Refactoring is also an integral part of Test Driven Development (TDD).", 420 | "Links" : [ 421 | { 422 | "Type" : "Website", 423 | "Text" : "Refactoring.com", 424 | "Href" : "https://refactoring.com/" 425 | }, 426 | { 427 | "Type" : "Website", 428 | "Text" : "What is refactoring?", 429 | "Href" : "https://www.agilealliance.org/glossary/refactoring" 430 | }, 431 | { 432 | "Type" : "Website", 433 | "Text" : "Online catalog of refactorings by Martin Fowler", 434 | "Href" : "https://refactoring.com/catalog/" 435 | }, 436 | { 437 | "Type" : "Video", 438 | "Text" : "Code Refactoring: Learn Code Smells And Level Up Your Game! - Sandi Metz (0:36)", 439 | "Href" : "https://www.youtube.com/watch?v=D4auWwMsEnY" 440 | }, 441 | { 442 | "Type" : "Video", 443 | "Text" : "Workflows of Refactoring - Martin Fowler (0:27)", 444 | "Href" : "https://www.youtube.com/watch?v=vqEg37e4Mkw" 445 | }, 446 | { 447 | "Type" : "Book", 448 | "Text" : "Refactoring: Improving the Design of Existing Code by Martin Fowler", 449 | "Href" : "https://www.amazon.com/Refactoring-Improving-Existing-Addison-Wesley-Signature/dp/0134757599/", 450 | "Paid" : "Yes" 451 | } 452 | ] 453 | }, 454 | "Org Structure, Culture and Incentives" : { 455 | "Advice" : "Org Structure, Culture and Incentives are critical for DevOps success within an organisation, but they are also the hardest/most disruptive elements to change and get right.", 456 | "Links" : [ 457 | { 458 | "Type" : "Blog", 459 | "Text" : "The Benefits of Feature Teams by Mike Cohn", 460 | "Href" : "https://www.mountaingoatsoftware.com/blog/the-benefits-of-feature-teams" 461 | }, 462 | { 463 | "Type" : "Video", 464 | "Text" : "Spotify Engineering Culture", 465 | "Href" : "https://vimeo.com/85490944" 466 | }, 467 | { 468 | "Type" : "Book", 469 | "Text" : "The Open Organization Field Guide", 470 | "Href" : "https://opensource.com/open-organization/resources/field-guide" 471 | }, 472 | { 473 | "Type" : "Website", 474 | "Text" : "Management 3.0", 475 | "Href" : "https://management30.com" 476 | }, 477 | { 478 | "Type" : "Video", 479 | "Text" : "DevOpsChat: \"Giving a Damn\" interview with Pawel Brodzinski (00:34)", 480 | "Href" : "https://www.youtube.com/watch?v=tY4_OTj46h8" 481 | } 482 | ] 483 | }, 484 | "Organisation Structure" : { 485 | "Advice" : "For successful DevOps adoption, the organisation needs to be structured into teams that are both cross-functional and autonomous.", 486 | 487 | "ReadMore" : "Many organisational structures are characterised by and aligned to functions (specialisms) rather than the outcomes that are needed for the business. The issue with function-based organisational structures is that they tend to create a lot of handovers between teams; things get thrown over the fence for the next team to deal with, generally by complaining about the quality from the previous team and using up all the time of the team after them. This doesn't support the development of a collaborative culture. Improve the organisational structure and both quality and flow will improve.", 488 | 489 | "Links" : [ 490 | { 491 | "Type" : "Blog", 492 | "Text" : "The Benefits of Feature Teams by Mike Cohn", 493 | "Href" : "https://www.mountaingoatsoftware.com/blog/the-benefits-of-feature-teams" 494 | }, 495 | { 496 | "Type" : "Article", 497 | "Text" : "Enterprise DevOps: Building a Service Oriented Organisation (Atos Whitepaper)", 498 | "Href" : "https://atos.net/wp-content/uploads/2017/01/DevOps_Building_a_Service_Oriented_Organization-White-Paper-web-FINAL-281116.pdf" 499 | }, 500 | { 501 | "Type" : "Video", 502 | "Text" : "Spotify Engineering Culture", 503 | "Href" : "https://vimeo.com/85490944" 504 | }, 505 | { 506 | "Type" : "Book", 507 | "Text" : "Migrating to Cloud-Native Application Architectures by Matt Stine", 508 | "Href" : "https://download3.vmware.com/vmworld/2015/downloads/oreilly-cloud-native-archx.pdf" 509 | }, 510 | { 511 | "Type" : "Book", 512 | "Text" : "The Phoenix Project by Gene Kim, Kevin Behr and George Spafford", 513 | "Href" : "https://www.amazon.com/Phoenix-Project-DevOps-Helping-Business/dp/0988262592", 514 | "Paid" : "Yes" 515 | } 516 | ] 517 | }, 518 | "Culture" : { 519 | "Advice" : "Driving the right culture within an organisation is critical for successful DevOps adoption. It is the \"X Factor\" for any organisation. An organisation may have the most incredible tool chain in the world, but if they do not collaborate, continuously improve, step out of their traditional/functionally based tribes, ensure clear connection between the desired strategic objectives and the software features being built, engage and empower people at all levels, connect everyone to the mission and embrace experimentation, then the full benefits of DevOps will never be truly realised.", 520 | 521 | "ReadMore" : "

    Culture change is hard and, as a result, many choose to focus on the tooling aspects of DevOps. Culture change is like a virus in the way it spreads: when first introduced to an organisation it will be attacked by \"company antibodies\" (e.g. \"we don’t do it like that here\"). Thus, taking the analogy further, the virus must be strong and continuously fed until it is dominant within the system.

    There are many culture change models/approaches and one size does not fit all. Success factors include true business engagement and alignment (DevOps is not \"an IT problem\"), recognising that the \"We is stronger than the I\", a meritocratic, free speaking, open organisation (command and control does not yield transformational results), and change through demonstration/delivery (not only is demonstrating tangible benefits the most effective way to convince doubters, it is backed through many change models; e.g. using the Satir Model for change, demonstrating a new approach is the \"transforming idea\" and repeating it is the \"practice and integration\" that takes an organisation to a new status quo for performance).", 522 | "Links" : [ 523 | { 524 | "Type" : "Book", 525 | "Text" : "Tribal Leadership Revised Edition: Leveraging Natural Groups to Build a Thriving Organization by Dave Logan, John King and Halee Fischer-Wright", 526 | "Href" : "https://www.amazon.com/Tribal-Leadership-Leveraging-Thriving-Organization/dp/0061251321/", 527 | "Paid" : "Yes" 528 | }, 529 | { 530 | "Type" : "Book", 531 | "Text" : "Tribal Unity: Getting from Teams to Tribes by Creating a One Team Culture by Em Campbell-Pretty", 532 | "Href" : "https://www.amazon.com/Tribal-Unity-Getting-Creating-Culture/dp/1537347578/", 533 | "Paid" : "Yes" 534 | }, 535 | { 536 | "Type" : "Book", 537 | "Text" : "The Open Organization by Jim Whitehurst", 538 | "Href" : "https://www.amazon.com/Open-Organization-Igniting-Passion-Performance/dp/1625275277/", 539 | "Paid" : "Yes" 540 | }, 541 | { 542 | "Type" : "Book", 543 | "Text" : "The Open Organization Field Guide", 544 | "Href" : "https://opensource.com/open-organization/resources/field-guide" 545 | } 546 | ] 547 | }, 548 | "Incentivisation" : { 549 | "Advice" : "For DevOps adoption personal incentives are less effective at driving the desired behaviors than team incentives. Within a DevOps approach, one wishes to drive ownership of the product/outcomes and the understanding that those successfully adopting DevOps will \"live and die\" as a team; this aligns earnings with collaboration, not competition.", 550 | 551 | "ReadMore" : "

    Incentives are just about the most controversial topic for any organisation, and there are many possible approaches. Making significant changes to incentive structures, especially in large organisations, can be hugely disruptive, controversial and, in some cases, require agreement from unions/employee forums, thus there is no perfect implementation we can recommend. Our advice, however, is to take a fresh look at the existing incentives within the organisation and ensure that they are aligned as much as possible to the outcomes that the organisation is looking to achieve through DevOps.

    Some organisations have removed all personal incentives in favour of team only incentives, others are constrained within a traditional incentive framework/structure, but can make simple changes like giving weight to actions that support others within the team. What is to be avoided is giving a bonus to the person that turns up at 3:30am and gets a system back up again, rather than rewarding the person who identifies and fixes the issue at its root cause so it doesn’t fall over again; this is an alarmingly common flaw in may incentive structures.

    Question whether incentives can be used effectively to drive not only DevOps adoption, but tighter unity and collaboration within the DevOps teams themselves. Failing to do so frequently results in team members sticking to their tribes, e.g. \"I'm a Dev, I'm not doing Ops work/going on call.\"", 552 | "Links" : [ 553 | { 554 | "Type" : "Website", 555 | "Text" : "Management 3.0", 556 | "Href" : "https://management30.com" 557 | }, 558 | { 559 | "Type" : "Video", 560 | "Text" : "DevOpsChat: \"Giving a Damn\" interview with Pawel Brodzinski (00:34)", 561 | "Href" : "https://www.youtube.com/watch?v=tY4_OTj46h8" 562 | }, 563 | { 564 | "Type" : "Blog", 565 | "Text" : "Introducing Open Salaries at Buffer: Our Transparent Formula and All Individual Salaries by Joel Gascoigne", 566 | "Href" : "https://open.buffer.com/introducing-open-salaries-at-buffer-including-our-transparent-formula-and-all-individual-salaries/" 567 | }, 568 | { 569 | "Type" : "Website", 570 | "Text" : "Holocracy.org", 571 | "Href" : "https://www.holacracy.org/" 572 | }, 573 | { 574 | "Type" : "Book", 575 | "Text" : "Accelerate: The Science of Lean Software and DevOps: Building and Scaling High Performing Technology Organisations by Gene Kim, Jez Humble and Nicole Forsgren", 576 | "Href" : "https://www.amazon.co.uk/dp/1942788339/", 577 | "Paid" : "Yes" 578 | } 579 | ] 580 | }, 581 | "Standardisation" : { 582 | "Advice" : "The arguments for standardisation versus flexibility are complex and multi-dimensional, as are the related decision points of utilising SaaS vs PaaS vs IaaS. In truth, there is no \"correct\" answer and the overall benefit of standardisation will vary. The key to success is to gain a good understanding of the relative merits and disadvantages, which can then be applied to any particular situation. Below are some excellent guides to help develop greater understanding of this.", 583 | "Links" : [ 584 | { 585 | "Type" : "Blog", 586 | "Text" : "Challenges in DevOps Standardization by Lavanya Subbarayalu", 587 | "Href" : "https://devops.com/challenges-devops-standardization/" 588 | }, 589 | { 590 | "Type" : "Blog", 591 | "Text" : "DevOps Survey Results: The Case for Standardized Continuous Delivery Tools by Heidi Gilmore", 592 | "Href" : "https://www.cloudbees.com/blog/devops-survey-results-case-standardized-continuous-delivery-tools" 593 | }, 594 | { 595 | "Type" : "Blog", 596 | "Text" : "Centralized vs. decentralized CI / CD strategies for multiple teams by Adrian Oprea", 597 | "Href" : "https://oprea.rocks/blog/centralized-vs-decentralized-ci-cd-strategies-for-multiple-teams/" 598 | }, 599 | { 600 | "Type" : "Blog", 601 | "Text" : "When to use SaaS, PaaS, and IaaS by Eamonn Colman", 602 | "Href" : "https://www.computenext.com/blog/when-to-use-saas-paas-and-iaas/" 603 | }, 604 | { 605 | "Type" : "Blog", 606 | "Text" : "SaaS vs PaaS vs IaaS: What’s The Difference and How To Choose by Stephen Watts", 607 | "Href" : "https://www.bmc.com/blogs/saas-vs-paas-vs-iaas-whats-the-difference-and-how-to-choose/" 608 | } 609 | ] 610 | } 611 | } 612 | -------------------------------------------------------------------------------- /js/bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v4.0.0 (https://getbootstrap.com) 3 | * Copyright 2011-2018 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("jquery"),require("popper.js")):"function"==typeof define&&define.amd?define(["exports","jquery","popper.js"],e):e(t.bootstrap={},t.jQuery,t.Popper)}(this,function(t,e,n){"use strict";function i(t,e){for(var n=0;n0?i:null}catch(t){return null}},reflow:function(t){return t.offsetHeight},triggerTransitionEnd:function(n){t(n).trigger(e.end)},supportsTransitionEnd:function(){return Boolean(e)},isElement:function(t){return(t[0]||t).nodeType},typeCheckConfig:function(t,e,n){for(var s in n)if(Object.prototype.hasOwnProperty.call(n,s)){var r=n[s],o=e[s],a=o&&i.isElement(o)?"element":(l=o,{}.toString.call(l).match(/\s([a-zA-Z]+)/)[1].toLowerCase());if(!new RegExp(r).test(a))throw new Error(t.toUpperCase()+': Option "'+s+'" provided type "'+a+'" but expected type "'+r+'".')}var l}};return e=("undefined"==typeof window||!window.QUnit)&&{end:"transitionend"},t.fn.emulateTransitionEnd=n,i.supportsTransitionEnd()&&(t.event.special[i.TRANSITION_END]={bindType:e.end,delegateType:e.end,handle:function(e){if(t(e.target).is(this))return e.handleObj.handler.apply(this,arguments)}}),i}(e),L=(a="alert",h="."+(l="bs.alert"),c=(o=e).fn[a],u={CLOSE:"close"+h,CLOSED:"closed"+h,CLICK_DATA_API:"click"+h+".data-api"},f="alert",d="fade",_="show",g=function(){function t(t){this._element=t}var e=t.prototype;return e.close=function(t){t=t||this._element;var e=this._getRootElement(t);this._triggerCloseEvent(e).isDefaultPrevented()||this._removeElement(e)},e.dispose=function(){o.removeData(this._element,l),this._element=null},e._getRootElement=function(t){var e=P.getSelectorFromElement(t),n=!1;return e&&(n=o(e)[0]),n||(n=o(t).closest("."+f)[0]),n},e._triggerCloseEvent=function(t){var e=o.Event(u.CLOSE);return o(t).trigger(e),e},e._removeElement=function(t){var e=this;o(t).removeClass(_),P.supportsTransitionEnd()&&o(t).hasClass(d)?o(t).one(P.TRANSITION_END,function(n){return e._destroyElement(t,n)}).emulateTransitionEnd(150):this._destroyElement(t)},e._destroyElement=function(t){o(t).detach().trigger(u.CLOSED).remove()},t._jQueryInterface=function(e){return this.each(function(){var n=o(this),i=n.data(l);i||(i=new t(this),n.data(l,i)),"close"===e&&i[e](this)})},t._handleDismiss=function(t){return function(e){e&&e.preventDefault(),t.close(this)}},s(t,null,[{key:"VERSION",get:function(){return"4.0.0"}}]),t}(),o(document).on(u.CLICK_DATA_API,'[data-dismiss="alert"]',g._handleDismiss(new g)),o.fn[a]=g._jQueryInterface,o.fn[a].Constructor=g,o.fn[a].noConflict=function(){return o.fn[a]=c,g._jQueryInterface},g),R=(m="button",E="."+(v="bs.button"),T=".data-api",y=(p=e).fn[m],C="active",I="btn",A="focus",b='[data-toggle^="button"]',D='[data-toggle="buttons"]',S="input",w=".active",N=".btn",O={CLICK_DATA_API:"click"+E+T,FOCUS_BLUR_DATA_API:"focus"+E+T+" blur"+E+T},k=function(){function t(t){this._element=t}var e=t.prototype;return e.toggle=function(){var t=!0,e=!0,n=p(this._element).closest(D)[0];if(n){var i=p(this._element).find(S)[0];if(i){if("radio"===i.type)if(i.checked&&p(this._element).hasClass(C))t=!1;else{var s=p(n).find(w)[0];s&&p(s).removeClass(C)}if(t){if(i.hasAttribute("disabled")||n.hasAttribute("disabled")||i.classList.contains("disabled")||n.classList.contains("disabled"))return;i.checked=!p(this._element).hasClass(C),p(i).trigger("change")}i.focus(),e=!1}}e&&this._element.setAttribute("aria-pressed",!p(this._element).hasClass(C)),t&&p(this._element).toggleClass(C)},e.dispose=function(){p.removeData(this._element,v),this._element=null},t._jQueryInterface=function(e){return this.each(function(){var n=p(this).data(v);n||(n=new t(this),p(this).data(v,n)),"toggle"===e&&n[e]()})},s(t,null,[{key:"VERSION",get:function(){return"4.0.0"}}]),t}(),p(document).on(O.CLICK_DATA_API,b,function(t){t.preventDefault();var e=t.target;p(e).hasClass(I)||(e=p(e).closest(N)),k._jQueryInterface.call(p(e),"toggle")}).on(O.FOCUS_BLUR_DATA_API,b,function(t){var e=p(t.target).closest(N)[0];p(e).toggleClass(A,/^focus(in)?$/.test(t.type))}),p.fn[m]=k._jQueryInterface,p.fn[m].Constructor=k,p.fn[m].noConflict=function(){return p.fn[m]=y,k._jQueryInterface},k),j=function(t){var e="carousel",n="bs.carousel",i="."+n,o=t.fn[e],a={interval:5e3,keyboard:!0,slide:!1,pause:"hover",wrap:!0},l={interval:"(number|boolean)",keyboard:"boolean",slide:"(boolean|string)",pause:"(string|boolean)",wrap:"boolean"},h="next",c="prev",u="left",f="right",d={SLIDE:"slide"+i,SLID:"slid"+i,KEYDOWN:"keydown"+i,MOUSEENTER:"mouseenter"+i,MOUSELEAVE:"mouseleave"+i,TOUCHEND:"touchend"+i,LOAD_DATA_API:"load"+i+".data-api",CLICK_DATA_API:"click"+i+".data-api"},_="carousel",g="active",p="slide",m="carousel-item-right",v="carousel-item-left",E="carousel-item-next",T="carousel-item-prev",y={ACTIVE:".active",ACTIVE_ITEM:".active.carousel-item",ITEM:".carousel-item",NEXT_PREV:".carousel-item-next, .carousel-item-prev",INDICATORS:".carousel-indicators",DATA_SLIDE:"[data-slide], [data-slide-to]",DATA_RIDE:'[data-ride="carousel"]'},C=function(){function o(e,n){this._items=null,this._interval=null,this._activeElement=null,this._isPaused=!1,this._isSliding=!1,this.touchTimeout=null,this._config=this._getConfig(n),this._element=t(e)[0],this._indicatorsElement=t(this._element).find(y.INDICATORS)[0],this._addEventListeners()}var C=o.prototype;return C.next=function(){this._isSliding||this._slide(h)},C.nextWhenVisible=function(){!document.hidden&&t(this._element).is(":visible")&&"hidden"!==t(this._element).css("visibility")&&this.next()},C.prev=function(){this._isSliding||this._slide(c)},C.pause=function(e){e||(this._isPaused=!0),t(this._element).find(y.NEXT_PREV)[0]&&P.supportsTransitionEnd()&&(P.triggerTransitionEnd(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null},C.cycle=function(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config.interval&&!this._isPaused&&(this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))},C.to=function(e){var n=this;this._activeElement=t(this._element).find(y.ACTIVE_ITEM)[0];var i=this._getItemIndex(this._activeElement);if(!(e>this._items.length-1||e<0))if(this._isSliding)t(this._element).one(d.SLID,function(){return n.to(e)});else{if(i===e)return this.pause(),void this.cycle();var s=e>i?h:c;this._slide(s,this._items[e])}},C.dispose=function(){t(this._element).off(i),t.removeData(this._element,n),this._items=null,this._config=null,this._element=null,this._interval=null,this._isPaused=null,this._isSliding=null,this._activeElement=null,this._indicatorsElement=null},C._getConfig=function(t){return t=r({},a,t),P.typeCheckConfig(e,t,l),t},C._addEventListeners=function(){var e=this;this._config.keyboard&&t(this._element).on(d.KEYDOWN,function(t){return e._keydown(t)}),"hover"===this._config.pause&&(t(this._element).on(d.MOUSEENTER,function(t){return e.pause(t)}).on(d.MOUSELEAVE,function(t){return e.cycle(t)}),"ontouchstart"in document.documentElement&&t(this._element).on(d.TOUCHEND,function(){e.pause(),e.touchTimeout&&clearTimeout(e.touchTimeout),e.touchTimeout=setTimeout(function(t){return e.cycle(t)},500+e._config.interval)}))},C._keydown=function(t){if(!/input|textarea/i.test(t.target.tagName))switch(t.which){case 37:t.preventDefault(),this.prev();break;case 39:t.preventDefault(),this.next()}},C._getItemIndex=function(e){return this._items=t.makeArray(t(e).parent().find(y.ITEM)),this._items.indexOf(e)},C._getItemByDirection=function(t,e){var n=t===h,i=t===c,s=this._getItemIndex(e),r=this._items.length-1;if((i&&0===s||n&&s===r)&&!this._config.wrap)return e;var o=(s+(t===c?-1:1))%this._items.length;return-1===o?this._items[this._items.length-1]:this._items[o]},C._triggerSlideEvent=function(e,n){var i=this._getItemIndex(e),s=this._getItemIndex(t(this._element).find(y.ACTIVE_ITEM)[0]),r=t.Event(d.SLIDE,{relatedTarget:e,direction:n,from:s,to:i});return t(this._element).trigger(r),r},C._setActiveIndicatorElement=function(e){if(this._indicatorsElement){t(this._indicatorsElement).find(y.ACTIVE).removeClass(g);var n=this._indicatorsElement.children[this._getItemIndex(e)];n&&t(n).addClass(g)}},C._slide=function(e,n){var i,s,r,o=this,a=t(this._element).find(y.ACTIVE_ITEM)[0],l=this._getItemIndex(a),c=n||a&&this._getItemByDirection(e,a),_=this._getItemIndex(c),C=Boolean(this._interval);if(e===h?(i=v,s=E,r=u):(i=m,s=T,r=f),c&&t(c).hasClass(g))this._isSliding=!1;else if(!this._triggerSlideEvent(c,r).isDefaultPrevented()&&a&&c){this._isSliding=!0,C&&this.pause(),this._setActiveIndicatorElement(c);var I=t.Event(d.SLID,{relatedTarget:c,direction:r,from:l,to:_});P.supportsTransitionEnd()&&t(this._element).hasClass(p)?(t(c).addClass(s),P.reflow(c),t(a).addClass(i),t(c).addClass(i),t(a).one(P.TRANSITION_END,function(){t(c).removeClass(i+" "+s).addClass(g),t(a).removeClass(g+" "+s+" "+i),o._isSliding=!1,setTimeout(function(){return t(o._element).trigger(I)},0)}).emulateTransitionEnd(600)):(t(a).removeClass(g),t(c).addClass(g),this._isSliding=!1,t(this._element).trigger(I)),C&&this.cycle()}},o._jQueryInterface=function(e){return this.each(function(){var i=t(this).data(n),s=r({},a,t(this).data());"object"==typeof e&&(s=r({},s,e));var l="string"==typeof e?e:s.slide;if(i||(i=new o(this,s),t(this).data(n,i)),"number"==typeof e)i.to(e);else if("string"==typeof l){if("undefined"==typeof i[l])throw new TypeError('No method named "'+l+'"');i[l]()}else s.interval&&(i.pause(),i.cycle())})},o._dataApiClickHandler=function(e){var i=P.getSelectorFromElement(this);if(i){var s=t(i)[0];if(s&&t(s).hasClass(_)){var a=r({},t(s).data(),t(this).data()),l=this.getAttribute("data-slide-to");l&&(a.interval=!1),o._jQueryInterface.call(t(s),a),l&&t(s).data(n).to(l),e.preventDefault()}}},s(o,null,[{key:"VERSION",get:function(){return"4.0.0"}},{key:"Default",get:function(){return a}}]),o}();return t(document).on(d.CLICK_DATA_API,y.DATA_SLIDE,C._dataApiClickHandler),t(window).on(d.LOAD_DATA_API,function(){t(y.DATA_RIDE).each(function(){var e=t(this);C._jQueryInterface.call(e,e.data())})}),t.fn[e]=C._jQueryInterface,t.fn[e].Constructor=C,t.fn[e].noConflict=function(){return t.fn[e]=o,C._jQueryInterface},C}(e),H=function(t){var e="collapse",n="bs.collapse",i="."+n,o=t.fn[e],a={toggle:!0,parent:""},l={toggle:"boolean",parent:"(string|element)"},h={SHOW:"show"+i,SHOWN:"shown"+i,HIDE:"hide"+i,HIDDEN:"hidden"+i,CLICK_DATA_API:"click"+i+".data-api"},c="show",u="collapse",f="collapsing",d="collapsed",_="width",g="height",p={ACTIVES:".show, .collapsing",DATA_TOGGLE:'[data-toggle="collapse"]'},m=function(){function i(e,n){this._isTransitioning=!1,this._element=e,this._config=this._getConfig(n),this._triggerArray=t.makeArray(t('[data-toggle="collapse"][href="#'+e.id+'"],[data-toggle="collapse"][data-target="#'+e.id+'"]'));for(var i=t(p.DATA_TOGGLE),s=0;s0&&(this._selector=o,this._triggerArray.push(r))}this._parent=this._config.parent?this._getParent():null,this._config.parent||this._addAriaAndCollapsedClass(this._element,this._triggerArray),this._config.toggle&&this.toggle()}var o=i.prototype;return o.toggle=function(){t(this._element).hasClass(c)?this.hide():this.show()},o.show=function(){var e,s,r=this;if(!this._isTransitioning&&!t(this._element).hasClass(c)&&(this._parent&&0===(e=t.makeArray(t(this._parent).find(p.ACTIVES).filter('[data-parent="'+this._config.parent+'"]'))).length&&(e=null),!(e&&(s=t(e).not(this._selector).data(n))&&s._isTransitioning))){var o=t.Event(h.SHOW);if(t(this._element).trigger(o),!o.isDefaultPrevented()){e&&(i._jQueryInterface.call(t(e).not(this._selector),"hide"),s||t(e).data(n,null));var a=this._getDimension();t(this._element).removeClass(u).addClass(f),this._element.style[a]=0,this._triggerArray.length>0&&t(this._triggerArray).removeClass(d).attr("aria-expanded",!0),this.setTransitioning(!0);var l=function(){t(r._element).removeClass(f).addClass(u).addClass(c),r._element.style[a]="",r.setTransitioning(!1),t(r._element).trigger(h.SHOWN)};if(P.supportsTransitionEnd()){var _="scroll"+(a[0].toUpperCase()+a.slice(1));t(this._element).one(P.TRANSITION_END,l).emulateTransitionEnd(600),this._element.style[a]=this._element[_]+"px"}else l()}}},o.hide=function(){var e=this;if(!this._isTransitioning&&t(this._element).hasClass(c)){var n=t.Event(h.HIDE);if(t(this._element).trigger(n),!n.isDefaultPrevented()){var i=this._getDimension();if(this._element.style[i]=this._element.getBoundingClientRect()[i]+"px",P.reflow(this._element),t(this._element).addClass(f).removeClass(u).removeClass(c),this._triggerArray.length>0)for(var s=0;s0&&t(n).toggleClass(d,!i).attr("aria-expanded",i)}},i._getTargetFromElement=function(e){var n=P.getSelectorFromElement(e);return n?t(n)[0]:null},i._jQueryInterface=function(e){return this.each(function(){var s=t(this),o=s.data(n),l=r({},a,s.data(),"object"==typeof e&&e);if(!o&&l.toggle&&/show|hide/.test(e)&&(l.toggle=!1),o||(o=new i(this,l),s.data(n,o)),"string"==typeof e){if("undefined"==typeof o[e])throw new TypeError('No method named "'+e+'"');o[e]()}})},s(i,null,[{key:"VERSION",get:function(){return"4.0.0"}},{key:"Default",get:function(){return a}}]),i}();return t(document).on(h.CLICK_DATA_API,p.DATA_TOGGLE,function(e){"A"===e.currentTarget.tagName&&e.preventDefault();var i=t(this),s=P.getSelectorFromElement(this);t(s).each(function(){var e=t(this),s=e.data(n)?"toggle":i.data();m._jQueryInterface.call(e,s)})}),t.fn[e]=m._jQueryInterface,t.fn[e].Constructor=m,t.fn[e].noConflict=function(){return t.fn[e]=o,m._jQueryInterface},m}(e),W=function(t){var e="dropdown",i="bs.dropdown",o="."+i,a=".data-api",l=t.fn[e],h=new RegExp("38|40|27"),c={HIDE:"hide"+o,HIDDEN:"hidden"+o,SHOW:"show"+o,SHOWN:"shown"+o,CLICK:"click"+o,CLICK_DATA_API:"click"+o+a,KEYDOWN_DATA_API:"keydown"+o+a,KEYUP_DATA_API:"keyup"+o+a},u="disabled",f="show",d="dropup",_="dropright",g="dropleft",p="dropdown-menu-right",m="dropdown-menu-left",v="position-static",E='[data-toggle="dropdown"]',T=".dropdown form",y=".dropdown-menu",C=".navbar-nav",I=".dropdown-menu .dropdown-item:not(.disabled)",A="top-start",b="top-end",D="bottom-start",S="bottom-end",w="right-start",N="left-start",O={offset:0,flip:!0,boundary:"scrollParent"},k={offset:"(number|string|function)",flip:"boolean",boundary:"(string|element)"},L=function(){function a(t,e){this._element=t,this._popper=null,this._config=this._getConfig(e),this._menu=this._getMenuElement(),this._inNavbar=this._detectNavbar(),this._addEventListeners()}var l=a.prototype;return l.toggle=function(){if(!this._element.disabled&&!t(this._element).hasClass(u)){var e=a._getParentFromElement(this._element),i=t(this._menu).hasClass(f);if(a._clearMenus(),!i){var s={relatedTarget:this._element},r=t.Event(c.SHOW,s);if(t(e).trigger(r),!r.isDefaultPrevented()){if(!this._inNavbar){if("undefined"==typeof n)throw new TypeError("Bootstrap dropdown require Popper.js (https://popper.js.org)");var o=this._element;t(e).hasClass(d)&&(t(this._menu).hasClass(m)||t(this._menu).hasClass(p))&&(o=e),"scrollParent"!==this._config.boundary&&t(e).addClass(v),this._popper=new n(o,this._menu,this._getPopperConfig())}"ontouchstart"in document.documentElement&&0===t(e).closest(C).length&&t("body").children().on("mouseover",null,t.noop),this._element.focus(),this._element.setAttribute("aria-expanded",!0),t(this._menu).toggleClass(f),t(e).toggleClass(f).trigger(t.Event(c.SHOWN,s))}}}},l.dispose=function(){t.removeData(this._element,i),t(this._element).off(o),this._element=null,this._menu=null,null!==this._popper&&(this._popper.destroy(),this._popper=null)},l.update=function(){this._inNavbar=this._detectNavbar(),null!==this._popper&&this._popper.scheduleUpdate()},l._addEventListeners=function(){var e=this;t(this._element).on(c.CLICK,function(t){t.preventDefault(),t.stopPropagation(),e.toggle()})},l._getConfig=function(n){return n=r({},this.constructor.Default,t(this._element).data(),n),P.typeCheckConfig(e,n,this.constructor.DefaultType),n},l._getMenuElement=function(){if(!this._menu){var e=a._getParentFromElement(this._element);this._menu=t(e).find(y)[0]}return this._menu},l._getPlacement=function(){var e=t(this._element).parent(),n=D;return e.hasClass(d)?(n=A,t(this._menu).hasClass(p)&&(n=b)):e.hasClass(_)?n=w:e.hasClass(g)?n=N:t(this._menu).hasClass(p)&&(n=S),n},l._detectNavbar=function(){return t(this._element).closest(".navbar").length>0},l._getPopperConfig=function(){var t=this,e={};return"function"==typeof this._config.offset?e.fn=function(e){return e.offsets=r({},e.offsets,t._config.offset(e.offsets)||{}),e}:e.offset=this._config.offset,{placement:this._getPlacement(),modifiers:{offset:e,flip:{enabled:this._config.flip},preventOverflow:{boundariesElement:this._config.boundary}}}},a._jQueryInterface=function(e){return this.each(function(){var n=t(this).data(i);if(n||(n=new a(this,"object"==typeof e?e:null),t(this).data(i,n)),"string"==typeof e){if("undefined"==typeof n[e])throw new TypeError('No method named "'+e+'"');n[e]()}})},a._clearMenus=function(e){if(!e||3!==e.which&&("keyup"!==e.type||9===e.which))for(var n=t.makeArray(t(E)),s=0;s0&&r--,40===e.which&&rdocument.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},p._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},p._checkScrollbar=function(){var t=document.body.getBoundingClientRect();this._isBodyOverflowing=t.left+t.right

    ',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:0,container:!1,fallbackPlacement:"flip",boundary:"scrollParent"},f="show",d="out",_={HIDE:"hide"+o,HIDDEN:"hidden"+o,SHOW:"show"+o,SHOWN:"shown"+o,INSERTED:"inserted"+o,CLICK:"click"+o,FOCUSIN:"focusin"+o,FOCUSOUT:"focusout"+o,MOUSEENTER:"mouseenter"+o,MOUSELEAVE:"mouseleave"+o},g="fade",p="show",m=".tooltip-inner",v=".arrow",E="hover",T="focus",y="click",C="manual",I=function(){function a(t,e){if("undefined"==typeof n)throw new TypeError("Bootstrap tooltips require Popper.js (https://popper.js.org)");this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}var I=a.prototype;return I.enable=function(){this._isEnabled=!0},I.disable=function(){this._isEnabled=!1},I.toggleEnabled=function(){this._isEnabled=!this._isEnabled},I.toggle=function(e){if(this._isEnabled)if(e){var n=this.constructor.DATA_KEY,i=t(e.currentTarget).data(n);i||(i=new this.constructor(e.currentTarget,this._getDelegateConfig()),t(e.currentTarget).data(n,i)),i._activeTrigger.click=!i._activeTrigger.click,i._isWithActiveTrigger()?i._enter(null,i):i._leave(null,i)}else{if(t(this.getTipElement()).hasClass(p))return void this._leave(null,this);this._enter(null,this)}},I.dispose=function(){clearTimeout(this._timeout),t.removeData(this.element,this.constructor.DATA_KEY),t(this.element).off(this.constructor.EVENT_KEY),t(this.element).closest(".modal").off("hide.bs.modal"),this.tip&&t(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,this._activeTrigger=null,null!==this._popper&&this._popper.destroy(),this._popper=null,this.element=null,this.config=null,this.tip=null},I.show=function(){var e=this;if("none"===t(this.element).css("display"))throw new Error("Please use show on visible elements");var i=t.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){t(this.element).trigger(i);var s=t.contains(this.element.ownerDocument.documentElement,this.element);if(i.isDefaultPrevented()||!s)return;var r=this.getTipElement(),o=P.getUID(this.constructor.NAME);r.setAttribute("id",o),this.element.setAttribute("aria-describedby",o),this.setContent(),this.config.animation&&t(r).addClass(g);var l="function"==typeof this.config.placement?this.config.placement.call(this,r,this.element):this.config.placement,h=this._getAttachment(l);this.addAttachmentClass(h);var c=!1===this.config.container?document.body:t(this.config.container);t(r).data(this.constructor.DATA_KEY,this),t.contains(this.element.ownerDocument.documentElement,this.tip)||t(r).appendTo(c),t(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new n(this.element,r,{placement:h,modifiers:{offset:{offset:this.config.offset},flip:{behavior:this.config.fallbackPlacement},arrow:{element:v},preventOverflow:{boundariesElement:this.config.boundary}},onCreate:function(t){t.originalPlacement!==t.placement&&e._handlePopperPlacementChange(t)},onUpdate:function(t){e._handlePopperPlacementChange(t)}}),t(r).addClass(p),"ontouchstart"in document.documentElement&&t("body").children().on("mouseover",null,t.noop);var u=function(){e.config.animation&&e._fixTransition();var n=e._hoverState;e._hoverState=null,t(e.element).trigger(e.constructor.Event.SHOWN),n===d&&e._leave(null,e)};P.supportsTransitionEnd()&&t(this.tip).hasClass(g)?t(this.tip).one(P.TRANSITION_END,u).emulateTransitionEnd(a._TRANSITION_DURATION):u()}},I.hide=function(e){var n=this,i=this.getTipElement(),s=t.Event(this.constructor.Event.HIDE),r=function(){n._hoverState!==f&&i.parentNode&&i.parentNode.removeChild(i),n._cleanTipClass(),n.element.removeAttribute("aria-describedby"),t(n.element).trigger(n.constructor.Event.HIDDEN),null!==n._popper&&n._popper.destroy(),e&&e()};t(this.element).trigger(s),s.isDefaultPrevented()||(t(i).removeClass(p),"ontouchstart"in document.documentElement&&t("body").children().off("mouseover",null,t.noop),this._activeTrigger[y]=!1,this._activeTrigger[T]=!1,this._activeTrigger[E]=!1,P.supportsTransitionEnd()&&t(this.tip).hasClass(g)?t(i).one(P.TRANSITION_END,r).emulateTransitionEnd(150):r(),this._hoverState="")},I.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},I.isWithContent=function(){return Boolean(this.getTitle())},I.addAttachmentClass=function(e){t(this.getTipElement()).addClass("bs-tooltip-"+e)},I.getTipElement=function(){return this.tip=this.tip||t(this.config.template)[0],this.tip},I.setContent=function(){var e=t(this.getTipElement());this.setElementContent(e.find(m),this.getTitle()),e.removeClass(g+" "+p)},I.setElementContent=function(e,n){var i=this.config.html;"object"==typeof n&&(n.nodeType||n.jquery)?i?t(n).parent().is(e)||e.empty().append(n):e.text(t(n).text()):e[i?"html":"text"](n)},I.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t},I._getAttachment=function(t){return c[t.toUpperCase()]},I._setListeners=function(){var e=this;this.config.trigger.split(" ").forEach(function(n){if("click"===n)t(e.element).on(e.constructor.Event.CLICK,e.config.selector,function(t){return e.toggle(t)});else if(n!==C){var i=n===E?e.constructor.Event.MOUSEENTER:e.constructor.Event.FOCUSIN,s=n===E?e.constructor.Event.MOUSELEAVE:e.constructor.Event.FOCUSOUT;t(e.element).on(i,e.config.selector,function(t){return e._enter(t)}).on(s,e.config.selector,function(t){return e._leave(t)})}t(e.element).closest(".modal").on("hide.bs.modal",function(){return e.hide()})}),this.config.selector?this.config=r({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},I._fixTitle=function(){var t=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},I._enter=function(e,n){var i=this.constructor.DATA_KEY;(n=n||t(e.currentTarget).data(i))||(n=new this.constructor(e.currentTarget,this._getDelegateConfig()),t(e.currentTarget).data(i,n)),e&&(n._activeTrigger["focusin"===e.type?T:E]=!0),t(n.getTipElement()).hasClass(p)||n._hoverState===f?n._hoverState=f:(clearTimeout(n._timeout),n._hoverState=f,n.config.delay&&n.config.delay.show?n._timeout=setTimeout(function(){n._hoverState===f&&n.show()},n.config.delay.show):n.show())},I._leave=function(e,n){var i=this.constructor.DATA_KEY;(n=n||t(e.currentTarget).data(i))||(n=new this.constructor(e.currentTarget,this._getDelegateConfig()),t(e.currentTarget).data(i,n)),e&&(n._activeTrigger["focusout"===e.type?T:E]=!1),n._isWithActiveTrigger()||(clearTimeout(n._timeout),n._hoverState=d,n.config.delay&&n.config.delay.hide?n._timeout=setTimeout(function(){n._hoverState===d&&n.hide()},n.config.delay.hide):n.hide())},I._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},I._getConfig=function(n){return"number"==typeof(n=r({},this.constructor.Default,t(this.element).data(),n)).delay&&(n.delay={show:n.delay,hide:n.delay}),"number"==typeof n.title&&(n.title=n.title.toString()),"number"==typeof n.content&&(n.content=n.content.toString()),P.typeCheckConfig(e,n,this.constructor.DefaultType),n},I._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},I._cleanTipClass=function(){var e=t(this.getTipElement()),n=e.attr("class").match(l);null!==n&&n.length>0&&e.removeClass(n.join(""))},I._handlePopperPlacementChange=function(t){this._cleanTipClass(),this.addAttachmentClass(this._getAttachment(t.placement))},I._fixTransition=function(){var e=this.getTipElement(),n=this.config.animation;null===e.getAttribute("x-placement")&&(t(e).removeClass(g),this.config.animation=!1,this.hide(),this.show(),this.config.animation=n)},a._jQueryInterface=function(e){return this.each(function(){var n=t(this).data(i),s="object"==typeof e&&e;if((n||!/dispose|hide/.test(e))&&(n||(n=new a(this,s),t(this).data(i,n)),"string"==typeof e)){if("undefined"==typeof n[e])throw new TypeError('No method named "'+e+'"');n[e]()}})},s(a,null,[{key:"VERSION",get:function(){return"4.0.0"}},{key:"Default",get:function(){return u}},{key:"NAME",get:function(){return e}},{key:"DATA_KEY",get:function(){return i}},{key:"Event",get:function(){return _}},{key:"EVENT_KEY",get:function(){return o}},{key:"DefaultType",get:function(){return h}}]),a}();return t.fn[e]=I._jQueryInterface,t.fn[e].Constructor=I,t.fn[e].noConflict=function(){return t.fn[e]=a,I._jQueryInterface},I}(e),x=function(t){var e="popover",n="bs.popover",i="."+n,o=t.fn[e],a=new RegExp("(^|\\s)bs-popover\\S+","g"),l=r({},U.Default,{placement:"right",trigger:"click",content:"",template:''}),h=r({},U.DefaultType,{content:"(string|element|function)"}),c="fade",u="show",f=".popover-header",d=".popover-body",_={HIDE:"hide"+i,HIDDEN:"hidden"+i,SHOW:"show"+i,SHOWN:"shown"+i,INSERTED:"inserted"+i,CLICK:"click"+i,FOCUSIN:"focusin"+i,FOCUSOUT:"focusout"+i,MOUSEENTER:"mouseenter"+i,MOUSELEAVE:"mouseleave"+i},g=function(r){var o,g;function p(){return r.apply(this,arguments)||this}g=r,(o=p).prototype=Object.create(g.prototype),o.prototype.constructor=o,o.__proto__=g;var m=p.prototype;return m.isWithContent=function(){return this.getTitle()||this._getContent()},m.addAttachmentClass=function(e){t(this.getTipElement()).addClass("bs-popover-"+e)},m.getTipElement=function(){return this.tip=this.tip||t(this.config.template)[0],this.tip},m.setContent=function(){var e=t(this.getTipElement());this.setElementContent(e.find(f),this.getTitle());var n=this._getContent();"function"==typeof n&&(n=n.call(this.element)),this.setElementContent(e.find(d),n),e.removeClass(c+" "+u)},m._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},m._cleanTipClass=function(){var e=t(this.getTipElement()),n=e.attr("class").match(a);null!==n&&n.length>0&&e.removeClass(n.join(""))},p._jQueryInterface=function(e){return this.each(function(){var i=t(this).data(n),s="object"==typeof e?e:null;if((i||!/destroy|hide/.test(e))&&(i||(i=new p(this,s),t(this).data(n,i)),"string"==typeof e)){if("undefined"==typeof i[e])throw new TypeError('No method named "'+e+'"');i[e]()}})},s(p,null,[{key:"VERSION",get:function(){return"4.0.0"}},{key:"Default",get:function(){return l}},{key:"NAME",get:function(){return e}},{key:"DATA_KEY",get:function(){return n}},{key:"Event",get:function(){return _}},{key:"EVENT_KEY",get:function(){return i}},{key:"DefaultType",get:function(){return h}}]),p}(U);return t.fn[e]=g._jQueryInterface,t.fn[e].Constructor=g,t.fn[e].noConflict=function(){return t.fn[e]=o,g._jQueryInterface},g}(e),K=function(t){var e="scrollspy",n="bs.scrollspy",i="."+n,o=t.fn[e],a={offset:10,method:"auto",target:""},l={offset:"number",method:"string",target:"(string|element)"},h={ACTIVATE:"activate"+i,SCROLL:"scroll"+i,LOAD_DATA_API:"load"+i+".data-api"},c="dropdown-item",u="active",f={DATA_SPY:'[data-spy="scroll"]',ACTIVE:".active",NAV_LIST_GROUP:".nav, .list-group",NAV_LINKS:".nav-link",NAV_ITEMS:".nav-item",LIST_ITEMS:".list-group-item",DROPDOWN:".dropdown",DROPDOWN_ITEMS:".dropdown-item",DROPDOWN_TOGGLE:".dropdown-toggle"},d="offset",_="position",g=function(){function o(e,n){var i=this;this._element=e,this._scrollElement="BODY"===e.tagName?window:e,this._config=this._getConfig(n),this._selector=this._config.target+" "+f.NAV_LINKS+","+this._config.target+" "+f.LIST_ITEMS+","+this._config.target+" "+f.DROPDOWN_ITEMS,this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,t(this._scrollElement).on(h.SCROLL,function(t){return i._process(t)}),this.refresh(),this._process()}var g=o.prototype;return g.refresh=function(){var e=this,n=this._scrollElement===this._scrollElement.window?d:_,i="auto"===this._config.method?n:this._config.method,s=i===_?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),t.makeArray(t(this._selector)).map(function(e){var n,r=P.getSelectorFromElement(e);if(r&&(n=t(r)[0]),n){var o=n.getBoundingClientRect();if(o.width||o.height)return[t(n)[i]().top+s,r]}return null}).filter(function(t){return t}).sort(function(t,e){return t[0]-e[0]}).forEach(function(t){e._offsets.push(t[0]),e._targets.push(t[1])})},g.dispose=function(){t.removeData(this._element,n),t(this._scrollElement).off(i),this._element=null,this._scrollElement=null,this._config=null,this._selector=null,this._offsets=null,this._targets=null,this._activeTarget=null,this._scrollHeight=null},g._getConfig=function(n){if("string"!=typeof(n=r({},a,n)).target){var i=t(n.target).attr("id");i||(i=P.getUID(e),t(n.target).attr("id",i)),n.target="#"+i}return P.typeCheckConfig(e,n,l),n},g._getScrollTop=function(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop},g._getScrollHeight=function(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)},g._getOffsetHeight=function(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height},g._process=function(){var t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),n=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=n){var i=this._targets[this._targets.length-1];this._activeTarget!==i&&this._activate(i)}else{if(this._activeTarget&&t0)return this._activeTarget=null,void this._clear();for(var s=this._offsets.length;s--;){this._activeTarget!==this._targets[s]&&t>=this._offsets[s]&&("undefined"==typeof this._offsets[s+1]||t=4)throw new Error("Bootstrap's JavaScript requires at least jQuery v1.9.1 but less than v4.0.0")}(e),t.Util=P,t.Alert=L,t.Button=R,t.Carousel=j,t.Collapse=H,t.Dropdown=W,t.Modal=M,t.Popover=x,t.Scrollspy=K,t.Tab=V,t.Tooltip=U,Object.defineProperty(t,"__esModule",{value:!0})}); 7 | //# sourceMappingURL=bootstrap.min.js.map --------------------------------------------------------------------------------