From 2f8c1bd513b56e05742aed4e76e7102383bd1447 Mon Sep 17 00:00:00 2001 From: Roman Munteanu Date: Fri, 20 Sep 2019 21:12:55 +0200 Subject: [PATCH 1/2] Issue #2911 - Create modals --- .../static/css/src/issue-wizard-popup.css | 97 +++++++++++ .../static/css/src/issue-wizard-slider.css | 151 ++++++++++++++++++ webcompat/static/css/src/issue-wizard.css | 7 +- webcompat/static/css/src/variables.css | 3 +- .../static/js/lib/issue-wizard-bugform.js | 115 ++++++++----- webcompat/static/js/lib/issue-wizard-popup.js | 42 +++++ .../static/js/lib/issue-wizard-slider.js | 95 +++++++++++ .../home-page/issue-wizard-form.html | 107 ++++++++++--- webcompat/templates/layout.html | 7 + 9 files changed, 566 insertions(+), 58 deletions(-) create mode 100644 webcompat/static/css/src/issue-wizard-popup.css create mode 100644 webcompat/static/css/src/issue-wizard-slider.css create mode 100644 webcompat/static/js/lib/issue-wizard-popup.js create mode 100644 webcompat/static/js/lib/issue-wizard-slider.js diff --git a/webcompat/static/css/src/issue-wizard-popup.css b/webcompat/static/css/src/issue-wizard-popup.css new file mode 100644 index 000000000..5e14eab28 --- /dev/null +++ b/webcompat/static/css/src/issue-wizard-popup.css @@ -0,0 +1,97 @@ +/* +* popup +* +---------------- +* DEPENDENCIES: +---------------- +* variable.css +*/ + +.popup-overlay { + background-color: rgba(0, 0, 0, .65); + display: none; + height: 100%; + left: 0; + position: fixed; + top: 0; + width: 100%; + z-index: 1010; +} + +.popup-overlay.is-blacked-out { + display: block; +} + +.popup-trigger { + display: inline-block; +} + +.popup-modal { + background-color: #fff; + border-radius: 5px; + height: 450px; + left: 50%; + opacity: 0; + overflow: hidden; + padding: 0; + pointer-events: none; + position: fixed; + top: 50%; + transform: translate(-50%, -50%); + transition: all 300ms ease-in-out; + width: 650px; + z-index: 1011; +} + +.popup-modal.text { + height: 400px; + width: 590px; +} + +.popup-modal.is--visible { + opacity: 1; + pointer-events: auto; +} + +.popup-modal__close:not(.close-control):not(.popup-overlay) { + cursor: pointer; + font-size: 1.2rem; + position: absolute; + right: 12px; + top: 12px; +} + +.popup-modal .close { + cursor: pointer; + position: absolute; + right: 12px; + top: 12px; + transition: transform .2s; + width: 22px; + z-index: 3; +} + +.popup-modal .close:hover { + transform: scale(1.1); +} + +.popup-text { + font-size: 18px; + padding: 0 16px; +} + +.popup-text h2 { + font-size: 32px; + font-weight: 300; + margin-bottom: 38px; +} + +.popup-modal .links { + padding-top: 32px; + text-align: center; +} + +.popup-modal .links a { + color: var(--link-color); + font-size: 16px; +} diff --git a/webcompat/static/css/src/issue-wizard-slider.css b/webcompat/static/css/src/issue-wizard-slider.css new file mode 100644 index 000000000..1ec7d5e33 --- /dev/null +++ b/webcompat/static/css/src/issue-wizard-slider.css @@ -0,0 +1,151 @@ +/* +* slider +* +---------------- +* DEPENDENCIES: +---------------- +* variable.css +*/ + +:root { + --slider-animation-distance: 100px; + --slider-title-transition: all .5s .1s; + --slider-text-transition: all .5s .2s; + --slider-image-transition: all .5s .3s; + --slide-height: 350px; +} + +.full-height { + height: 100%; +} + +.slider .slides { + min-height: var(--slide-height); + position: relative; +} + +.slider .slide { + height: 100%; + left: 0; + opacity: 0; + position: absolute; + transition: opacity .3s; + width: 100%; +} + +.slider .slide.active { + opacity: 1; + z-index: 2; +} + +.slider .text-half { + width: 60%; +} + +.slider .slide .text-half .title { + font-size: 32px; + left: var(--slider-animation-distance); + margin-top: 10px; + opacity: 0; + padding: 16px; + position: relative; + text-align: left; + transition: var(--slider-title-transition); +} + +.slider .slide.active .text-half .title { + left: 0; + opacity: 1; +} + +.slider .slide .text-half .text { + font-size: 18px; + left: var(--slider-animation-distance); + margin-top: 20px; + opacity: 0; + padding: 16px; + position: relative; + text-align: left; + transition: var(--slider-text-transition); +} + +.slider .slide.slide.active .text-half .text { + left: 0; + opacity: 1; +} + +.slider .slide .image-half { + align-items: center; + display: flex; + justify-content: center; + position: relative; + width: 40%; +} + +.slider .slide .image-half::before { + background-color: var(--upload-background); + border-bottom-left-radius: 50%; + border-top-left-radius: 50%; + content: ""; + height: 140%; + left: 0; + position: absolute; + top: -20%; + width: 100%; + z-index: -1; +} + +.slider .slide .image-half img { + left: var(--slider-animation-distance); + opacity: 0; + position: relative; + transition: var(--slider-image-transition); +} + +.slider .slide.active .image-half img { + left: 0; + opacity: 1; +} + +.controls { + margin-top: 0; +} + +.controls .row { + justify-content: center; +} + +.controls .dot { + background-color: var(--dot-color); + border-radius: 50%; + cursor: pointer; + height: 12px; + margin: 0 8px; + transition: all .3s cubic-bezier(.175, .885, .32, 1.275); + width: 12px; +} + +.controls .dot.active { + background-color: var(--wizard-step-color); + border: 2px solid var(--dot-color); + transform: scale(1.3); +} + +.controls .btn { + background-color: var(--color-first); + border: none; + border-radius: 5px; + cursor: pointer; + display: block; + margin: 22px auto 0; + min-width: 140px; + padding: 11px; +} + +.controls .btn:hover { + opacity: .85; +} + +.controls .btn.close-control { + display: none; +} diff --git a/webcompat/static/css/src/issue-wizard.css b/webcompat/static/css/src/issue-wizard.css index f70752290..a84a651d5 100644 --- a/webcompat/static/css/src/issue-wizard.css +++ b/webcompat/static/css/src/issue-wizard.css @@ -1,11 +1,16 @@ /* -* form +* issue wizard * ---------------- * DEPENDENCIES: ---------------- * variable.css */ + +@import "../src/variables.css"; +@import "../src/issue-wizard-popup.css"; +@import "../src/issue-wizard-slider.css"; + :root { --between-steps-margin: 53px; --presumed-step-height: -360px; diff --git a/webcompat/static/css/src/variables.css b/webcompat/static/css/src/variables.css index 01dfff867..003ac869b 100644 --- a/webcompat/static/css/src/variables.css +++ b/webcompat/static/css/src/variables.css @@ -65,5 +65,6 @@ --warning-border: rgba(255, 184, 158, 1); /* #ffb89e */ --screenshot-shadow: rgba(0, 0, 0, .3); /* #000000 */ --warm-grey: rgba(151, 151, 151, 1); /* #979797 */ - --upload-background: rgba(231, 231, 231, 1) /* #e7e7e7 */ + --upload-background: rgba(231, 231, 231, 1); /* #e7e7e7 */ + --dot-color: rgba(50, 60, 89, 1); /* #323c59 */ } diff --git a/webcompat/static/js/lib/issue-wizard-bugform.js b/webcompat/static/js/lib/issue-wizard-bugform.js index 86a3b1fae..c27e79ce5 100644 --- a/webcompat/static/js/lib/issue-wizard-bugform.js +++ b/webcompat/static/js/lib/issue-wizard-bugform.js @@ -42,6 +42,7 @@ BugForm.prototype.onDOMReadyInit = function() { this.step2Trigger = $(".next-step.step-2"); this.step3Trigger = $("#problem_category input"); this.step3Btn = $(".next-step.step-3"); + this.step4Trigger = $(".subproblem input[type='radio']"); this.step6Btn = $("button.next-step.step-6"); this.step8Btn = $("button.next-step.step-8"); this.step10Btn = $("button.next-step.step-10"); @@ -270,6 +271,9 @@ BugForm.prototype.init = function() { this.step3Trigger.on("change", this.nextStep.bind(this)); this.step3Radio.on("change", this.nextStep.bind(this)); this.step6Radio.on("change", this.nextStep.bind(this)); + + window.addEventListener("pageshow", this.resetProblemType.bind(this)); + // See if the user already has a valid form // (after a page refresh, back button, etc.) this.checkForm(); @@ -431,6 +435,7 @@ BugForm.prototype.determineValidityFunction = function(func, field, silent) { }; BugForm.prototype.checkProblemTypeValidity = function(silent) { + this.resetProblemSubcategory(this.problemType.val() + "_subcategory"); var func = this.determineValidityFunction( this.validation.isProblemTypeValid, this.problemType, @@ -776,6 +781,10 @@ BugForm.prototype.nextStep = function(e) { if (trigger.hasClass("disabled")) { return false; } + var hideStep = trigger.data("hidestep") || false; + if (trigger.val() === this.otherProblemId) { + hideStep = 4; + } var nextStepNumber = trigger.attr("type") === "radio" @@ -784,20 +793,8 @@ BugForm.prototype.nextStep = function(e) { var stepperIndex = trigger.parents(".step-container").data("activate-stepper") || false; - var hideStep = trigger.data("hidestep") || false; - if (nextStepNumber !== this.stepNotDefined) { - if ( - trigger.attr("type") === "radio" && - trigger.attr("name") === this.problemCategoryName - ) { - this.problemSubgategoryStep(trigger); - this.isSubproblem = true; - } else { - this.isSubproblem = false; - this.blockNext = false; - } - + this.checkIfSubproblem(trigger); if ( trigger.attr("type") === "radio" && trigger.attr("name") === this.browserSelectionName @@ -805,26 +802,55 @@ BugForm.prototype.nextStep = function(e) { this.browserSelectionStep(trigger); return; } - this.setActiveStep(stepperIndex); + this.stepRevealControl(nextStepNumber); + this.scrollToElement(nextStepNumber); + } - if ( - (!this.blockNext && !this.isSubproblem) || - (this.isSubproblem && this.skipOneStep) - ) { - var nextStep = this.skipOneStep ? nextStepNumber : nextStepNumber - 1; - this.skipOneStep = false; - var animation = - this.stepsArray[nextStep][0].style.animationName !== - this.cssAnimations.slidedownandheight - ? this.cssAnimations.slidedown - : this.cssAnimations.slideupandheight; - this.stepsArray[nextStep][0].style.animationName = animation; - this.stepsArray[nextStep][0].classList.add("open"); - } + if (hideStep) { + this.hideStep(hideStep); } + return false; +}; - var scrollToEl = this.stepsArray[nextStepNumber - 1][0]; +BugForm.prototype.checkIfSubproblem = function(trigger) { + if ( + trigger.attr("type") === "radio" && + trigger.attr("name") === this.problemCategoryName + ) { + this.problemSubgategoryStep(trigger); + this.isSubproblem = true; + } else { + this.isSubproblem = false; + this.blockNext = false; + } +}; + +BugForm.prototype.hideStep = function(stepToHide) { + this.stepsArray[ + stepToHide - 1 + ][0].style.animationName = this.cssAnimations.slideupandheight; +}; + +BugForm.prototype.stepRevealControl = function(nextStepNumber) { + if ( + (!this.blockNext && !this.isSubproblem) || + (this.isSubproblem && this.skipOneStep) + ) { + var nextStep = this.skipOneStep ? nextStepNumber : nextStepNumber - 1; + this.skipOneStep = false; + var animation = + this.stepsArray[nextStep][0].style.animationName !== + this.cssAnimations.slidedownandheight + ? this.cssAnimations.slidedown + : this.cssAnimations.slideupandheight; + this.stepsArray[nextStep][0].style.animationName = animation; + this.stepsArray[nextStep][0].classList.add("open"); + } +}; + +BugForm.prototype.scrollToElement = function(nextStep) { + var scrollToEl = this.stepsArray[nextStep - 1][0]; // Delay "scroll to element" effect in order to let the animation finish, otherwise the scroll point isn't correct setTimeout( function() { @@ -836,14 +862,6 @@ BugForm.prototype.nextStep = function(e) { }.bind(this), this.isSubproblem ? 450 : 250 ); - - if (hideStep) { - this.stepsArray[ - hideStep - 1 - ][0].style.animationName = this.cssAnimations.slideupandheight; - } - - return false; }; BugForm.prototype.setActiveStep = function(nextStep) { @@ -868,6 +886,11 @@ BugForm.prototype.problemSubgategoryStep = function(trigger) { ? this.slideUpTimeout : 0; + if (!isOther) { + this.inputs["other_problem"].el[0].value = ""; + this.makeInvalidSilent("other_problem"); + } + $(".step" + this.subproblemStep) .find("ul") .each(function() { @@ -1171,6 +1194,24 @@ BugForm.prototype.handleUploadError = function(response) { this.removeUploadPreview(); }; +BugForm.prototype.resetProblemType = function() { + this.resetRadio(this.step3Trigger); +}; + +BugForm.prototype.resetProblemSubcategory = function(subformName) { + var resetElements = + subformName && subformName.length > 0 + ? this.step4Trigger.not("input[name='" + subformName + "']") + : this.step4Trigger; + this.resetRadio(resetElements); +}; + +BugForm.prototype.resetRadio = function(element) { + element.each(function() { + $(this).prop("checked", false); + }); +}; + BugForm.prototype.submitForm = function() { var dfd = $.Deferred(); var formEl = this.form.get(0); diff --git a/webcompat/static/js/lib/issue-wizard-popup.js b/webcompat/static/js/lib/issue-wizard-popup.js new file mode 100644 index 000000000..4191d713c --- /dev/null +++ b/webcompat/static/js/lib/issue-wizard-popup.js @@ -0,0 +1,42 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +function Popup() { + this.init = function() { + this.setUpEvents(); + }; + + this.setUpEvents = function() { + this.popupHandler(); + }; + + this.popupHandler = function() { + var modalTriggers = document.querySelectorAll(".popup-trigger"); + var overlay = document.querySelector(".popup-overlay"); + var closeButtons = document.querySelectorAll(".popup-modal__close"); + modalTriggers.forEach(function(trigger) { + trigger.addEventListener("click", function(e) { + e.preventDefault(); + var popupTrigger = trigger.dataset.popupTrigger; + var popupModal = document.querySelector( + '[data-popup-modal="'.concat(popupTrigger, '"]') + ); + popupModal.classList.add("is--visible"); + overlay.classList.add("is-blacked-out"); + closeButtons.forEach(function(btn) { + btn.addEventListener("click", function() { + popupModal.classList.remove("is--visible"); + overlay.classList.remove("is-blacked-out"); + }); + }); + }); + }); + }; + + return this.init(); +} + +$(function() { + new Popup(); +}); diff --git a/webcompat/static/js/lib/issue-wizard-slider.js b/webcompat/static/js/lib/issue-wizard-slider.js new file mode 100644 index 000000000..38e26e619 --- /dev/null +++ b/webcompat/static/js/lib/issue-wizard-slider.js @@ -0,0 +1,95 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +function Slider() { + this.init = function() { + this.setUpEvents(); + }; + + this.setUpEvents = function() { + this.sliderHandler(); + }; + + this.sliderHandler = function() { + var nextBtn = document.querySelectorAll(".slider .next"); + var prevBtn = document.querySelectorAll(".slider .prev"); + var dot = document.querySelectorAll(".slider .dot"); + var slide = document.querySelectorAll(".slider .slides .slide"); + var controlNext = document.querySelector(".slider .controls .next"); + var controlFinish = document.querySelector( + ".slider .controls .close-control" + ); + // Intercepted popup close buttons that trigger the return to first slide + var closeButtons = document.querySelectorAll(".popup-modal__close"); + var index = 0; + + var setActiveControls = function(index) { + var selectedDot = document.querySelector(".slider .dot.active"); + selectedDot.classList.remove("active"); + dot.forEach(function(d) { + if (index === $(d).data("slide")) { + d.classList.add("active"); + } + }); + if (index === slide.length - 1) { + controlNext.style.display = "none"; + controlFinish.style.display = "block"; + } else { + controlNext.style.display = "block"; + controlFinish.style.display = "none"; + } + }; + + prevBtn.forEach(function(btn) { + btn.addEventListener("click", function() { + index--; + if (index < 0) { + index = 0; + return false; + } + slide[index + 1].classList.remove("active"); + slide[index].classList.add("active"); + setActiveControls(index); + }); + }); + + nextBtn.forEach(function(btn) { + btn.addEventListener("click", function() { + index++; + if (index >= slide.length) { + index--; + return false; + } + slide[index - 1].classList.remove("active"); + slide[index].classList.add("active"); + setActiveControls(index); + }); + }); + + dot.forEach(function(d) { + d.addEventListener("click", function() { + slide[index].classList.remove("active"); + index = $(d).data("slide"); + slide[index].classList.add("active"); + setActiveControls(index); + }); + }); + + closeButtons.forEach(function(btn) { + btn.addEventListener("click", function() { + slide[index].classList.remove("active"); + index = 0; + slide[index].classList.add("active"); + dot[index].click(); + setActiveControls(index); + }); + }); + }; + + return this.init(); +} + +$(function() { + new Slider(); +}); diff --git a/webcompat/templates/home-page/issue-wizard-form.html b/webcompat/templates/home-page/issue-wizard-form.html index 7625203da..feae8cbcb 100644 --- a/webcompat/templates/home-page/issue-wizard-form.html +++ b/webcompat/templates/home-page/issue-wizard-form.html @@ -39,14 +39,14 @@

Filing a web compatibility issue

-
All information included in this report will be publicly visible. Learn More
+
All information included in this report will be publicly visible. Learn More
@@ -60,7 +60,7 @@

Filing a web compatibility issue

{% endfor %} {% endif %}
- {{form.problem_category}} + {{form.problem_category(autocomplete='off')}}
@@ -77,7 +77,7 @@

Filing a web compatibility issue

- +
@@ -126,7 +126,7 @@

Filing a web compatibility issue

- Device data image + Device data image
@@ -139,7 +139,7 @@

Filing a web compatibility issue

- +
I encountered the issue on a  different device or browser
@@ -171,7 +171,7 @@

Filing a web compatibility issue

- +
@@ -206,7 +206,7 @@

Filing a web compatibility issue

@@ -217,8 +217,8 @@

Filing a web compatibility issue

Warning
We recommend testing the website in another browser to validate this as a web compatibility issue.
- - What is a web compatibility issue? + + What is a web compatibility issue?
@@ -235,7 +235,7 @@

Filing a web compatibility issue

{{ form.steps_reproduce(class_='form-field text-field js-autogrow-field', - rows=3, placeholder="Describe what happened") }} + rows=3, maxlength=200, placeholder="Describe what happened") }}
Valid message
@@ -247,7 +247,7 @@

Filing a web compatibility issue

- +
@@ -272,8 +272,8 @@

Filing a web compatibility issue

- - + +
Upload a different image
@@ -300,11 +300,11 @@

Filing a web compatibility issue

-
+
{{ form.image(class_='form-input input-upload', accept='.jpe,.jpg,.jpeg,.gif,.png,.bmp', id='image') }}
- Upload screenshot + Upload screenshot
Upload screenshot
@@ -326,8 +326,8 @@

Filing a web compatibility issue

- - + +
@@ -364,3 +364,72 @@

Filing a web compatibility issue

{{ form.hidden_tag() }} + + + + + + diff --git a/webcompat/templates/layout.html b/webcompat/templates/layout.html index e4d43c0a5..09fbdf5d0 100644 --- a/webcompat/templates/layout.html +++ b/webcompat/templates/layout.html @@ -36,7 +36,14 @@ + +{%- if ab_active('exp') == 'form-v2' %} + + +{% endif %} + + {%- if config['LOCALHOST'] -%} From 8f24c71a3e91d948430710bec07560d5cac397da Mon Sep 17 00:00:00 2001 From: Roman Munteanu Date: Fri, 20 Sep 2019 21:15:41 +0200 Subject: [PATCH 2/2] Issue #2911 - Add SVG images --- webcompat/static/img/svg/help-step-1.svg | 26 +++ webcompat/static/img/svg/help-step-2.svg | 22 +++ webcompat/static/img/svg/help-step-3.svg | 39 ++++ .../static/img/svg/icons/svg-cross-black.svg | 4 + .../static/img/svg/icons/svg-github-white.svg | 4 + .../img/svg/icons/svg-question-mark.svg | 9 + webcompat/static/img/svg/sprite.svg | 176 ++++++++++++------ 7 files changed, 227 insertions(+), 53 deletions(-) create mode 100644 webcompat/static/img/svg/help-step-1.svg create mode 100644 webcompat/static/img/svg/help-step-2.svg create mode 100644 webcompat/static/img/svg/help-step-3.svg create mode 100644 webcompat/static/img/svg/icons/svg-cross-black.svg create mode 100644 webcompat/static/img/svg/icons/svg-github-white.svg create mode 100644 webcompat/static/img/svg/icons/svg-question-mark.svg diff --git a/webcompat/static/img/svg/help-step-1.svg b/webcompat/static/img/svg/help-step-1.svg new file mode 100644 index 000000000..d73cb5171 --- /dev/null +++ b/webcompat/static/img/svg/help-step-1.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/webcompat/static/img/svg/help-step-2.svg b/webcompat/static/img/svg/help-step-2.svg new file mode 100644 index 000000000..469626c4a --- /dev/null +++ b/webcompat/static/img/svg/help-step-2.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/webcompat/static/img/svg/help-step-3.svg b/webcompat/static/img/svg/help-step-3.svg new file mode 100644 index 000000000..1a5602583 --- /dev/null +++ b/webcompat/static/img/svg/help-step-3.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/webcompat/static/img/svg/icons/svg-cross-black.svg b/webcompat/static/img/svg/icons/svg-cross-black.svg new file mode 100644 index 000000000..1045f47e0 --- /dev/null +++ b/webcompat/static/img/svg/icons/svg-cross-black.svg @@ -0,0 +1,4 @@ + + cross-black + + diff --git a/webcompat/static/img/svg/icons/svg-github-white.svg b/webcompat/static/img/svg/icons/svg-github-white.svg new file mode 100644 index 000000000..446727382 --- /dev/null +++ b/webcompat/static/img/svg/icons/svg-github-white.svg @@ -0,0 +1,4 @@ + + github-white + + diff --git a/webcompat/static/img/svg/icons/svg-question-mark.svg b/webcompat/static/img/svg/icons/svg-question-mark.svg new file mode 100644 index 000000000..0bf729746 --- /dev/null +++ b/webcompat/static/img/svg/icons/svg-question-mark.svg @@ -0,0 +1,9 @@ + + question-mark + Created with Sketch. + + + + + + \ No newline at end of file diff --git a/webcompat/static/img/svg/sprite.svg b/webcompat/static/img/svg/sprite.svg index d4636f2df..f3788df9e 100644 --- a/webcompat/static/img/svg/sprite.svg +++ b/webcompat/static/img/svg/sprite.svg @@ -1,110 +1,180 @@ -arrow-down + -arrow + -at-sign + - + -bug + - + -check + -checkbox-checked + -checkbox-unchecked + -svg-checkmark + -chevron-right + -chevrons-right + -circle-down + -circle-left + -circle-right + -circle-up + -cloud2 + -svg-cross2 + -download + -download + -external-link + -filter + -github + -hash + -home + -leaf + -leaf + -left + -link-2 + -log-in + -log-out + -mail + -menu + -message-square + -minus + -plus + -radio-checked + -radio-checked2 + -radio-unchecked + -search + -settings + -slack + - + -spinner8 + -target + -twitter + -up + -upload-2 + -user + -users + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -warning + -x + -zap + \ No newline at end of file