From 0eed921cf68623455fbbe4c18e9650df6c31bef7 Mon Sep 17 00:00:00 2001 From: MiriamKyoseva <133047546+MiriamKyoseva@users.noreply.github.com> Date: Mon, 27 May 2024 11:59:19 +0300 Subject: [PATCH 01/94] Renamed TextFindStrategy to InnerTextContainingFindStrategy and made it use XPath - to match with the corresponding find strategy in web module --- .../InnerTextContainingFindStrategy.java | 29 ++++++++++ .../findstrategies/TextFindStrategy.java | 57 ------------------- 2 files changed, 29 insertions(+), 57 deletions(-) create mode 100644 bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/findstrategies/InnerTextContainingFindStrategy.java delete mode 100644 bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/findstrategies/TextFindStrategy.java diff --git a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/findstrategies/InnerTextContainingFindStrategy.java b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/findstrategies/InnerTextContainingFindStrategy.java new file mode 100644 index 00000000..5dfdd324 --- /dev/null +++ b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/findstrategies/InnerTextContainingFindStrategy.java @@ -0,0 +1,29 @@ +/* + * Copyright 2024 Automate The Planet Ltd. + * Author: Miriam Kyoseva + * Licensed under the Apache License, Version 2.0 (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package solutions.bellatrix.playwright.findstrategies; + +import com.microsoft.playwright.Page; +import lombok.Getter; +import solutions.bellatrix.playwright.components.common.webelement.WebElement; +import solutions.bellatrix.playwright.findstrategies.options.TextOptions; +import solutions.bellatrix.playwright.findstrategies.utils.By; + +import java.util.regex.Pattern; + +@Getter +public class InnerTextContainingFindStrategy extends XpathFindStrategy { + public InnerTextContainingFindStrategy(String text) { + super(String.format("//*contains(text(), '%s')", text)); + } +} diff --git a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/findstrategies/TextFindStrategy.java b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/findstrategies/TextFindStrategy.java deleted file mode 100644 index d77920f0..00000000 --- a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/findstrategies/TextFindStrategy.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2024 Automate The Planet Ltd. - * Author: Miriam Kyoseva - * Licensed under the Apache License, Version 2.0 (the "License"); - * You may not use this file except in compliance with the License. - * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package solutions.bellatrix.playwright.findstrategies; - -import com.microsoft.playwright.Page; -import lombok.Getter; -import solutions.bellatrix.playwright.components.common.webelement.WebElement; -import solutions.bellatrix.playwright.findstrategies.options.TextOptions; -import solutions.bellatrix.playwright.findstrategies.utils.By; - -import java.util.regex.Pattern; - -@Getter -public class TextFindStrategy extends PatternStrategy { - public TextFindStrategy(String text) { - this.text = text; - } - - public TextFindStrategy(Pattern pattern) { - this.pattern = pattern; - } - - public TextFindStrategy(String text, TextOptions options) { - this.text = text; - this.options = options; - } - - public TextFindStrategy(Pattern pattern, TextOptions options) { - this.pattern = pattern; - this.options = options; - } - - @Override - public WebElement convert(Page page) { - if (text != null) return get(page, By.TEXT, text, ((TextOptions)options).absolute()); - if (pattern != null) return get(page, By.TEXT, pattern, ((TextOptions)options).absolute()); - return null; - } - - @Override - public WebElement convert(WebElement locator) { - if (text != null) return get(locator, By.TEXT, text, ((TextOptions)options).relative()); - if (pattern != null) return get(locator, By.TEXT, pattern, ((TextOptions)options).relative()); - return null; - } -} From 10c5c3e9bfc3d250b818b52e10d7c7c0e2c6fe50 Mon Sep 17 00:00:00 2001 From: MiriamKyoseva <133047546+MiriamKyoseva@users.noreply.github.com> Date: Mon, 27 May 2024 11:59:54 +0300 Subject: [PATCH 02/94] Update testFrameworkSettings.dev.json --- .../src/main/resources/testFrameworkSettings.dev.json | 1 + 1 file changed, 1 insertion(+) diff --git a/bellatrix.playwright.getting.started/src/main/resources/testFrameworkSettings.dev.json b/bellatrix.playwright.getting.started/src/main/resources/testFrameworkSettings.dev.json index 4a77d263..023d0c91 100644 --- a/bellatrix.playwright.getting.started/src/main/resources/testFrameworkSettings.dev.json +++ b/bellatrix.playwright.getting.started/src/main/resources/testFrameworkSettings.dev.json @@ -10,6 +10,7 @@ "artificialDelayBeforeAction": "0", "automaticallyScrollToVisible": "false", "waitUntilReadyOnElementFound": "false", + "toastNotificationBddLogging": "false", "waitForAngular": "false", "shouldHighlightElements": "true", "shouldCaptureHttpTraffic": "false", From bc86036d07b1d474c92100c8dd35d2ffd5eb69ad Mon Sep 17 00:00:00 2001 From: MiriamKyoseva <133047546+MiriamKyoseva@users.noreply.github.com> Date: Mon, 27 May 2024 12:01:54 +0300 Subject: [PATCH 03/94] Created HtmlService An utility class used by bellatrix.web and bellatrix.playwright modules for the purpose of finding through xpath an element, getting its absolute position (absolute xpath), and converting it to CSS locator. --- .../bellatrix/core/utilities/HtmlService.java | 167 ++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/HtmlService.java diff --git a/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/HtmlService.java b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/HtmlService.java new file mode 100644 index 00000000..65920752 --- /dev/null +++ b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/HtmlService.java @@ -0,0 +1,167 @@ +/* + * Copyright 2024 Automate The Planet Ltd. + * Author: Miriam Kyoseva + * Licensed under the Apache License, Version 2.0 (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package solutions.bellatrix.core.utilities; + +import lombok.experimental.UtilityClass; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Element; + +import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Web Utility Class + */ +@UtilityClass +public class HtmlService { + public static String findCssLocator(String html, String xpath) { + var absoluteXpath = HtmlService.findElementAbsoluteXpath(html, xpath); + + return HtmlService.convertXpathToCss(absoluteXpath); + } + + public static String findRelativeCssLocator(Element element, String xpath) { + var absoluteXpath = HtmlService.findRelativeElementAbsoluteXpath(element, xpath); + + return HtmlService.convertXpathToCss(absoluteXpath); + } + + public static ArrayList findCssLocators(String html, String xpath) { + var absoluteXpaths = HtmlService.findElementsAbsoluteXpath(html, xpath); + + return HtmlService.convertXpathToCss(absoluteXpaths); + } + + public static ArrayList findRelativeCssLocators(Element element, String xpath) { + var absoluteXpaths = HtmlService.findRelativeElementsAbsoluteXpath(element, xpath); + + return HtmlService.convertXpathToCss(absoluteXpaths); + } + + public static Element findElement(String html, String cssQuery) { + var doc = Jsoup.parse(html); + + return doc.select(cssQuery).stream().findFirst() + .orElseThrow(() -> new IllegalArgumentException(String.format("No element was found with the css: %s", cssQuery))); + } + + private static String findElementAbsoluteXpath(String html, String xpath) { + var doc = Jsoup.parse(html); + var el = doc.selectXpath(xpath); + + if (el.isEmpty()) { + throw new IllegalArgumentException(String.format("No element was found with the xpath: %s", xpath)); + } + + return getAbsoluteXPath(el.first()); + } + + private static ArrayList findElementsAbsoluteXpath(String html, String xpath) { + var doc = Jsoup.parse(html); + var elements = doc.selectXpath(xpath).stream().toList(); + + if (elements.isEmpty()) { + throw new IllegalArgumentException(String.format("No elements were found with the xpath: %s", xpath)); + } + + ArrayList individualQueries = new ArrayList<>(); + + for (Element el : elements) { + individualQueries.add(getAbsoluteXPath(el)); + } + + return individualQueries; + } + + private static String findRelativeElementAbsoluteXpath(Element baseElement, String xpath) { + var el = baseElement.selectXpath(xpath); + + if (el.isEmpty()) { + throw new IllegalArgumentException(String.format("No element was found with the xpath: %s", xpath)); + } + + return getAbsoluteXPath(el.first()); + } + + private static ArrayList findRelativeElementsAbsoluteXpath(Element baseElement, String xpath) { + var elements = baseElement.selectXpath(xpath).stream().toList(); + + if (elements.isEmpty()) { + throw new IllegalArgumentException(String.format("No elements were found with the xpath: %s", xpath)); + } + + ArrayList queries = new ArrayList(); + + for (Element el : elements) { + queries.add(getAbsoluteXPath(el)); + } + + return queries; + } + + private static String convertXpathToCss(String xpath) { + String cssSelector = xpath.replace("/", " > "); + + // Use regular expression to replace [number] with :nth-child(number) + Pattern pattern = Pattern.compile("\\[(\\d+)\\]"); + Matcher matcher = pattern.matcher(cssSelector); + StringBuilder builder = new StringBuilder(); + + while (matcher.find()) { + matcher.appendReplacement(builder, ":nth-child(" + matcher.group(1) + ")"); + } + matcher.appendTail(builder); + + var semiFinalLocator = builder.toString(); + + if (semiFinalLocator.startsWith(" > ")) { + semiFinalLocator = semiFinalLocator.substring(2); + } + + return semiFinalLocator; + } + + private static ArrayList convertXpathToCss(ArrayList queries) { + for (String query : queries) { + query = convertXpathToCss(query); + } + + return queries; + } + + private static String getAbsoluteXPath(Element element) { + StringBuilder xpath = new StringBuilder("/"); + + for (Element el : element.parents()) { + + if (el.tagName().equals("html") || el.tagName().equals("body")) { + // ignore the and , because jsoup added them to the html fragment + continue; + } + + int index = 1; + for (Element sibling : el.siblingElements()) { + if (sibling.tagName().equals(el.tagName())) { + index++; + } + } + xpath.insert(0, "/" + el.tagName() + "[" + index + "]"); + } + + xpath.append(element.tagName()); + + return xpath.toString(); + } +} From 3d13d2d833553555dc2e615404d6411f283d2649 Mon Sep 17 00:00:00 2001 From: MiriamKyoseva <133047546+MiriamKyoseva@users.noreply.github.com> Date: Mon, 27 May 2024 12:03:03 +0300 Subject: [PATCH 04/94] Created ShadowXPathFindStrategy Strategy that uses CSS to locate elements, but saves the original XPath for debugging purposes. --- .../ShadowXpathFindStrategy.java | 37 +++++++++++++++++ .../ShadowXPathFindStrategy.java | 40 +++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/findstrategies/ShadowXpathFindStrategy.java create mode 100644 bellatrix.web/src/main/java/solutions/bellatrix/web/findstrategies/ShadowXPathFindStrategy.java diff --git a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/findstrategies/ShadowXpathFindStrategy.java b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/findstrategies/ShadowXpathFindStrategy.java new file mode 100644 index 00000000..2a853a73 --- /dev/null +++ b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/findstrategies/ShadowXpathFindStrategy.java @@ -0,0 +1,37 @@ +/* + * Copyright 2024 Automate The Planet Ltd. + * Author: Miriam Kyoseva + * Licensed under the Apache License, Version 2.0 (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package solutions.bellatrix.playwright.findstrategies; + +import com.microsoft.playwright.Page; +import lombok.Getter; +import solutions.bellatrix.playwright.components.common.webelement.WebElement; +import solutions.bellatrix.playwright.findstrategies.utils.By; + +/** + * Strategy that uses CSS to locate elements, but saves the original XPath for debugging purposes.
+ */ +@Getter +public class ShadowXpathFindStrategy extends CssFindStrategy { + private final String originalXpath; + + public ShadowXpathFindStrategy(String xpath, String cssLocator) { + super(cssLocator); + originalXpath = xpath; + } + + @Override + public String toString() { + return String.format("xpath = %s ; css = %s", originalXpath, getValue()); + } +} diff --git a/bellatrix.web/src/main/java/solutions/bellatrix/web/findstrategies/ShadowXPathFindStrategy.java b/bellatrix.web/src/main/java/solutions/bellatrix/web/findstrategies/ShadowXPathFindStrategy.java new file mode 100644 index 00000000..13f41591 --- /dev/null +++ b/bellatrix.web/src/main/java/solutions/bellatrix/web/findstrategies/ShadowXPathFindStrategy.java @@ -0,0 +1,40 @@ +/* + * Copyright 2022 Automate The Planet Ltd. + * Author: Anton Angelov + * Licensed under the Apache License, Version 2.0 (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package solutions.bellatrix.web.findstrategies; + +import lombok.Getter; +import org.openqa.selenium.By; + + +/** + * Strategy that uses CSS to locate elements, but saves the original XPath for debugging purposes.
+ */ +@Getter +public class ShadowXPathFindStrategy extends FindStrategy { + String originalXpath; + public ShadowXPathFindStrategy(String xpath, String css) { + super(css); + originalXpath = xpath; + } + + @Override + public By convert() { + return By.cssSelector(getValue()); + } + + @Override + public String toString() { + return String.format("xpath = %s ; css = %s", originalXpath, getValue()); + } +} From 3f8eadecf9b265fadb2156c39670304ef6b5aa3b Mon Sep 17 00:00:00 2001 From: MiriamKyoseva <133047546+MiriamKyoseva@users.noreply.github.com> Date: Mon, 27 May 2024 12:05:46 +0300 Subject: [PATCH 05/94] Created ShadowRoot component and changed the component creation logic --- .../playwright/components/ShadowRoot.java | 39 ++ .../playwright/components/WebComponent.java | 421 ++++++++++++++++-- .../common/create/RelativeCreateService.java | 115 ++++- .../create/ShadowRootCreateService.java | 107 +++++ .../services/ComponentCreateService.java | 32 +- .../bellatrix/web/components/ShadowRoot.java | 103 +++++ .../web/components/WebComponent.java | 244 +++++++++- 7 files changed, 976 insertions(+), 85 deletions(-) create mode 100644 bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/ShadowRoot.java create mode 100644 bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/create/ShadowRootCreateService.java create mode 100644 bellatrix.web/src/main/java/solutions/bellatrix/web/components/ShadowRoot.java diff --git a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/ShadowRoot.java b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/ShadowRoot.java new file mode 100644 index 00000000..295dc85e --- /dev/null +++ b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/ShadowRoot.java @@ -0,0 +1,39 @@ +/* + * Copyright 2024 Automate The Planet Ltd. + * Author: Miriam Kyoseva + * Licensed under the Apache License, Version 2.0 (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package solutions.bellatrix.playwright.components; + +import solutions.bellatrix.playwright.components.common.create.ShadowRootCreateService; +import solutions.bellatrix.playwright.components.common.webelement.WebElement; +import solutions.bellatrix.playwright.components.contracts.ComponentHtml; +import solutions.bellatrix.playwright.utilities.Settings; + +public class ShadowRoot extends WebComponent implements ComponentHtml { + public ShadowRoot() { + createService = new ShadowRootCreateService(this, CREATING, CREATED); + webSettings = Settings.web(); + } + + public ShadowRoot(WebElement element) { + this.wrappedElement = element; + createService = new ShadowRootCreateService(this, CREATING, CREATED); + webSettings = Settings.web(); + } + + /** + * Returns the innerHTML of the shadowRoot of the shadow host. + */ + public String getHtml() { + return (String)wrappedElement.evaluate("el => el.shadowRoot.innerHTML"); + } +} diff --git a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/WebComponent.java b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/WebComponent.java index eb5bbf18..33fa2e0a 100644 --- a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/WebComponent.java +++ b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/WebComponent.java @@ -75,7 +75,7 @@ public class WebComponent extends LayoutComponentValidationsBuilder implements C public final static EventListener CREATING = new EventListener<>(); public final static EventListener CREATED = new EventListener<>(); - private final WebSettings webSettings; + protected WebSettings webSettings; @Getter @Setter private WebComponent parentComponent; @Getter @Setter private int elementIndex; @Getter @Setter protected FindStrategy findStrategy; @@ -123,6 +123,7 @@ public ComponentT as(Class compone } public WebElement getWrappedElement() { + RETURNING_WRAPPED_ELEMENT.broadcast(new ComponentActionEventArgs(this)); return wrappedElement; } @@ -194,6 +195,10 @@ public WebElement findLocator() { return wrappedElement; } + public ShadowRoot getShadowRoot() { + return this.as(ShadowRoot.class); + } + @Override public Point getLocation() { return new Point((int)getBoundingBox().x, (int)getBoundingBox().y); @@ -615,425 +620,771 @@ public TElementType waitToBe() { // createBy methods + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public TComponent createByName(Class componentClass, String name) { return create().by(componentClass, new NameFindStrategy(name)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public List createAllByName(Class componentClass, String name) { return create().allBy(componentClass, new NameFindStrategy(name)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public TComponent createByNameEndingWith(Class componentClass, String value) { return create().by(componentClass, new NameEndingWithFindStrategy(value)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public List createAllByNameEndingWith(Class componentClass, String value) { return create().allBy(componentClass, new NameEndingWithFindStrategy(value)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public TComponent createByTag(Class componentClass, String tag) { return create().by(componentClass, new TagFindStrategy(tag)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public List createAllByTag(Class componentClass, String tag) { return create().allBy(componentClass, new TagFindStrategy(tag)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public TComponent createByValueContaining(Class componentClass, String value) { return create().by(componentClass, new ValueContainingFindStrategy(value)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public List createAllByValueContaining(Class componentClass, String value) { return create().allBy(componentClass, new ValueContainingFindStrategy(value)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public TComponent createByLinkText(Class componentClass, String text) { return create().by(componentClass, new LinkTextFindStrategy(text)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public List createAllByLinkText(Class componentClass, String text) { return create().allBy(componentClass, new LinkTextFindStrategy(text)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public TComponent createByLinkTextContaining(Class componentClass, String text) { return create().by(componentClass, new LinkTextContainingFindStrategy(text)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public List createAllByLinkTextContaining(Class componentClass, String text) { return create().allBy(componentClass, new LinkTextContainingFindStrategy(text)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public TComponent createByIdEndingWith(Class componentClass, String value) { return create().by(componentClass, new IdEndingWithFindStrategy(value)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public List createAllByIdEndingWith(Class componentClass, String value) { return create().allBy(componentClass, new IdEndingWithFindStrategy(value)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public TComponent createByPlaceholder(Class componentClass, String text) { return create().byPlaceholder(componentClass, text, null); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public List createAllByPlaceholder(Class componentClass, String text) { return create().allByPlaceholder(componentClass, text, null); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public TComponent createByPlaceholder(Class componentClass, Pattern pattern) { return create().byPlaceholder(componentClass, pattern, null); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public List createAllByPlaceholder(Class componentClass, Pattern pattern) { return create().allByPlaceholder(componentClass, pattern, null); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public TComponent createByRole(Class componentClass, AriaRole role) { return create().byRole(componentClass, role, null); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public List createAllByRole(Class componentClass, AriaRole role) { return create().allByRole(componentClass, role, null); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public TComponent createByAltText(Class componentClass, String text) { return create().byAltText(componentClass, text, null); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public List createAllByAltText(Class componentClass, String text) { return create().allByAltText(componentClass, text, null); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public TComponent createByAltText(Class componentClass, Pattern pattern) { return create().byAltText(componentClass, pattern, null); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public List createAllByAltText(Class componentClass, Pattern pattern) { return create().allByAltText(componentClass, pattern, null); } - public TComponent createByText(Class componentClass, String text) { - return create().byText(componentClass, text, null); - } - - public List createAllByText(Class componentClass, String text) { - return create().allByText(componentClass, text, null); - } - + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public TComponent createByTextContaining(Class componentClass, String text) { - return create().byText(componentClass, Pattern.compile(String.format(".*%s.*", text)), null); + return create().byInnerTextContaining(componentClass, text); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public List createAllByTextContaining(Class componentClass, String text) { - return create().allByText(componentClass, Pattern.compile(String.format(".*%s.*", text)), null); + return create().allByInnerTextContaining(componentClass, text); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public TComponent createByTitle(Class componentClass, String text) { return create().byTitle(componentClass, text, null); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public List createAllByTitle(Class componentClass, String text) { return create().allByTitle(componentClass, text, null); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public TComponent createByTitle(Class componentClass, Pattern pattern) { return create().byTitle(componentClass, pattern, null); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public List createAllByTitle(Class componentClass, Pattern pattern) { return create().allByTitle(componentClass, pattern, null); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public TComponent createByIdContaining(Class componentClass, String value) { return create().by(componentClass, new IdContainingFindStrategy(value)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public List createAllByIdContaining(Class componentClass, String value) { return create().allBy(componentClass, new IdContainingFindStrategy(value)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public TComponent createById(Class componentClass, String value) { return create().by(componentClass, new IdFindStrategy(value)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public List createAllById(Class componentClass, String value) { return create().allBy(componentClass, new IdFindStrategy(value)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public TComponent createByClass(Class componentClass, String value) { return create().by(componentClass, new ClassFindStrategy(value)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public List createAllByClass(Class componentClass, String value) { return create().allBy(componentClass, new ClassFindStrategy(value)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public TComponent createByClassContaining(Class componentClass, String value) { return create().by(componentClass, new ClassContainingFindStrategy(value)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public List createAllByClassContaining(Class componentClass, String value) { return create().allBy(componentClass, new ClassContainingFindStrategy(value)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public TComponent createByAttributeContaining(Class componentClass, String attributeName, String value) { return create().by(componentClass, new AttributeContainingFindStrategy(attributeName, value)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public List createAllByAttributeContaining(Class componentClass, String attributeName, String value) { return create().allBy(componentClass, new AttributeContainingFindStrategy(attributeName, value)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public TComponent createByPlaceholder(Class componentClass, String text, Function options) { var placeholderOptions = PlaceholderOptions.createAbsolute(options); return create().by(componentClass, new PlaceholderFindStrategy(text, placeholderOptions)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public List createAllByPlaceholder(Class componentClass, String text, Function options) { var placeholderOptions = PlaceholderOptions.createAbsolute(options); return create().allBy(componentClass, new PlaceholderFindStrategy(text, placeholderOptions)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public TComponent createByPlaceholder(Class componentClass, Pattern pattern, Function options) { var placeholderOptions = PlaceholderOptions.createAbsolute(options); return create().by(componentClass, new PlaceholderFindStrategy(pattern, placeholderOptions)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public List createAllByPlaceholder(Class componentClass, Pattern pattern, Function options) { var placeholderOptions = PlaceholderOptions.createAbsolute(options); return create().allBy(componentClass, new PlaceholderFindStrategy(pattern, placeholderOptions)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public TComponent createByTestId(Class componentClass, String text) { return create().by(componentClass, new TestIdFindStrategy(text)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public List createAllByTestId(Class componentClass, String text) { return create().allBy(componentClass, new TestIdFindStrategy(text)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public TComponent createByTestId(Class componentClass, Pattern pattern) { return create().by(componentClass, new TestIdFindStrategy(pattern)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public List createAllByTestId(Class componentClass, Pattern pattern) { return create().allBy(componentClass, new TestIdFindStrategy(pattern)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public TComponent createByRole(Class componentClass, AriaRole role, Function options) { var roleOptions = RoleOptions.createAbsolute(options); return create().by(componentClass, new AriaRoleFindStrategy(role, roleOptions)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public List createAllByRole(Class componentClass, AriaRole role, Function options) { var roleOptions = RoleOptions.createAbsolute(options); return create().allBy(componentClass, new AriaRoleFindStrategy(role, roleOptions)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public TComponent createByAltText(Class componentClass, String text, Function options) { var altTextOptions = AltTextOptions.createAbsolute(options); return create().by(componentClass, new AltTextFindStrategy(text, altTextOptions)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public List createAllByAltText(Class componentClass, String text, Function options) { var altTextOptions = AltTextOptions.createAbsolute(options); return create().allBy(componentClass, new AltTextFindStrategy(text, altTextOptions)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public TComponent createByAltText(Class componentClass, Pattern pattern, Function options) { var altTextOptions = AltTextOptions.createAbsolute(options); return create().by(componentClass, new AltTextFindStrategy(pattern, altTextOptions)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public List createAllByAltText(Class componentClass, Pattern pattern, Function options) { var altTextOptions = AltTextOptions.createAbsolute(options); return create().allBy(componentClass, new AltTextFindStrategy(pattern, altTextOptions)); } - public TComponent createByText(Class componentClass, String text, Function options) { - var textOptions = TextOptions.createAbsolute(options); - return create().by(componentClass, new TextFindStrategy(text, textOptions)); - } - - public List createAllByText(Class componentClass, String text, Function options) { - var textOptions = TextOptions.createAbsolute(options); - return create().allBy(componentClass, new TextFindStrategy(text, textOptions)); - } - - public TComponent createByText(Class componentClass, Pattern pattern, Function options) { - var textOptions = TextOptions.createAbsolute(options); - return create().by(componentClass, new TextFindStrategy(pattern, textOptions)); - } - - public List createAllByText(Class componentClass, Pattern pattern, Function options) { - var textOptions = TextOptions.createAbsolute(options); - return create().allBy(componentClass, new TextFindStrategy(pattern, textOptions)); - } - + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public TComponent createByTitle(Class componentClass, String text, Function options) { var titleOptions = TitleOptions.createAbsolute(options); return create().by(componentClass, new TitleFindStrategy(text, titleOptions)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public List createAllByTitle(Class componentClass, String text, Function options) { var titleOptions = TitleOptions.createAbsolute(options); return create().allBy(componentClass, new TitleFindStrategy(text, titleOptions)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public TComponent createByTitle(Class componentClass, Pattern pattern, Function options) { var titleOptions = TitleOptions.createAbsolute(options); return create().by(componentClass, new TitleFindStrategy(pattern, titleOptions)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public List createAllByTitle(Class componentClass, Pattern pattern, Function options) { var titleOptions = TitleOptions.createAbsolute(options); return create().allBy(componentClass, new TitleFindStrategy(pattern, titleOptions)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public TComponent createByXpath(Class componentClass, String xpath) { return create().by(componentClass, new XpathFindStrategy(xpath)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public List createAllByXpath(Class componentClass, String xpath) { return create().allBy(componentClass, new XpathFindStrategy(xpath)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public TComponent createByCss(Class componentClass, String css) { return create().by(componentClass, new CssFindStrategy(css)); } + /** + * Use {@link WebComponent#create() } instead + */ + @Deprecated public List createAllByCss(Class componentClass, String css) { return create().allBy(componentClass, new CssFindStrategy(css)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreate(Class findStrategyClass, Class componentClass, Object... args) { var findStrategy = InstanceFactory.create(findStrategyClass, args); return create().by(componentClass, findStrategy); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAll(Class findStrategyClass, Class componentClass, Object... args) { var findStrategy = InstanceFactory.create(findStrategyClass, args); return create().allBy(componentClass, findStrategy); } - - // There is no need for shadowRootCreate, because the native playwright locators pierce the shadow DOM (except for xpath) + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreateById(Class componentClass, String id) { return create().by(componentClass, new IdFindStrategy(id)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreateByAttributeContaining(Class componentClass, String attributeName, String value) { return create().by(componentClass, new AttributeContainingFindStrategy(attributeName, value)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreateByIdEndingWith(Class componentClass, String idEnding) { return create().by(componentClass, new IdEndingWithFindStrategy(idEnding)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreateByCss(Class componentClass, String css) { return create().by(componentClass, new CssFindStrategy(css)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreateByClass(Class componentClass, String className) { return create().by(componentClass, new ClassFindStrategy(className)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreateByName(Class componentClass, String name) { return create().by(componentClass, new NameFindStrategy(name)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreateByNameEnding(Class componentClass, String nameEnding) { return create().by(componentClass, new NameEndingWithFindStrategy(nameEnding)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreateByValueContaining(Class componentClass, String valueContaining) { return create().by(componentClass, new ValueContainingFindStrategy(valueContaining)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreateByClassContaining(Class componentClass, String classNameContaining) { return create().by(componentClass, new ClassContainingFindStrategy(classNameContaining)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreateByXPath(Class componentClass, String xpath) { return create().by(componentClass, new XpathFindStrategy(xpath)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreateByLinkText(Class componentClass, String linkText) { return create().by(componentClass, new LinkTextFindStrategy(linkText)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreateByLinkTextContaining(Class componentClass, String linkTextContaining) { return create().by(componentClass, new LinkTextContainingFindStrategy(linkTextContaining)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreateByTag(Class componentClass, String tag) { return create().by(componentClass, new TagFindStrategy(tag)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreateByIdContaining(Class componentClass, String idContaining) { return create().by(componentClass, new IdContainingFindStrategy(idContaining)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreateByInnerTextContaining(Class componentClass, String innerText) { - return create().by(componentClass, new TextFindStrategy(Pattern.compile(String.format(".*%s.*", innerText)))); + return create().by(componentClass, new InnerTextContainingFindStrategy(innerText)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAllById(Class componentClass, String id) { return create().allBy(componentClass, new IdFindStrategy(id)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAllByAttributeContaining(Class componentClass, String attributeName, String value) { return create().allBy(componentClass, new AttributeContainingFindStrategy(attributeName, value)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAllByIdEndingWith(Class componentClass, String idEnding) { return create().allBy(componentClass, new IdEndingWithFindStrategy(idEnding)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAllByCss(Class componentClass, String css) { return create().allBy(componentClass, new CssFindStrategy(css)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAllByClass(Class componentClass, String className) { return create().allBy(componentClass, new ClassFindStrategy(className)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAllByName(Class componentClass, String name) { return create().allBy(componentClass, new NameFindStrategy(name)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAllByNameEnding(Class componentClass, String nameEnding) { return create().allBy(componentClass, new NameEndingWithFindStrategy(nameEnding)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAllByValueContaining(Class componentClass, String valueContaining) { return create().allBy(componentClass, new ValueContainingFindStrategy(valueContaining)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAllByClassContaining(Class componentClass, String classNameContaining) { return create().allBy(componentClass, new ClassContainingFindStrategy(classNameContaining)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAllByXPath(Class componentClass, String xpath) { return create().allBy(componentClass, new XpathFindStrategy(xpath)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAllByLinkText(Class componentClass, String linkText) { return create().allBy(componentClass, new LinkTextFindStrategy(linkText)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAllByLinkTextContaining(Class componentClass, String linkTextContaining) { return create().allBy(componentClass, new LinkTextContainingFindStrategy(linkTextContaining)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAllByTag(Class componentClass, String tag) { return create().allBy(componentClass, new TagFindStrategy(tag)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAllByIdContaining(Class componentClass, String idContaining) { return create().allBy(componentClass, new IdContainingFindStrategy(idContaining)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAllByInnerTextContaining(Class componentClass, String innerText) { - return create().allBy(componentClass, new TextFindStrategy(Pattern.compile(String.format(".*%s.*", innerText)))); + return create().allBy(componentClass, new InnerTextContainingFindStrategy(innerText)); } } diff --git a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/create/RelativeCreateService.java b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/create/RelativeCreateService.java index 865e78ba..19a15f69 100644 --- a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/create/RelativeCreateService.java +++ b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/create/RelativeCreateService.java @@ -14,20 +14,25 @@ package solutions.bellatrix.playwright.components.common.create; import solutions.bellatrix.core.plugins.EventListener; +import solutions.bellatrix.core.utilities.HtmlService; +import solutions.bellatrix.playwright.components.ShadowRoot; import solutions.bellatrix.playwright.components.WebComponent; import solutions.bellatrix.playwright.components.common.ComponentActionEventArgs; +import solutions.bellatrix.playwright.components.common.webelement.WebElement; import solutions.bellatrix.playwright.components.contracts.Component; import solutions.bellatrix.playwright.findstrategies.FindStrategy; +import solutions.bellatrix.playwright.findstrategies.ShadowXpathFindStrategy; +import solutions.bellatrix.playwright.findstrategies.XpathFindStrategy; import solutions.bellatrix.playwright.services.ComponentCreateService; import java.util.ArrayList; import java.util.List; public class RelativeCreateService extends ComponentCreateService { - private final EventListener CREATING; - private final EventListener CREATED; + public final EventListener CREATING; + public final EventListener CREATED; - private final Component baseComponent; + protected final Component baseComponent; public RelativeCreateService(Component baseComponent, EventListener creating, EventListener created) { this.baseComponent = baseComponent; @@ -41,10 +46,15 @@ public TCo wrappedBrowser().getCurrentPage().waitForLoadState(); - var element = findStrategy.convert(baseComponent.getWrappedElement()).first(); + TComponent newComponent; - var newComponent = createInstance(componentClass, findStrategy, element); - newComponent.setParentComponent((WebComponent)baseComponent); + var ancestor = getAncestor(); + + if (ancestor instanceof ShadowRoot && findStrategy instanceof XpathFindStrategy) { + newComponent = createFromAncestorShadowRoot(componentClass, getShadowXpath((ShadowRoot)ancestor, findStrategy), (ShadowRoot)ancestor); + } else { + newComponent = createFromParentComponent(componentClass, findStrategy); + } CREATED.broadcast(new ComponentActionEventArgs((WebComponent)baseComponent)); @@ -57,18 +67,101 @@ public Lis wrappedBrowser().getCurrentPage().waitForLoadState(); - var elements = findStrategy.convert(baseComponent.getWrappedElement()).all(); + var ancestor = getAncestor(); + List componentList = new ArrayList<>(); - for (var element : elements) { - var component = createInstance(componentClass, findStrategy, element); - component.setParentComponent((WebComponent)baseComponent); + if (ancestor instanceof ShadowRoot && findStrategy instanceof XpathFindStrategy) { + var shadowXpathStrategies = getShadowXpathList((ShadowRoot)ancestor, findStrategy); - componentList.add(component); + for (var strategy : shadowXpathStrategies) { + var component = createFromAncestorShadowRoot(componentClass, strategy, (ShadowRoot)ancestor); + + componentList.add(component); + } + } + else { + var elements = findStrategy.convert(baseComponent.getWrappedElement()).all(); + + for (var element : elements) { + var component = createFromParentComponent(componentClass, findStrategy, element); + + componentList.add(component); + } } CREATED.broadcast(new ComponentActionEventArgs((WebComponent)baseComponent)); return componentList; } + + /** + * @return Last ancestor or first ShadowRoot ancestor. + */ + private WebComponent getAncestor() { + var component = (WebComponent)baseComponent; + + while (component != null) { + if (component instanceof ShadowRoot) { + return component; + } + component = component.getParentComponent(); + } + + return component; + } + + private ShadowXpathFindStrategy getShadowXpath(ShadowRoot ancestor, FindStrategy findStrategy) { + // First, we find the absolute location of baseComponent inside the shadow DOM + var searchContext = HtmlService.findElement(ancestor.getHtml(), baseComponent.getFindStrategy().getValue()); + + // Then we use its absolute location as a start point to navigate inside the shadow DOM (XPath Axes is allowed) + // We get the absolute xpath of the new component, and finally we convert it to css locator + var cssLocator = HtmlService.findRelativeCssLocator(searchContext, findStrategy.getValue()); + + return new ShadowXpathFindStrategy(findStrategy.getValue(), cssLocator); + } + + private List getShadowXpathList(ShadowRoot ancestor, FindStrategy findStrategy) { + // First, we find the absolute location of baseComponent inside the shadow DOM + var searchContext = HtmlService.findElement(ancestor.getHtml(), baseComponent.getFindStrategy().getValue()); + + // Then we use its absolute location as a start point to navigate inside the shadow DOM (XPath Axes is allowed) + // We get the absolute xpath of the new components, and finally we convert them to css locators + var cssLocators = HtmlService.findRelativeCssLocators(searchContext, findStrategy.getValue()); + + List strategies = new ArrayList<>(); + + for (var locator : cssLocators) { + strategies.add(new ShadowXpathFindStrategy(findStrategy.getValue(), locator)); + } + + return strategies; + } + + /** + * Creates from the shadowRoot itself as to allow for XPath Axes queries. + */ + private TComponent createFromAncestorShadowRoot(Class componentClass, ShadowXpathFindStrategy shadowXpathStrategy, ShadowRoot ancestor) { + var element = shadowXpathStrategy.convert(ancestor.getWrappedElement()).first(); + var newComponent = createInstance(componentClass, shadowXpathStrategy, element); + newComponent.setParentComponent(ancestor); + + return newComponent; + } + + protected TComponent createFromParentComponent(Class componentClass, TFindStrategy findStrategy) { + var element = findStrategy.convert(baseComponent.getWrappedElement()).first(); + var newComponent = createInstance(componentClass, findStrategy, element); + newComponent.setParentComponent((WebComponent)baseComponent); + + return newComponent; + } + + protected TComponent createFromParentComponent(Class componentClass, TFindStrategy findStrategy, WebElement element) { + var newComponent = createInstance(componentClass, findStrategy, element); + newComponent.setParentComponent((WebComponent)baseComponent); + + return newComponent; + } } diff --git a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/create/ShadowRootCreateService.java b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/create/ShadowRootCreateService.java new file mode 100644 index 00000000..67b05720 --- /dev/null +++ b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/create/ShadowRootCreateService.java @@ -0,0 +1,107 @@ +/* + * Copyright 2024 Automate The Planet Ltd. + * Author: Miriam Kyoseva + * Licensed under the Apache License, Version 2.0 (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package solutions.bellatrix.playwright.components.common.create; + +import solutions.bellatrix.core.plugins.EventListener; +import solutions.bellatrix.core.utilities.HtmlService; +import solutions.bellatrix.playwright.components.ShadowRoot; +import solutions.bellatrix.playwright.components.WebComponent; +import solutions.bellatrix.playwright.components.common.ComponentActionEventArgs; +import solutions.bellatrix.playwright.components.common.webelement.WebElement; +import solutions.bellatrix.playwright.findstrategies.FindStrategy; +import solutions.bellatrix.playwright.findstrategies.ShadowXpathFindStrategy; +import solutions.bellatrix.playwright.findstrategies.XpathFindStrategy; + +import java.util.ArrayList; +import java.util.List; + +public class ShadowRootCreateService extends RelativeCreateService { + public ShadowRootCreateService(ShadowRoot baseComponent, EventListener creating, EventListener created) { + super(baseComponent, creating, created); + } + + @Override + public TComponent by(Class componentClass, TFindStrategy findStrategy) { + CREATING.broadcast(new ComponentActionEventArgs((WebComponent)baseComponent)); + + wrappedBrowser().getCurrentPage().waitForLoadState(); + + TComponent newComponent; + + if (findStrategy instanceof XpathFindStrategy) { + var shadowXpathStrategy = getShadowXpath(findStrategy); + + newComponent = createFromParentComponent(componentClass, shadowXpathStrategy); + + } else { + newComponent = createFromParentComponent(componentClass, findStrategy); + } + + CREATED.broadcast(new ComponentActionEventArgs((WebComponent)baseComponent)); + + return newComponent; + } + + @Override + public List allBy(Class componentClass, TFindStrategy findStrategy) { + CREATING.broadcast(new ComponentActionEventArgs((WebComponent)baseComponent)); + + wrappedBrowser().getCurrentPage().waitForLoadState(); + + List componentList = new ArrayList<>(); + + if (findStrategy instanceof XpathFindStrategy) { + var shadowXpathStrategies = getShadowXpathList(findStrategy); + + for (var strategy : shadowXpathStrategies) { + var component = createFromParentComponent(componentClass, strategy); + + componentList.add(component); + } + } + else { + var elements = findStrategy.convert(baseComponent.getWrappedElement()).all(); + + for (var element : elements) { + var component = createFromParentComponent(componentClass, findStrategy, element); + + componentList.add(component); + } + } + + CREATED.broadcast(new ComponentActionEventArgs((WebComponent)baseComponent)); + + return componentList; + } + + private ShadowXpathFindStrategy getShadowXpath(FindStrategy findStrategy) { + // We get the absolute xpath of the new component, and we convert it to css locator + var cssLocator = HtmlService.findCssLocator(((ShadowRoot)baseComponent).getHtml(), findStrategy.getValue()); + + return new ShadowXpathFindStrategy(findStrategy.getValue(), cssLocator); + } + + private List getShadowXpathList(FindStrategy findStrategy) { + // We get the absolute xpath of the new components, and we convert them to css locators + var cssLocators = HtmlService.findCssLocators(((ShadowRoot)baseComponent).getHtml(), findStrategy.getValue()); + + List strategies = new ArrayList<>(); + + for (var locator : cssLocators) { + strategies.add(new ShadowXpathFindStrategy(findStrategy.getValue(), locator)); + } + + return strategies; + } +} diff --git a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/services/ComponentCreateService.java b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/services/ComponentCreateService.java index 4f8a7f27..95af6be9 100644 --- a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/services/ComponentCreateService.java +++ b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/services/ComponentCreateService.java @@ -126,20 +126,12 @@ public List allByAltText(Class TComponent byText(Class componentClass, String text) { - return byText(componentClass, text, null); - } - - public List allByText(Class componentClass, String text) { - return allByText(componentClass, text, null); - } - public TComponent byInnerTextContaining(Class componentClass, String text) { - return byText(componentClass, Pattern.compile(String.format(".*%s.*", text)), null); + return by(componentClass, new InnerTextContainingFindStrategy(text)); } public List allByInnerTextContaining(Class componentClass, String text) { - return allByText(componentClass, Pattern.compile(String.format(".*%s.*", text)), null); + return allBy(componentClass, new InnerTextContainingFindStrategy(text)); } public TComponent byTitle(Class componentClass, String text) { @@ -264,26 +256,6 @@ public List allByAltText(Class TComponent byText(Class componentClass, String text, Function options) { - var textOptions = TextOptions.createAbsolute(options); - return by(componentClass, new TextFindStrategy(text, textOptions)); - } - - public List allByText(Class componentClass, String text, Function options) { - var textOptions = TextOptions.createAbsolute(options); - return allBy(componentClass, new TextFindStrategy(text, textOptions)); - } - - public TComponent byText(Class componentClass, Pattern pattern, Function options) { - var textOptions = TextOptions.createAbsolute(options); - return by(componentClass, new TextFindStrategy(pattern, textOptions)); - } - - public List allByText(Class componentClass, Pattern pattern, Function options) { - var textOptions = TextOptions.createAbsolute(options); - return allBy(componentClass, new TextFindStrategy(pattern, textOptions)); - } - public TComponent byTitle(Class componentClass, String text, Function options) { var titleOptions = TitleOptions.createAbsolute(options); return by(componentClass, new TitleFindStrategy(text, titleOptions)); diff --git a/bellatrix.web/src/main/java/solutions/bellatrix/web/components/ShadowRoot.java b/bellatrix.web/src/main/java/solutions/bellatrix/web/components/ShadowRoot.java new file mode 100644 index 00000000..f2569c78 --- /dev/null +++ b/bellatrix.web/src/main/java/solutions/bellatrix/web/components/ShadowRoot.java @@ -0,0 +1,103 @@ +/* + * Copyright 2022 Automate The Planet Ltd. + * Author: Anton Angelov + * Licensed under the Apache License, Version 2.0 (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * Unless required createBy applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package solutions.bellatrix.web.components; + +import org.openqa.selenium.By; +import solutions.bellatrix.core.utilities.HtmlService; +import solutions.bellatrix.core.utilities.InstanceFactory; +import solutions.bellatrix.web.components.contracts.ComponentHtml; +import solutions.bellatrix.web.findstrategies.FindStrategy; +import solutions.bellatrix.web.findstrategies.ShadowXPathFindStrategy; + +import java.util.ArrayList; +import java.util.List; + +public class ShadowRoot extends WebComponent implements ComponentHtml { + /** + * Returns the innerHTML of the shadowRoot of the shadow host. + */ + public String getHtml() { + return javaScriptService.execute("return arguments[0].shadowRoot.innerHTML", getWrappedElement()); + } + + @Override + protected TComponent create(Class componentClass, TFindStrategy findStrategy) { + CREATING_ELEMENT.broadcast(new ComponentActionEventArgs(this)); + findElement(); + var component = InstanceFactory.create(componentClass); + + if (findStrategy.convert() instanceof By.ByXPath) { + component.setFindStrategy(getShadowXpath(findStrategy)); + } else { + component.setFindStrategy(findStrategy); + } + + component.setParentComponent(this); + component.setParentWrappedElement(this.shadowRoot()); + + CREATED_ELEMENT.broadcast(new ComponentActionEventArgs(this)); + return component; + } + + @Override + protected List createAll(Class componentClass, TFindStrategy findStrategy) { + CREATING_ELEMENTS.broadcast(new ComponentActionEventArgs(this)); + findElement(); + + List componentList = new ArrayList<>(); + + if (findStrategy.convert() instanceof By.ByXPath) { + var strategies = getShadowXpaths(findStrategy); + + for (var strategy : strategies) { + var component = InstanceFactory.create(componentClass); + component.setFindStrategy(strategy); + component.setParentComponent(this); + component.setParentWrappedElement(this.shadowRoot()); + componentList.add(component); + } + } else { + var nativeElements = this.shadowRoot().findElements(findStrategy.convert()); + + for (int i = 0; i < nativeElements.size(); i++) { + var component = InstanceFactory.create(componentClass); + component.setFindStrategy(findStrategy); + component.setElementIndex(i); + component.setParentWrappedElement(this.shadowRoot()); + componentList.add(component); + } + } + + CREATED_ELEMENTS.broadcast(new ComponentActionEventArgs(this)); + return componentList; + } + + private ShadowXPathFindStrategy getShadowXpath(FindStrategy findStrategy) { + var cssLocator = HtmlService.findCssLocator(this.getHtml(), findStrategy.getValue()); + + return new ShadowXPathFindStrategy(findStrategy.getValue(), cssLocator); + } + + private List getShadowXpaths(FindStrategy findStrategy) { + var cssLocators = HtmlService.findCssLocators(this.getHtml(), findStrategy.getValue()); + + List strategies = new ArrayList<>(); + + for (var locator : cssLocators) { + strategies.add(new ShadowXPathFindStrategy(findStrategy.getValue(), locator)); + } + + return strategies; + } +} diff --git a/bellatrix.web/src/main/java/solutions/bellatrix/web/components/WebComponent.java b/bellatrix.web/src/main/java/solutions/bellatrix/web/components/WebComponent.java index 186a4046..f642ed74 100644 --- a/bellatrix.web/src/main/java/solutions/bellatrix/web/components/WebComponent.java +++ b/bellatrix.web/src/main/java/solutions/bellatrix/web/components/WebComponent.java @@ -26,6 +26,7 @@ import solutions.bellatrix.core.configuration.ConfigurationService; import solutions.bellatrix.core.plugins.EventListener; import solutions.bellatrix.core.utilities.DebugInformation; +import solutions.bellatrix.core.utilities.HtmlService; import solutions.bellatrix.core.utilities.InstanceFactory; import solutions.bellatrix.core.utilities.Log; import solutions.bellatrix.web.components.contracts.Component; @@ -67,6 +68,7 @@ public class WebComponent extends LayoutComponentValidationsBuilder implements C public final static EventListener CREATED_ELEMENTS = new EventListener<>(); @Setter(AccessLevel.PROTECTED) private WebElement wrappedElement; + @Getter @Setter protected WebComponent parentComponent; @Getter @Setter private SearchContext parentWrappedElement; @Getter @Setter private int elementIndex; @Getter @Setter private FindStrategy findStrategy; @@ -88,6 +90,24 @@ public WebComponent() { wrappedDriver = DriverService.getWrappedDriver(); } + /** + * Convert this component to another type of component. + * @param componentClass type of component + */ + public ComponentT as(Class componentClass) { + if (this.getClass() == componentClass) return (ComponentT)this; + + var component = InstanceFactory.create(componentClass); + + component.setWrappedElement(this.wrappedElement); + component.setParentComponent(this.parentComponent); + component.setParentWrappedElement(this.parentWrappedElement); + component.setFindStrategy(this.findStrategy); + component.setElementIndex(this.elementIndex); + + return component; + } + public WebElement getWrappedElement() { try { wrappedElement.isDisplayed(); // checking if getting property throws exception @@ -119,6 +139,15 @@ public SearchContext shadowRoot() { return getWrappedElement().getShadowRoot(); } + /** + * Returns {@link ShadowRoot} from which you can safely create elements inside the shadow DOM + * even with XPath. + * @return {@link ShadowRoot} + */ + public ShadowRoot getShadowRoot() { + return this.as(ShadowRoot.class); + } + public void focus() { FOCUSING.broadcast(new ComponentActionEventArgs(this)); javaScriptService.execute("window.focus();"); @@ -413,132 +442,260 @@ public List createAllByInnerTextCo return createAll(componentClass, new InnerTextContainingFindStrategy(innerText)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreate(Class findStrategyClass, Class componentClass, Object... args) { var findStrategy = InstanceFactory.create(findStrategyClass, args); return shadowRootCreate(componentClass, findStrategy); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAll(Class findStrategyClass, Class componentClass, Object... args) { var findStrategy = InstanceFactory.create(findStrategyClass, args); return shadowRootCreateAll(componentClass, findStrategy); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreateById(Class componentClass, String id) { return shadowRootCreate(componentClass, new IdFindStrategy(id)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreateByAttributeContaining(Class componentClass, String attributeName, String value) { return shadowRootCreate(componentClass, new AttributeContainingWithFindStrategy(attributeName, value)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreateByIdEndingWith(Class componentClass, String idEnding) { return shadowRootCreate(componentClass, new IdEndingWithFindStrategy(idEnding)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreateByCss(Class componentClass, String css) { return shadowRootCreate(componentClass, new CssFindStrategy(css)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreateByClass(Class componentClass, String className) { return shadowRootCreate(componentClass, new ClassFindStrategy(className)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreateByName(Class componentClass, String name) { return shadowRootCreate(componentClass, new NameFindStrategy(name)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreateByNameEnding(Class componentClass, String nameEnding) { return shadowRootCreate(componentClass, new NameEndingWithFindStrategy(nameEnding)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreateByValueContaining(Class componentClass, String valueContaining) { return shadowRootCreate(componentClass, new ValueContainingWithFindStrategy(valueContaining)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreateByClassContaining(Class componentClass, String classNameContaining) { return shadowRootCreate(componentClass, new ClassContainingFindStrategy(classNameContaining)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreateByXPath(Class componentClass, String xpath) { return shadowRootCreate(componentClass, new XPathFindStrategy(xpath)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreateByLinkText(Class componentClass, String linkText) { return shadowRootCreate(componentClass, new LinkTextFindStrategy(linkText)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreateByLinkTextContaining(Class componentClass, String linkTextContaining) { return shadowRootCreate(componentClass, new LinkTextContainingFindStrategy(linkTextContaining)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreateByTag(Class componentClass, String tag) { return shadowRootCreate(componentClass, new TagFindStrategy(tag)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreateByIdContaining(Class componentClass, String idContaining) { return shadowRootCreate(componentClass, new IdContainingFindStrategy(idContaining)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public TComponent shadowRootCreateByInnerTextContaining(Class componentClass, String innerText) { return shadowRootCreate(componentClass, new InnerTextContainingFindStrategy(innerText)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAllById(Class componentClass, String id) { return shadowRootCreateAll(componentClass, new IdFindStrategy(id)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAllByAttributeContaining(Class componentClass, String attributeName, String value) { return shadowRootCreateAll(componentClass, new AttributeContainingWithFindStrategy(attributeName, value)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAllByIdEndingWith(Class componentClass, String idEnding) { return shadowRootCreateAll(componentClass, new IdEndingWithFindStrategy(idEnding)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAllByCss(Class componentClass, String css) { return shadowRootCreateAll(componentClass, new CssFindStrategy(css)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAllByClass(Class componentClass, String className) { return shadowRootCreateAll(componentClass, new ClassFindStrategy(className)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAllByName(Class componentClass, String name) { return shadowRootCreateAll(componentClass, new NameFindStrategy(name)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAllByNameEnding(Class componentClass, String nameEnding) { return shadowRootCreateAll(componentClass, new NameEndingWithFindStrategy(nameEnding)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAllByValueContaining(Class componentClass, String valueContaining) { return shadowRootCreateAll(componentClass, new ValueContainingWithFindStrategy(valueContaining)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAllByClassContaining(Class componentClass, String classNameContaining) { return shadowRootCreateAll(componentClass, new ClassContainingFindStrategy(classNameContaining)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAllByXPath(Class componentClass, String xpath) { return shadowRootCreateAll(componentClass, new XPathFindStrategy(xpath)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAllByLinkText(Class componentClass, String linkText) { return shadowRootCreateAll(componentClass, new LinkTextFindStrategy(linkText)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAllByLinkTextContaining(Class componentClass, String linkTextContaining) { return shadowRootCreateAll(componentClass, new LinkTextContainingFindStrategy(linkTextContaining)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAllByTag(Class componentClass, String tag) { return shadowRootCreateAll(componentClass, new TagFindStrategy(tag)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAllByIdContaining(Class componentClass, String idContaining) { return shadowRootCreateAll(componentClass, new IdContainingFindStrategy(idContaining)); } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated public List shadowRootCreateAllByInnerTextContaining(Class componentClass, String innerText) { return shadowRootCreateAll(componentClass, new InnerTextContainingFindStrategy(innerText)); } @@ -564,6 +721,10 @@ public void highlight() { } } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated protected TComponent shadowRootCreate(Class componentClass, TFindStrategy findStrategy) { CREATING_ELEMENT.broadcast(new ComponentActionEventArgs(this)); findElement(); @@ -574,6 +735,10 @@ protected return component; } + /** + * Use {@link WebComponent#getShadowRoot() } instead + */ + @Deprecated protected List shadowRootCreateAll(Class componentClass, TFindStrategy findStrategy) { CREATING_ELEMENTS.broadcast(new ComponentActionEventArgs(this)); findElement(); @@ -596,8 +761,18 @@ protected CREATING_ELEMENT.broadcast(new ComponentActionEventArgs(this)); findElement(); var component = InstanceFactory.create(componentClass); - component.setFindStrategy(findStrategy); - component.setParentWrappedElement(wrappedElement); + + var ancestor = getAncestor(); + + if (ancestor.getComponentClass() == ShadowRoot.class && findStrategy.convert() instanceof By.ByXPath) { + component.setFindStrategy(getShadowXpath((ShadowRoot)ancestor, findStrategy)); + } else { + component.setFindStrategy(findStrategy); + } + + component.setParentComponent(this); + component.setParentWrappedElement(ancestor.shadowRoot()); + CREATED_ELEMENT.broadcast(new ComponentActionEventArgs(this)); return component; } @@ -605,20 +780,71 @@ protected protected List createAll(Class componentClass, TFindStrategy findStrategy) { CREATING_ELEMENTS.broadcast(new ComponentActionEventArgs(this)); findElement(); - var nativeElements = wrappedElement.findElements(findStrategy.convert()); + + var ancestor = getAncestor(); + List componentList = new ArrayList<>(); - for (int i = 0; i < nativeElements.size(); i++) { - var component = InstanceFactory.create(componentClass); - component.setFindStrategy(findStrategy); - component.setElementIndex(i); - component.setParentWrappedElement(wrappedElement); - componentList.add(component); + + if (ancestor.getComponentClass() == ShadowRoot.class && findStrategy.convert() instanceof By.ByXPath) { + var strategies = getShadowXpaths((ShadowRoot)ancestor, findStrategy); + + for (var strategy : strategies) { + var component = InstanceFactory.create(componentClass); + component.setFindStrategy(strategy); + component.setParentComponent(this); + component.setParentWrappedElement(ancestor.shadowRoot()); + componentList.add(component); + } + } + else { + var nativeElements = wrappedElement.findElements(findStrategy.convert()); + + for (int i = 0; i < nativeElements.size(); i++) { + var component = InstanceFactory.create(componentClass); + component.setFindStrategy(findStrategy); + component.setElementIndex(i); + component.setParentWrappedElement(wrappedElement); + componentList.add(component); + } } CREATED_ELEMENTS.broadcast(new ComponentActionEventArgs(this)); return componentList; } + private WebComponent getAncestor() { + var component = this; + + while (component != null) { + if (component instanceof ShadowRoot) { + return component; + } + component = component.getParentComponent(); + } + + return component; + } + + private ShadowXPathFindStrategy getShadowXpath(ShadowRoot ancestor, FindStrategy findStrategy) { + var searchContext = HtmlService.findElement(ancestor.getHtml(), this.getFindStrategy().getValue()); + var cssLocator = HtmlService.findRelativeCssLocator(searchContext, findStrategy.getValue()); + + return new ShadowXPathFindStrategy(findStrategy.getValue(), cssLocator); + } + + private List getShadowXpaths(ShadowRoot ancestor, FindStrategy findStrategy) { + var searchContext = HtmlService.findElement(ancestor.getHtml(), this.getFindStrategy().getValue()); + var cssLocators = HtmlService.findRelativeCssLocators(searchContext, findStrategy.getValue()); + + List strategies = new ArrayList<>(); + + for (var locator : cssLocators) { + strategies.add(new ShadowXPathFindStrategy(findStrategy.getValue(), locator)); + } + + return strategies; + } + public WebElement findElement() { if (waitStrategies.size() == 0) { waitStrategies.add(Wait.to().exist(webSettings.getTimeoutSettings().getElementWaitTimeout(), webSettings.getTimeoutSettings().getSleepInterval())); From 43d26bcbf5b7aeae35b0ef7d4e294300d2832649 Mon Sep 17 00:00:00 2001 From: MiriamKyoseva <133047546+MiriamKyoseva@users.noreply.github.com> Date: Mon, 27 May 2024 12:05:53 +0300 Subject: [PATCH 06/94] Update IFramesAndShadowDOMTests.java --- .../IFramesAndShadowDOMTests.java | 54 ++++++++++++++++--- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/bellatrix.playwright.getting.started/src/test/java/O24_iframes_and_shadow_dom/IFramesAndShadowDOMTests.java b/bellatrix.playwright.getting.started/src/test/java/O24_iframes_and_shadow_dom/IFramesAndShadowDOMTests.java index 8556178d..9f0fe2ea 100644 --- a/bellatrix.playwright.getting.started/src/test/java/O24_iframes_and_shadow_dom/IFramesAndShadowDOMTests.java +++ b/bellatrix.playwright.getting.started/src/test/java/O24_iframes_and_shadow_dom/IFramesAndShadowDOMTests.java @@ -36,17 +36,57 @@ public void testFindingIFramesOnThePage() { @Test public void testFindingElementsInShadowDOM() { app().navigate().to("https://web.dev/articles/shadowdom-v1"); - // First, we create a Frame component, because the elements for this test are inside of it var iframe = app().create().byXpath(Frame.class, "//iframe[contains(@src, 'raw/fancy-tabs-demo.html')]"); iframe.scrollToVisible(); - var tabList = iframe.create().byAttributeContaining(Div.class, "role", "tablist"); + // As you might know, when working with shadowRoot, we can use only CSS locators, which might prove difficult + // When we want to find an element relative to another or an element by its inner text. + // BELLATRIX offers a solution to this problem. - // Be mindful that when in the Shadow DOM, Xpath doesn't work, you'll have to use CSS only - var tabs = tabList.create().byId(Div.class, "tabsSlot"); - // This Xpath won't find the element, even though it searches by id as well: - //// var tabs = tabList.create().byXpath(Div.class, "//*[@id='tabsSlot']"); + // Not going into detail, this works in the following way: + // 1. Find the shadow root + // 2. Get its inner HTML + // 3. Get the element using jsoup to navigate inside it with xpath + // 4. Get its absolute position in the form of an absolute xpath + // 5. Convert the absolute xpath into CSS + // 6. Use this CSS locator to find the actual element on the page - Assertions.assertEquals(tabs.getAttribute("name"), "title"); + // Let's test a simply shadow DOM: + //
+ // + //
+ //
+ // + //
+ + // To get inside the shadowRoot, we first have to locate its host + // And then we use the method getShadowRoot(), which will return a ShadowRoot component + var shadowRoot = iframe.create().byXpath(Div.class, "//fancy-tabs").getShadowRoot(); + + + // Absolute xpath: /div[1]/slot + // CSS locator: div:nth-child(1)/slot + var elementInShadow = shadowRoot.create().byXpath(Div.class, "//div[@id='tabs']//slot[@id='tabsSlot']"); + + // What if we wanted to go back in the DOM? + // Absolute xpath: /div[1] + // CSS locator: div:nth-child(1) + var parentInShadow = elementInShadow.create().byXpath(Div.class, "//parent::div"); + + System.out.println(elementInShadow.getFindStrategy().toString()); + + // The same as elementInShadow... + // Absolute xpath: /div[1]/slot + // CSS locator: div:nth-child(1)/slot + var slot = parentInShadow.create().byXpath(Div.class, "//slot"); + + Assertions.assertEquals(slot.getAttribute("name"), "title"); + + // More complex xpath will also work the same way. + // Of course, the test here doesn't make much sense, but it is a showcase of + // what you can do with BELLATRIX regarding shadow DOM: + // - Use xpath to locate elements inside the shadow DOM + // - Go 'back' in the DOM tree (something you cannot achieve with CSS) + // - Locate elements by their inner text (something you cannot achieve with CSS) } } \ No newline at end of file From 83fc36a09210662375da3965fa98403f918307d4 Mon Sep 17 00:00:00 2001 From: MiriamKyoseva <133047546+MiriamKyoseva@users.noreply.github.com> Date: Mon, 27 May 2024 12:07:26 +0300 Subject: [PATCH 07/94] Updated WebComponent in bellatrix.web --- .../solutions/bellatrix/web/components/WebComponent.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/bellatrix.web/src/main/java/solutions/bellatrix/web/components/WebComponent.java b/bellatrix.web/src/main/java/solutions/bellatrix/web/components/WebComponent.java index f642ed74..1c76f7d4 100644 --- a/bellatrix.web/src/main/java/solutions/bellatrix/web/components/WebComponent.java +++ b/bellatrix.web/src/main/java/solutions/bellatrix/web/components/WebComponent.java @@ -826,15 +826,13 @@ private WebComponent getAncestor() { } private ShadowXPathFindStrategy getShadowXpath(ShadowRoot ancestor, FindStrategy findStrategy) { - var searchContext = HtmlService.findElement(ancestor.getHtml(), this.getFindStrategy().getValue()); - var cssLocator = HtmlService.findRelativeCssLocator(searchContext, findStrategy.getValue()); + var cssLocator = HtmlService.findRelativeCssLocator(HtmlService.findElement(ancestor.getHtml(), this.getFindStrategy().getValue()), findStrategy.getValue()); return new ShadowXPathFindStrategy(findStrategy.getValue(), cssLocator); } private List getShadowXpaths(ShadowRoot ancestor, FindStrategy findStrategy) { - var searchContext = HtmlService.findElement(ancestor.getHtml(), this.getFindStrategy().getValue()); - var cssLocators = HtmlService.findRelativeCssLocators(searchContext, findStrategy.getValue()); + var cssLocators = HtmlService.findRelativeCssLocators(HtmlService.findElement(ancestor.getHtml(), this.getFindStrategy().getValue()), findStrategy.getValue()); List strategies = new ArrayList<>(); From 368a5d8decc9cc07959c2b7811385e628960ced9 Mon Sep 17 00:00:00 2001 From: MiriamKyoseva <133047546+MiriamKyoseva@users.noreply.github.com> Date: Mon, 27 May 2024 12:07:49 +0300 Subject: [PATCH 08/94] Update WrappedBrowser.java --- .../playwright/infrastructure/WrappedBrowser.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/infrastructure/WrappedBrowser.java b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/infrastructure/WrappedBrowser.java index 71872ea0..5abd1de1 100644 --- a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/infrastructure/WrappedBrowser.java +++ b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/infrastructure/WrappedBrowser.java @@ -42,18 +42,18 @@ public WrappedBrowser(Playwright playwright, Browser browser, BrowserContext con private String gridSessionId; public void close() { - // ToDo maybe only the playwright object needs to be explicitly closed - currentPage.close(); - currentContext.close(); + // Close everything manually + for (var page : currentContext.pages()) page.close(); + for (var context : browser.contexts()) context.close(); browser.close(); playwright.close(); } public void changeContext(BrowserContext context) { - currentPage.close(); + for (var page : currentContext.pages()) page.close(); currentContext.close(); setCurrentContext(context); - setCurrentPage(currentContext.newPage()); + setCurrentPage(context.newPage()); } } From 3868e86fcebead88cae24352fea2e9d38f3b44d6 Mon Sep 17 00:00:00 2001 From: MiriamKyoseva <133047546+MiriamKyoseva@users.noreply.github.com> Date: Mon, 27 May 2024 12:21:48 +0300 Subject: [PATCH 09/94] Updated bellatrix.core pom.xml --- bellatrix.core/pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bellatrix.core/pom.xml b/bellatrix.core/pom.xml index 80339850..278e62e0 100644 --- a/bellatrix.core/pom.xml +++ b/bellatrix.core/pom.xml @@ -166,5 +166,11 @@ azure-identity 1.2.0 + + org.jsoup + jsoup + 1.17.2 + + \ No newline at end of file From 1c37a7fcd9a57aab29778693024436fc675b0e53 Mon Sep 17 00:00:00 2001 From: MiriamKyoseva Date: Fri, 7 Jun 2024 23:13:49 +0300 Subject: [PATCH 10/94] Renamed methods in HtmlService --- .../bellatrix/core/utilities/HtmlService.java | 22 +++++++++---------- .../common/create/RelativeCreateService.java | 4 ++-- .../create/ShadowRootCreateService.java | 5 ++--- .../bellatrix/web/components/ShadowRoot.java | 4 ++-- .../web/components/WebComponent.java | 4 ++-- 5 files changed, 19 insertions(+), 20 deletions(-) diff --git a/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/HtmlService.java b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/HtmlService.java index 65920752..68a7476a 100644 --- a/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/HtmlService.java +++ b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/HtmlService.java @@ -26,28 +26,28 @@ */ @UtilityClass public class HtmlService { - public static String findCssLocator(String html, String xpath) { + public static String convertXpathToCssLocator(String html, String xpath) { var absoluteXpath = HtmlService.findElementAbsoluteXpath(html, xpath); - return HtmlService.convertXpathToCss(absoluteXpath); + return HtmlService.convertAbsoluteXpathToCss(absoluteXpath); } - public static String findRelativeCssLocator(Element element, String xpath) { + public static String convertXpathToCssLocator(Element element, String xpath) { var absoluteXpath = HtmlService.findRelativeElementAbsoluteXpath(element, xpath); - return HtmlService.convertXpathToCss(absoluteXpath); + return HtmlService.convertAbsoluteXpathToCss(absoluteXpath); } - public static ArrayList findCssLocators(String html, String xpath) { + public static ArrayList convertXpathToCssLocators(String html, String xpath) { var absoluteXpaths = HtmlService.findElementsAbsoluteXpath(html, xpath); - return HtmlService.convertXpathToCss(absoluteXpaths); + return HtmlService.convertAbsoluteXpathToCss(absoluteXpaths); } - public static ArrayList findRelativeCssLocators(Element element, String xpath) { + public static ArrayList convertXpathToCssLocators(Element element, String xpath) { var absoluteXpaths = HtmlService.findRelativeElementsAbsoluteXpath(element, xpath); - return HtmlService.convertXpathToCss(absoluteXpaths); + return HtmlService.convertAbsoluteXpathToCss(absoluteXpaths); } public static Element findElement(String html, String cssQuery) { @@ -111,7 +111,7 @@ private static ArrayList findRelativeElementsAbsoluteXpath(Element baseE return queries; } - private static String convertXpathToCss(String xpath) { + private static String convertAbsoluteXpathToCss(String xpath) { String cssSelector = xpath.replace("/", " > "); // Use regular expression to replace [number] with :nth-child(number) @@ -133,9 +133,9 @@ private static String convertXpathToCss(String xpath) { return semiFinalLocator; } - private static ArrayList convertXpathToCss(ArrayList queries) { + private static ArrayList convertAbsoluteXpathToCss(ArrayList queries) { for (String query : queries) { - query = convertXpathToCss(query); + query = convertAbsoluteXpathToCss(query); } return queries; diff --git a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/create/RelativeCreateService.java b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/create/RelativeCreateService.java index 19a15f69..b40c288d 100644 --- a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/create/RelativeCreateService.java +++ b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/create/RelativeCreateService.java @@ -117,7 +117,7 @@ private ShadowXpathFindStrategy getShadowXpath(ShadowRoot ancestor, FindStrategy // Then we use its absolute location as a start point to navigate inside the shadow DOM (XPath Axes is allowed) // We get the absolute xpath of the new component, and finally we convert it to css locator - var cssLocator = HtmlService.findRelativeCssLocator(searchContext, findStrategy.getValue()); + var cssLocator = HtmlService.convertXpathToCssLocator(searchContext, findStrategy.getValue()); return new ShadowXpathFindStrategy(findStrategy.getValue(), cssLocator); } @@ -128,7 +128,7 @@ private List getShadowXpathList(ShadowRoot ancestor, Fi // Then we use its absolute location as a start point to navigate inside the shadow DOM (XPath Axes is allowed) // We get the absolute xpath of the new components, and finally we convert them to css locators - var cssLocators = HtmlService.findRelativeCssLocators(searchContext, findStrategy.getValue()); + var cssLocators = HtmlService.convertXpathToCssLocators(searchContext, findStrategy.getValue()); List strategies = new ArrayList<>(); diff --git a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/create/ShadowRootCreateService.java b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/create/ShadowRootCreateService.java index 67b05720..538ab3a3 100644 --- a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/create/ShadowRootCreateService.java +++ b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/create/ShadowRootCreateService.java @@ -18,7 +18,6 @@ import solutions.bellatrix.playwright.components.ShadowRoot; import solutions.bellatrix.playwright.components.WebComponent; import solutions.bellatrix.playwright.components.common.ComponentActionEventArgs; -import solutions.bellatrix.playwright.components.common.webelement.WebElement; import solutions.bellatrix.playwright.findstrategies.FindStrategy; import solutions.bellatrix.playwright.findstrategies.ShadowXpathFindStrategy; import solutions.bellatrix.playwright.findstrategies.XpathFindStrategy; @@ -87,14 +86,14 @@ public Lis private ShadowXpathFindStrategy getShadowXpath(FindStrategy findStrategy) { // We get the absolute xpath of the new component, and we convert it to css locator - var cssLocator = HtmlService.findCssLocator(((ShadowRoot)baseComponent).getHtml(), findStrategy.getValue()); + var cssLocator = HtmlService.convertXpathToCssLocator(((ShadowRoot)baseComponent).getHtml(), findStrategy.getValue()); return new ShadowXpathFindStrategy(findStrategy.getValue(), cssLocator); } private List getShadowXpathList(FindStrategy findStrategy) { // We get the absolute xpath of the new components, and we convert them to css locators - var cssLocators = HtmlService.findCssLocators(((ShadowRoot)baseComponent).getHtml(), findStrategy.getValue()); + var cssLocators = HtmlService.convertXpathToCssLocators(((ShadowRoot)baseComponent).getHtml(), findStrategy.getValue()); List strategies = new ArrayList<>(); diff --git a/bellatrix.web/src/main/java/solutions/bellatrix/web/components/ShadowRoot.java b/bellatrix.web/src/main/java/solutions/bellatrix/web/components/ShadowRoot.java index f2569c78..95b768ec 100644 --- a/bellatrix.web/src/main/java/solutions/bellatrix/web/components/ShadowRoot.java +++ b/bellatrix.web/src/main/java/solutions/bellatrix/web/components/ShadowRoot.java @@ -84,13 +84,13 @@ protected } private ShadowXPathFindStrategy getShadowXpath(FindStrategy findStrategy) { - var cssLocator = HtmlService.findCssLocator(this.getHtml(), findStrategy.getValue()); + var cssLocator = HtmlService.convertXpathToCssLocator(this.getHtml(), findStrategy.getValue()); return new ShadowXPathFindStrategy(findStrategy.getValue(), cssLocator); } private List getShadowXpaths(FindStrategy findStrategy) { - var cssLocators = HtmlService.findCssLocators(this.getHtml(), findStrategy.getValue()); + var cssLocators = HtmlService.convertXpathToCssLocators(this.getHtml(), findStrategy.getValue()); List strategies = new ArrayList<>(); diff --git a/bellatrix.web/src/main/java/solutions/bellatrix/web/components/WebComponent.java b/bellatrix.web/src/main/java/solutions/bellatrix/web/components/WebComponent.java index 1c76f7d4..d54c5a17 100644 --- a/bellatrix.web/src/main/java/solutions/bellatrix/web/components/WebComponent.java +++ b/bellatrix.web/src/main/java/solutions/bellatrix/web/components/WebComponent.java @@ -826,13 +826,13 @@ private WebComponent getAncestor() { } private ShadowXPathFindStrategy getShadowXpath(ShadowRoot ancestor, FindStrategy findStrategy) { - var cssLocator = HtmlService.findRelativeCssLocator(HtmlService.findElement(ancestor.getHtml(), this.getFindStrategy().getValue()), findStrategy.getValue()); + var cssLocator = HtmlService.convertXpathToCssLocator(HtmlService.findElement(ancestor.getHtml(), this.getFindStrategy().getValue()), findStrategy.getValue()); return new ShadowXPathFindStrategy(findStrategy.getValue(), cssLocator); } private List getShadowXpaths(ShadowRoot ancestor, FindStrategy findStrategy) { - var cssLocators = HtmlService.findRelativeCssLocators(HtmlService.findElement(ancestor.getHtml(), this.getFindStrategy().getValue()), findStrategy.getValue()); + var cssLocators = HtmlService.convertXpathToCssLocators(HtmlService.findElement(ancestor.getHtml(), this.getFindStrategy().getValue()), findStrategy.getValue()); List strategies = new ArrayList<>(); From 6ccd496065abb8af464c7eb26f3980ae96851b63 Mon Sep 17 00:00:00 2001 From: MiriamKyoseva Date: Fri, 7 Jun 2024 23:15:28 +0300 Subject: [PATCH 11/94] Renamed methods in HtmlService --- .../solutions/bellatrix/core/utilities/HtmlService.java | 8 ++++---- .../components/common/create/RelativeCreateService.java | 4 ++-- .../components/common/create/ShadowRootCreateService.java | 4 ++-- .../solutions/bellatrix/web/components/ShadowRoot.java | 4 ++-- .../solutions/bellatrix/web/components/WebComponent.java | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/HtmlService.java b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/HtmlService.java index 68a7476a..27e80a8d 100644 --- a/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/HtmlService.java +++ b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/HtmlService.java @@ -26,25 +26,25 @@ */ @UtilityClass public class HtmlService { - public static String convertXpathToCssLocator(String html, String xpath) { + public static String convertXpathToAbsoluteCssLocator(String html, String xpath) { var absoluteXpath = HtmlService.findElementAbsoluteXpath(html, xpath); return HtmlService.convertAbsoluteXpathToCss(absoluteXpath); } - public static String convertXpathToCssLocator(Element element, String xpath) { + public static String convertXpathToAbsoluteCssLocator(Element element, String xpath) { var absoluteXpath = HtmlService.findRelativeElementAbsoluteXpath(element, xpath); return HtmlService.convertAbsoluteXpathToCss(absoluteXpath); } - public static ArrayList convertXpathToCssLocators(String html, String xpath) { + public static ArrayList convertXpathToAbsoluteCssLocators(String html, String xpath) { var absoluteXpaths = HtmlService.findElementsAbsoluteXpath(html, xpath); return HtmlService.convertAbsoluteXpathToCss(absoluteXpaths); } - public static ArrayList convertXpathToCssLocators(Element element, String xpath) { + public static ArrayList convertXpathToAbsoluteCssLocators(Element element, String xpath) { var absoluteXpaths = HtmlService.findRelativeElementsAbsoluteXpath(element, xpath); return HtmlService.convertAbsoluteXpathToCss(absoluteXpaths); diff --git a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/create/RelativeCreateService.java b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/create/RelativeCreateService.java index b40c288d..05154a88 100644 --- a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/create/RelativeCreateService.java +++ b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/create/RelativeCreateService.java @@ -117,7 +117,7 @@ private ShadowXpathFindStrategy getShadowXpath(ShadowRoot ancestor, FindStrategy // Then we use its absolute location as a start point to navigate inside the shadow DOM (XPath Axes is allowed) // We get the absolute xpath of the new component, and finally we convert it to css locator - var cssLocator = HtmlService.convertXpathToCssLocator(searchContext, findStrategy.getValue()); + var cssLocator = HtmlService.convertXpathToAbsoluteCssLocator(searchContext, findStrategy.getValue()); return new ShadowXpathFindStrategy(findStrategy.getValue(), cssLocator); } @@ -128,7 +128,7 @@ private List getShadowXpathList(ShadowRoot ancestor, Fi // Then we use its absolute location as a start point to navigate inside the shadow DOM (XPath Axes is allowed) // We get the absolute xpath of the new components, and finally we convert them to css locators - var cssLocators = HtmlService.convertXpathToCssLocators(searchContext, findStrategy.getValue()); + var cssLocators = HtmlService.convertXpathToAbsoluteCssLocators(searchContext, findStrategy.getValue()); List strategies = new ArrayList<>(); diff --git a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/create/ShadowRootCreateService.java b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/create/ShadowRootCreateService.java index 538ab3a3..63e4e22b 100644 --- a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/create/ShadowRootCreateService.java +++ b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/create/ShadowRootCreateService.java @@ -86,14 +86,14 @@ public Lis private ShadowXpathFindStrategy getShadowXpath(FindStrategy findStrategy) { // We get the absolute xpath of the new component, and we convert it to css locator - var cssLocator = HtmlService.convertXpathToCssLocator(((ShadowRoot)baseComponent).getHtml(), findStrategy.getValue()); + var cssLocator = HtmlService.convertXpathToAbsoluteCssLocator(((ShadowRoot)baseComponent).getHtml(), findStrategy.getValue()); return new ShadowXpathFindStrategy(findStrategy.getValue(), cssLocator); } private List getShadowXpathList(FindStrategy findStrategy) { // We get the absolute xpath of the new components, and we convert them to css locators - var cssLocators = HtmlService.convertXpathToCssLocators(((ShadowRoot)baseComponent).getHtml(), findStrategy.getValue()); + var cssLocators = HtmlService.convertXpathToAbsoluteCssLocators(((ShadowRoot)baseComponent).getHtml(), findStrategy.getValue()); List strategies = new ArrayList<>(); diff --git a/bellatrix.web/src/main/java/solutions/bellatrix/web/components/ShadowRoot.java b/bellatrix.web/src/main/java/solutions/bellatrix/web/components/ShadowRoot.java index 95b768ec..a3ec1a81 100644 --- a/bellatrix.web/src/main/java/solutions/bellatrix/web/components/ShadowRoot.java +++ b/bellatrix.web/src/main/java/solutions/bellatrix/web/components/ShadowRoot.java @@ -84,13 +84,13 @@ protected } private ShadowXPathFindStrategy getShadowXpath(FindStrategy findStrategy) { - var cssLocator = HtmlService.convertXpathToCssLocator(this.getHtml(), findStrategy.getValue()); + var cssLocator = HtmlService.convertXpathToAbsoluteCssLocator(this.getHtml(), findStrategy.getValue()); return new ShadowXPathFindStrategy(findStrategy.getValue(), cssLocator); } private List getShadowXpaths(FindStrategy findStrategy) { - var cssLocators = HtmlService.convertXpathToCssLocators(this.getHtml(), findStrategy.getValue()); + var cssLocators = HtmlService.convertXpathToAbsoluteCssLocators(this.getHtml(), findStrategy.getValue()); List strategies = new ArrayList<>(); diff --git a/bellatrix.web/src/main/java/solutions/bellatrix/web/components/WebComponent.java b/bellatrix.web/src/main/java/solutions/bellatrix/web/components/WebComponent.java index d54c5a17..1baec10d 100644 --- a/bellatrix.web/src/main/java/solutions/bellatrix/web/components/WebComponent.java +++ b/bellatrix.web/src/main/java/solutions/bellatrix/web/components/WebComponent.java @@ -826,13 +826,13 @@ private WebComponent getAncestor() { } private ShadowXPathFindStrategy getShadowXpath(ShadowRoot ancestor, FindStrategy findStrategy) { - var cssLocator = HtmlService.convertXpathToCssLocator(HtmlService.findElement(ancestor.getHtml(), this.getFindStrategy().getValue()), findStrategy.getValue()); + var cssLocator = HtmlService.convertXpathToAbsoluteCssLocator(HtmlService.findElement(ancestor.getHtml(), this.getFindStrategy().getValue()), findStrategy.getValue()); return new ShadowXPathFindStrategy(findStrategy.getValue(), cssLocator); } private List getShadowXpaths(ShadowRoot ancestor, FindStrategy findStrategy) { - var cssLocators = HtmlService.convertXpathToCssLocators(HtmlService.findElement(ancestor.getHtml(), this.getFindStrategy().getValue()), findStrategy.getValue()); + var cssLocators = HtmlService.convertXpathToAbsoluteCssLocators(HtmlService.findElement(ancestor.getHtml(), this.getFindStrategy().getValue()), findStrategy.getValue()); List strategies = new ArrayList<>(); From 312ded76345a30c0ac6876b8f07fe3c3f9a08cfb Mon Sep 17 00:00:00 2001 From: MiriamKyoseva Date: Fri, 7 Jun 2024 23:50:28 +0300 Subject: [PATCH 12/94] Added module bellatrix.web.getting.started to the main pom.xml --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index 74222f9b..f2c2398e 100644 --- a/pom.xml +++ b/pom.xml @@ -24,6 +24,7 @@ bellatrix.android.tests bellatrix.ios.tests bellatrix.playwright.getting.started + bellatrix.web.getting.started From a385fa4d17cff9e5229b734b9028fda110f64bf6 Mon Sep 17 00:00:00 2001 From: MiriamKyoseva Date: Wed, 12 Jun 2024 12:10:14 +0300 Subject: [PATCH 13/94] Added common methods and classes in bellatrix.core --- .../bellatrix/core/utilities/HtmlService.java | 49 +++++----- .../bellatrix/core/utilities/Ref.java | 25 +++++ .../bellatrix/core/utilities/TypeParser.java | 91 +++++++++++++++++++ .../bellatrix/core/utilities/Wait.java | 24 +++++ 4 files changed, 166 insertions(+), 23 deletions(-) create mode 100644 bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/Ref.java create mode 100644 bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/TypeParser.java diff --git a/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/HtmlService.java b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/HtmlService.java index 27e80a8d..91c25be5 100644 --- a/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/HtmlService.java +++ b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/HtmlService.java @@ -57,6 +57,32 @@ public static Element findElement(String html, String cssQuery) { .orElseThrow(() -> new IllegalArgumentException(String.format("No element was found with the css: %s", cssQuery))); } + public static String getAbsoluteXPath(Element element) { + StringBuilder xpath = new StringBuilder("/"); + + for (Element el : element.parents()) { + + if (el.tagName().equals("html") || el.tagName().equals("body")) { + // ignore the and , because jsoup added them to the html fragment + continue; + } + + int index = 1; + for (Element sibling : el.siblingElements()) { + if (sibling.tagName().equals(el.tagName())) { + index++; + } + } + + if (index == 1) xpath.insert(0, "/" + el.tagName()); + else xpath.insert(0, "/" + el.tagName() + "[" + index + "]"); + } + + xpath.append(element.tagName()); + + return xpath.toString(); + } + private static String findElementAbsoluteXpath(String html, String xpath) { var doc = Jsoup.parse(html); var el = doc.selectXpath(xpath); @@ -141,27 +167,4 @@ private static ArrayList convertAbsoluteXpathToCss(ArrayList que return queries; } - private static String getAbsoluteXPath(Element element) { - StringBuilder xpath = new StringBuilder("/"); - - for (Element el : element.parents()) { - - if (el.tagName().equals("html") || el.tagName().equals("body")) { - // ignore the and , because jsoup added them to the html fragment - continue; - } - - int index = 1; - for (Element sibling : el.siblingElements()) { - if (sibling.tagName().equals(el.tagName())) { - index++; - } - } - xpath.insert(0, "/" + el.tagName() + "[" + index + "]"); - } - - xpath.append(element.tagName()); - - return xpath.toString(); - } } diff --git a/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/Ref.java b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/Ref.java new file mode 100644 index 00000000..fe74b7a6 --- /dev/null +++ b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/Ref.java @@ -0,0 +1,25 @@ +/* + * Copyright 2024 Automate The Planet Ltd. + * Author: Miriam Kyoseva + * Licensed under the Apache License, Version 2.0 (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package solutions.bellatrix.core.utilities; + +/** + * Wrapper for passing primitives by reference. + */ +public class Ref { + public T value; + + public Ref(T value) { + this.value = value; + } +} \ No newline at end of file diff --git a/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/TypeParser.java b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/TypeParser.java new file mode 100644 index 00000000..697bcaa6 --- /dev/null +++ b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/TypeParser.java @@ -0,0 +1,91 @@ +/* + * Copyright 2024 Automate The Planet Ltd. + * Author: Miriam Kyoseva + * Licensed under the Apache License, Version 2.0 (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package solutions.bellatrix.core.utilities; + +import lombok.SneakyThrows; +import lombok.experimental.UtilityClass; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +/** + * Utility class that contains instructions how to convert from one type to another. + */ +@UtilityClass +@SuppressWarnings("unchecked") +public class TypeParser { + private static final SpecificInstructions STRING_ALLOWED_OPERATIONS = new SpecificInstructions<>((Map, Function>) (Map) Map.ofEntries( + Map.entry(String.class, (Function) (x) -> x), + Map.entry(Integer.class, (Function) Integer::parseInt), + Map.entry(Double.class, (Function) Double::parseDouble), + Map.entry(Float.class, (Function) Float::parseFloat), + Map.entry(Byte.class, (Function) Byte::parseByte), + Map.entry(Long.class, (Function) Long::parseLong), + Map.entry(Short.class, (Function) Short::parseShort), + Map.entry(Boolean.class, (Function) Boolean::parseBoolean), + Map.entry(Character.class, (Function) (x) -> x.charAt(0)), + Map.entry(BigDecimal.class, (Function) BigDecimal::new), + Map.entry(BigInteger.class, (Function) BigInteger::new) + )); + + /** + * Instructions for converting from one type to another.
+ * You can specify it statically here, or you could add new instructions dynamically via {@link Map#put(Object, Object)} + */ + public static InstructionsCollection ALLOWED_OPERATIONS = new InstructionsCollection<>(Map.ofEntries( + Map.entry(String.class, STRING_ALLOWED_OPERATIONS) + )); + + @SuppressWarnings("unchecked") + @SneakyThrows + public static T parseEnumValue(String value, Class enumClass) { + var fields = enumClass.getDeclaredFields(); + for (T enumConstant : enumClass.getEnumConstants()) { + for (var field : fields) { + field.setAccessible(true); + Object fieldValue = field.get(enumConstant); + if (fieldValue != null && fieldValue.toString().equals(value)) { + return enumConstant; + } + } + } + + return (T) Enum.valueOf((Class)enumClass, value); + } + + // TODO: RENAME ME + public class SpecificInstructions extends HashMap, Function> { + public SpecificInstructions(Map, Function> map) { + super(map); + } + + public Function to(Class clazz) { + return this.get(clazz); + } + } + + // TODO: RENAME ME + public class InstructionsCollection extends HashMap, T> { + public InstructionsCollection(Map, T> map) { + super(map); + } + + public T from(Class clazz) { + return this.get(clazz); + } + } +} diff --git a/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/Wait.java b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/Wait.java index 756f45c0..764fb29c 100644 --- a/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/Wait.java +++ b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/Wait.java @@ -58,4 +58,28 @@ public static void retry(Runnable action, Duration timeout, Duration sleepInterv } } } + + public static boolean forConditionUntilTimeout(Comparator condition, long timeoutInMilliseconds, long pollingIntervalInMilliseconds) { + boolean isConditionMet = false; + + long startTime = System.currentTimeMillis(); + + while (!isConditionMet && (System.currentTimeMillis() - startTime) <= (timeoutInMilliseconds)) { + try { + if (condition.evaluate()) { + isConditionMet = true; + } else { + Thread.sleep(pollingIntervalInMilliseconds); + } + } catch (Exception ignored) { + } + } + + return isConditionMet; + } + + @FunctionalInterface + public interface Comparator { + boolean evaluate(); + } } From 869ec53cec86528c498aaeedd26defd13c568218 Mon Sep 17 00:00:00 2001 From: MiriamKyoseva Date: Wed, 12 Jun 2024 12:10:20 +0300 Subject: [PATCH 14/94] Update ConverterService.java --- .../core/utilities/ConverterService.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/ConverterService.java b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/ConverterService.java index 466746b8..a1f0c22c 100644 --- a/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/ConverterService.java +++ b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/ConverterService.java @@ -1,3 +1,16 @@ +/* + * Copyright 2024 Automate The Planet Ltd. + * Author: Miriam Kyoseva + * Licensed under the Apache License, Version 2.0 (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package solutions.bellatrix.core.utilities; import lombok.SneakyThrows; @@ -6,9 +19,11 @@ public class ConverterService { public static ResultT convert(SourceT source, int index) { ResultT object = InstanceFactory.createByTypeParameter(source.getClass(), index); + assert object != null; return convert(source, object); } + @SuppressWarnings("unchecked") public static ResultT convert(SourceT source, ResultT result) { var object = (ResultT) InstanceFactory.create(result.getClass()); From f4fb4e889e75dedecb34b0f0de2339ba942cc7e7 Mon Sep 17 00:00:00 2001 From: MiriamKyoseva Date: Wed, 12 Jun 2024 12:10:24 +0300 Subject: [PATCH 15/94] Update InstanceFactory.java --- .../java/solutions/bellatrix/core/utilities/InstanceFactory.java | 1 + 1 file changed, 1 insertion(+) diff --git a/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/InstanceFactory.java b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/InstanceFactory.java index fc630195..dd8e5360 100644 --- a/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/InstanceFactory.java +++ b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/InstanceFactory.java @@ -16,6 +16,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.ParameterizedType; +@SuppressWarnings("unchecked") public final class InstanceFactory { public static T create(Class classOf) { T obj = null; From 43d9cf32759da2292e5adc5ce29d49f898c64f07 Mon Sep 17 00:00:00 2001 From: MiriamKyoseva Date: Wed, 12 Jun 2024 12:15:43 +0300 Subject: [PATCH 16/94] Update SingletonFactory.java There is no need to catch the exception and return null, especially without logging why the code failed. When using SingletonFactory#getInstance method, one expects an object, not null; the program will throw an exception like NullPointerException anyway. I removed the try-catch and added @SneakyThrows, if SingletonFactory#getInstance fails, it is most probably incorrectly used. --- .../core/utilities/SingletonFactory.java | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/SingletonFactory.java b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/SingletonFactory.java index 396fdc9c..a9ac34bb 100644 --- a/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/SingletonFactory.java +++ b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/SingletonFactory.java @@ -13,11 +13,14 @@ package solutions.bellatrix.core.utilities; +import lombok.SneakyThrows; + import java.util.HashMap; import java.util.Map; // Based on http://neutrofoton.github.io/blog/2013/08/29/generic-singleton-pattern-in-java/ // Can be used inside App design pattern. +@SuppressWarnings("unchecked") public class SingletonFactory { private static final SingletonFactory SINGLETON_FACTORY = new SingletonFactory(); @@ -26,18 +29,14 @@ public class SingletonFactory { private SingletonFactory() { } + @SneakyThrows public static T getInstance(Class classOf, Object... initargs) { - try { - if (!SINGLETON_FACTORY.mapHolder.containsKey(classOf.getName())) { - - T obj = (T)classOf.getConstructors()[0].newInstance(initargs); - SINGLETON_FACTORY.mapHolder.put(classOf.getName(), obj); - } + if (!SINGLETON_FACTORY.mapHolder.containsKey(classOf.getName())) { - return (T)SINGLETON_FACTORY.mapHolder.get(classOf.getName()); - } catch (Exception e) { - // not the best practice to return null. But probably we will never end here so it is OK. - return null; + T obj = (T)classOf.getConstructors()[0].newInstance(initargs); + SINGLETON_FACTORY.mapHolder.put(classOf.getName(), obj); } + + return (T)SINGLETON_FACTORY.mapHolder.get(classOf.getName()); } } From 838283593c6d08fca85bdfdb03c6c67cfd891944 Mon Sep 17 00:00:00 2001 From: MiriamKyoseva Date: Wed, 12 Jun 2024 12:16:30 +0300 Subject: [PATCH 17/94] Changes to bellatrix.playwright Mostly concerning the validator and the functional interfaces --- .../common/validate/ComponentValidator.java | 24 +++++----- .../components/common/validate/Validator.java | 46 +++---------------- .../playwright/services/BrowserService.java | 22 ++++----- .../playwright/services/DialogService.java | 5 +- .../services/JavaScriptService.java | 4 +- .../playwright/utilities/DebugLogger.java | 4 +- .../{Action.java => Assertable.java} | 4 +- .../functionalinterfaces/AssertionMethod.java | 19 -------- .../ComparatorMethod.java | 19 -------- .../{EvaluationMethod.java => Evaluable.java} | 2 +- 10 files changed, 39 insertions(+), 110 deletions(-) rename bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/utilities/functionalinterfaces/{Action.java => Assertable.java} (95%) delete mode 100644 bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/utilities/functionalinterfaces/AssertionMethod.java delete mode 100644 bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/utilities/functionalinterfaces/ComparatorMethod.java rename bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/utilities/functionalinterfaces/{EvaluationMethod.java => Evaluable.java} (95%) diff --git a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/validate/ComponentValidator.java b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/validate/ComponentValidator.java index bec5a47d..e6c9a489 100644 --- a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/validate/ComponentValidator.java +++ b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/validate/ComponentValidator.java @@ -17,7 +17,7 @@ import solutions.bellatrix.core.plugins.EventListener; import solutions.bellatrix.playwright.components.WebComponent; import solutions.bellatrix.playwright.components.common.ComponentActionEventArgs; -import solutions.bellatrix.playwright.utilities.functionalinterfaces.AssertionMethod; +import solutions.bellatrix.playwright.utilities.functionalinterfaces.Assertable; import java.util.List; import java.util.function.BooleanSupplier; @@ -45,7 +45,7 @@ public class ComponentValidator { public static void defaultValidateAttributeIsNull(WebComponent component, Supplier supplier, String attributeName) { VALIDATING_ATTRIBUTE.broadcast(new ComponentActionEventArgs(component, null, String.format("validating %s's %s is null", component.getComponentName(), attributeName))); - AssertionMethod assertion = () -> { + Assertable assertion = () -> { Validator.validateCondition(() -> supplier.get() == null); }; Validator.validate(assertion, component, attributeName, "null", supplier, "be"); @@ -56,7 +56,7 @@ public static void defaultValidateAttributeIsNull(WebComponent component, Suppli public static void defaultValidateAttributeNotNull(WebComponent component, Supplier supplier, String attributeName) { VALIDATING_ATTRIBUTE.broadcast(new ComponentActionEventArgs(component, null, String.format("validating %s's %s is NOT null", component.getComponentName(), attributeName))); - AssertionMethod assertion = () -> { + Assertable assertion = () -> { Validator.validateCondition(() -> supplier.get() != null); }; Validator.validate(assertion, component, attributeName, "not null", (Supplier) () -> "null", "be"); @@ -67,7 +67,7 @@ public static void defaultValidateAttributeNotNull(WebComponent component, Suppl public static void defaultValidateAttributeIsSet(WebComponent component, Supplier supplier, String attributeName) { VALIDATING_ATTRIBUTE.broadcast(new ComponentActionEventArgs(component, null, String.format("validating %s's %s is set", component.getComponentName(), attributeName))); - AssertionMethod assertion = () -> { + Assertable assertion = () -> { Validator.validateCondition(() -> !supplier.get().isEmpty()); }; Validator.validate(assertion, component, attributeName, "set", supplier, "be"); @@ -78,7 +78,7 @@ public static void defaultValidateAttributeIsSet(WebComponent component, Supplie public static void defaultValidateAttributeNotSet(WebComponent component, Supplier supplier, String attributeName) { VALIDATING_ATTRIBUTE.broadcast(new ComponentActionEventArgs(component, null, String.format("validating %s's %s is NOT set", component.getComponentName(), attributeName))); - AssertionMethod assertion = () -> { + Assertable assertion = () -> { Validator.validateCondition(() -> supplier.get().isEmpty()); }; Validator.validate(assertion, component, attributeName, "not set", supplier, "be"); @@ -89,7 +89,7 @@ public static void defaultValidateAttributeNotSet(WebComponent component, Suppli public static void defaultValidateAttributeIs(WebComponent component, Supplier supplier, String value, String attributeName) { VALIDATING_ATTRIBUTE.broadcast(new ComponentActionEventArgs(component, value, String.format("validating %s's %s is '%s'", component.getComponentName(), attributeName, value))); - AssertionMethod assertion = () -> { + Assertable assertion = () -> { Validator.validateCondition(() -> supplier.get().equals(value)); }; Validator.validate(assertion, component, attributeName, value, supplier, "be"); @@ -100,7 +100,7 @@ public static void defaultValidateAttributeIs(WebComponent component, Supplier supplier, Number value, String attributeName) { VALIDATING_ATTRIBUTE.broadcast(new ComponentActionEventArgs(component, value.toString(), String.format("validating %s's %s is '%s'", component.getComponentName(), attributeName, value))); - AssertionMethod assertion = () -> { + Assertable assertion = () -> { Validator.validateCondition(() -> supplier.get().equals(value)); }; Validator.validate(assertion, component, attributeName, value, supplier, "be"); @@ -111,7 +111,7 @@ public void defaultValidateAttributeIs(WebComponent component, Supplier public static void defaultValidateAttributeContains(WebComponent component, Supplier supplier, String value, String attributeName) { VALIDATING_ATTRIBUTE.broadcast(new ComponentActionEventArgs(component, value, String.format("validating %s's %s contains '%s'", component.getComponentName(), attributeName, value))); - AssertionMethod assertion = () -> { + Assertable assertion = () -> { Validator.validateCondition(() -> supplier.get().contains(value)); }; Validator.validate(assertion, component, attributeName, value, supplier, "contain"); @@ -122,7 +122,7 @@ public static void defaultValidateAttributeContains(WebComponent component, Supp public static void defaultValidateAttributeNotContains(WebComponent component, Supplier supplier, String value, String attributeName) { VALIDATING_ATTRIBUTE.broadcast(new ComponentActionEventArgs(component, value, String.format("validating %s's %s doesn't contain '%s'", component.getComponentName(), attributeName, value))); - AssertionMethod assertion = () -> { + Assertable assertion = () -> { Validator.validateCondition(() -> !supplier.get().contains(value)); }; Validator.validate(assertion, component, attributeName, value, supplier, "not contain"); @@ -133,7 +133,7 @@ public static void defaultValidateAttributeNotContains(WebComponent component, S public static void defaultValidateAttributeTrue(WebComponent component, BooleanSupplier supplier, String attributeName) { VALIDATING_ATTRIBUTE.broadcast(new ComponentActionEventArgs(component, null, String.format("validating %s is %s", component.getComponentName(), attributeName))); - AssertionMethod assertion = () -> { + Assertable assertion = () -> { Validator.validateCondition(supplier::getAsBoolean); }; Validator.validate(assertion, component, attributeName, "true", () -> "false", "be"); @@ -144,7 +144,7 @@ public static void defaultValidateAttributeTrue(WebComponent component, BooleanS public static void defaultValidateAttributeFalse(WebComponent component, BooleanSupplier supplier, String attributeName) { VALIDATING_ATTRIBUTE.broadcast(new ComponentActionEventArgs(component, null, String.format("validating %s is not %s", component.getComponentName(), attributeName))); - AssertionMethod assertion = () -> { + Assertable assertion = () -> { Validator.validateCondition(() -> !supplier.getAsBoolean()); }; Validator.validate(assertion, component, attributeName, "false", () -> "true", "be"); @@ -155,7 +155,7 @@ public static void defaultValidateAttributeFalse(WebComponent component, Boolean public static void defaultValidateCollectionIs(WebComponent component, Supplier> supplier, List value, String attributeName) { VALIDATING_ATTRIBUTE.broadcast(new ComponentActionEventArgs(component, value.toString(), String.format("validating %s's %s is '%s'", component.getComponentName(), attributeName, value))); - AssertionMethod assertion = () -> { + Assertable assertion = () -> { Validator.validateCondition(() -> supplier.get().equals(value)); }; Validator.validate(assertion, component, attributeName, value, supplier, "be"); diff --git a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/validate/Validator.java b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/validate/Validator.java index cb0e15df..6d4ec68f 100644 --- a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/validate/Validator.java +++ b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/common/validate/Validator.java @@ -16,13 +16,13 @@ import lombok.experimental.UtilityClass; import org.opentest4j.AssertionFailedError; import solutions.bellatrix.core.configuration.ConfigurationService; +import solutions.bellatrix.core.utilities.Wait; import solutions.bellatrix.playwright.components.WebComponent; import solutions.bellatrix.playwright.configuration.TimeoutSettings; import solutions.bellatrix.playwright.configuration.WebSettings; import solutions.bellatrix.playwright.services.WebService; import solutions.bellatrix.playwright.utilities.DebugLogger; -import solutions.bellatrix.playwright.utilities.functionalinterfaces.AssertionMethod; -import solutions.bellatrix.playwright.utilities.functionalinterfaces.ComparatorMethod; +import solutions.bellatrix.playwright.utilities.functionalinterfaces.Assertable; import java.util.function.Supplier; @@ -30,54 +30,22 @@ public class Validator extends WebService { private static final TimeoutSettings timeoutSettings = ConfigurationService.get(WebSettings.class).getTimeoutSettings(); - public static void validateCondition(ComparatorMethod condition) { - boolean isConditionMet = false; - + public static void validateCondition(Wait.Comparator condition) { long pollingInterval = timeoutSettings.inMilliseconds().getSleepInterval(); long timeout = timeoutSettings.inMilliseconds().getValidationsTimeout(); - long startTime = System.currentTimeMillis(); - - while (!isConditionMet && (System.currentTimeMillis() - startTime) <= timeout) { - try { - if (condition.evaluate()) { - isConditionMet = true; - } else { - Thread.sleep(pollingInterval); - } - } catch (Exception e) { - // ignore - } - } - - if (!isConditionMet) { + if (!Wait.forConditionUntilTimeout(condition, timeout, pollingInterval)) { throw new AssertionFailedError(String.format("Assertion failed.\n%s", condition.toString())); } } - public static void validateCondition(ComparatorMethod condition, long timeoutInMilliseconds, long pollingIntervalInMilliseconds) { - boolean isConditionMet = false; - - long startTime = System.currentTimeMillis(); - - while (!isConditionMet && (System.currentTimeMillis() - startTime) <= (timeoutInMilliseconds)) { - try { - if (condition.evaluate()) { - isConditionMet = true; - } else { - Thread.sleep(pollingIntervalInMilliseconds); - } - } catch (Exception e) { - // ignore - } - } - - if (!isConditionMet) { + public static void validateCondition(Wait.Comparator condition, long timeoutInMilliseconds, long pollingIntervalInMilliseconds) { + if (!Wait.forConditionUntilTimeout(condition, timeoutInMilliseconds, pollingIntervalInMilliseconds)) { throw new AssertionFailedError(String.format("Assertion failed.\n%s", condition.toString())); } } - public static void validate(AssertionMethod assertion, WebComponent component, String attributeName, V value, Supplier supplier, String prefix) { + public static void validate(Assertable assertion, WebComponent component, String attributeName, V value, Supplier supplier, String prefix) { var error = String.format("The %s of %s (%s)%n" + " Should %s: \"%s\"%n" + " %" + prefix.length() + "sBut was: \"%s\"%n" + diff --git a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/services/BrowserService.java b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/services/BrowserService.java index 133a73a3..40cae43b 100644 --- a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/services/BrowserService.java +++ b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/services/BrowserService.java @@ -23,12 +23,12 @@ import org.apache.commons.text.StringEscapeUtils; import org.testng.Assert; import solutions.bellatrix.core.utilities.SingletonFactory; +import solutions.bellatrix.core.utilities.Wait; import solutions.bellatrix.playwright.components.Frame; import solutions.bellatrix.playwright.components.common.validate.Validator; import solutions.bellatrix.playwright.utilities.DebugLogger; import solutions.bellatrix.playwright.utilities.Settings; -import solutions.bellatrix.playwright.utilities.functionalinterfaces.AssertionMethod; -import solutions.bellatrix.playwright.utilities.functionalinterfaces.ComparatorMethod; +import solutions.bellatrix.playwright.utilities.functionalinterfaces.Assertable; import java.net.URI; import java.net.URISyntaxException; @@ -298,11 +298,11 @@ public void waitForReactPageLoadsCompletely() { long waitUntilReadyTimeout = Settings.timeout().inMilliseconds().getWaitUntilReadyTimeout(); long sleepInterval = Settings.timeout().inMilliseconds().getSleepInterval(); - ComparatorMethod dataReactRootNotNull = () -> { + Wait.Comparator dataReactRootNotNull = () -> { return (boolean)page().evaluate("document.querySelector('data-reactroot') !== null"); }; - ComparatorMethod loadEventEndBiggerThanZero = () -> { + Wait.Comparator loadEventEndBiggerThanZero = () -> { return (boolean)page().evaluate("window.performance.timing.loadEventEnd > 0"); }; @@ -314,7 +314,7 @@ public void waitForJavaScriptAnimations() { long waitForJavaScriptAnimationsTimeout = Settings.timeout().inMilliseconds().getWaitForJavaScriptAnimationsTimeout(); long sleepInterval = Settings.timeout().inMilliseconds().getSleepInterval(); - ComparatorMethod javaScriptAnimationsWait = () -> { + Wait.Comparator javaScriptAnimationsWait = () -> { return (boolean)page().evaluate("jQuery && jQuery(':animated').length === 0"); }; @@ -362,7 +362,7 @@ public void waitForAjax() { long ajaxTimeout = Settings.timeout().inMilliseconds().getWaitForAjaxTimeout(); long sleepInterval = Settings.timeout().inMilliseconds().getSleepInterval(); - ComparatorMethod ajaxComplete = () -> { + Wait.Comparator ajaxComplete = () -> { var numberOfAjaxConnection = page().evaluate("!isNaN(window.openHTTPs) ? window.openHTTPs : null"); if (Objects.nonNull(numberOfAjaxConnection)) { int ajaxConnections = Integer.parseInt(numberOfAjaxConnection.toString()); @@ -405,7 +405,7 @@ public void waitForAjaxRequest(String requestPartialUrl, int additionalTimeoutIn long ajaxTimeout = Settings.timeout().inMilliseconds().getWaitForAjaxTimeout(); long sleepInterval = Settings.timeout().inMilliseconds().getSleepInterval() + (additionalTimeoutInSeconds * 1000); String script = String.format("performance.getEntriesByType('resource').filter(item => item.initiatorType == 'xmlhttprequest' && item.name.toLowerCase().includes('%s'))[0] !== undefined;", requestPartialUrl); - ComparatorMethod ajaxReadyState = () -> { + Wait.Comparator ajaxReadyState = () -> { return (boolean)page().evaluate(script); }; @@ -419,7 +419,7 @@ public void waitForAjaxRequest(String requestPartialUrl) { public void waitUntilPageLoadsCompletely() { long waitUntilReadyTimeout = Settings.timeout().inMilliseconds().getWaitUntilReadyTimeout(); long sleepInterval = Settings.timeout().inMilliseconds().getSleepInterval(); - ComparatorMethod readyStateEqualsComplete = () -> { + Wait.Comparator readyStateEqualsComplete = () -> { return page().evaluate("document.readyState").equals("complete"); }; @@ -439,7 +439,7 @@ public void validateLandedOnPage(String partialUrl, boolean shouldUrlEncode) { var timeout = Settings.timeout().getWaitForPartialUrl(); - AssertionMethod assertion = () -> PlaywrightAssertions.assertThat(page()).hasURL(pattern, new PageAssertions.HasURLOptions().setTimeout(timeout)); + Assertable assertion = () -> PlaywrightAssertions.assertThat(page()).hasURL(pattern, new PageAssertions.HasURLOptions().setTimeout(timeout)); String log = String.format("The expected partialUrl: %s was not found in the page's url: %s", partialUrl, getUrl()); DebugLogger.assertAndLogOnFail(assertion, log); @@ -457,7 +457,7 @@ public void validateNotLandedOnPage(String partialUrl, boolean shouldUrlEncode) Pattern pattern = Pattern.compile(String.format(".*%s.*", partialUrl)); var timeout = Settings.timeout().getWaitForPartialUrl(); - AssertionMethod assertion = () -> PlaywrightAssertions.assertThat(page()).not().hasURL(pattern, new PageAssertions.HasURLOptions().setTimeout(timeout)); + Assertable assertion = () -> PlaywrightAssertions.assertThat(page()).not().hasURL(pattern, new PageAssertions.HasURLOptions().setTimeout(timeout)); String log = String.format("The expected partialUrl: %s was found in the page's url: %s", partialUrl, getUrl()); DebugLogger.assertAndLogOnFail(assertion, log); @@ -465,7 +465,7 @@ public void validateNotLandedOnPage(String partialUrl, boolean shouldUrlEncode) public void validateUrl(String fullUrl) { var timeout = Settings.timeout().getValidationsTimeout(); - AssertionMethod assertion = () -> PlaywrightAssertions.assertThat(page()).hasURL(fullUrl, new PageAssertions.HasURLOptions().setTimeout(timeout)); + Assertable assertion = () -> PlaywrightAssertions.assertThat(page()).hasURL(fullUrl, new PageAssertions.HasURLOptions().setTimeout(timeout)); String log = String.format("Expected URL:\n%s\nIs different than the actual one:\n%s", fullUrl, getUrl()); DebugLogger.assertAndLogOnFail(assertion, log); diff --git a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/services/DialogService.java b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/services/DialogService.java index 2e679ba8..77d379a4 100644 --- a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/services/DialogService.java +++ b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/services/DialogService.java @@ -17,7 +17,6 @@ import lombok.Getter; import solutions.bellatrix.playwright.components.common.validate.Validator; import solutions.bellatrix.playwright.utilities.Settings; -import solutions.bellatrix.playwright.utilities.functionalinterfaces.Action; import java.util.concurrent.*; import java.util.function.Consumer; @@ -82,13 +81,13 @@ private void listenForDialog() { wrappedBrowser().getCurrentPage().onceDialog((dialog) -> this.dialog = dialog); } - private void tryPerformAction(Action action, long timeout) { + private void tryPerformAction(Runnable action, long timeout) { try (ExecutorService executor = Executors.newSingleThreadExecutor()) { try { // Create a callable task representing the action to be executed Callable callableTask = () -> { // Perform the action here - action.perform(); + action.run(); return null; }; diff --git a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/services/JavaScriptService.java b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/services/JavaScriptService.java index 6b71a3f2..25a3a9d1 100644 --- a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/services/JavaScriptService.java +++ b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/services/JavaScriptService.java @@ -18,7 +18,7 @@ import solutions.bellatrix.core.utilities.SingletonFactory; import solutions.bellatrix.playwright.components.Frame; import solutions.bellatrix.playwright.components.WebComponent; -import solutions.bellatrix.playwright.utilities.functionalinterfaces.EvaluationMethod; +import solutions.bellatrix.playwright.utilities.functionalinterfaces.Evaluable; @SuppressWarnings("resource") @@ -48,7 +48,7 @@ public String execute(String script, Locator nativeLocator) { return (String) performEvaluation(() -> nativeLocator.evaluate(script)); } - private Object performEvaluation(EvaluationMethod method) { + private Object performEvaluation(Evaluable method) { try { return method.evaluate(); } catch (Exception ex) { diff --git a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/utilities/DebugLogger.java b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/utilities/DebugLogger.java index fe6018fb..b37f0bcd 100644 --- a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/utilities/DebugLogger.java +++ b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/utilities/DebugLogger.java @@ -14,12 +14,12 @@ package solutions.bellatrix.playwright.utilities; import lombok.experimental.UtilityClass; -import solutions.bellatrix.playwright.utilities.functionalinterfaces.AssertionMethod; +import solutions.bellatrix.playwright.utilities.functionalinterfaces.Assertable; // ToDo rename class and method or remove altogether @UtilityClass public class DebugLogger { - public void assertAndLogOnFail(AssertionMethod assertion, String infoLog) { + public void assertAndLogOnFail(Assertable assertion, String infoLog) { try { assertion.perform(); } catch (Exception exception) { diff --git a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/utilities/functionalinterfaces/Action.java b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/utilities/functionalinterfaces/Assertable.java similarity index 95% rename from bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/utilities/functionalinterfaces/Action.java rename to bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/utilities/functionalinterfaces/Assertable.java index 16c814d7..c439d9b9 100644 --- a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/utilities/functionalinterfaces/Action.java +++ b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/utilities/functionalinterfaces/Assertable.java @@ -14,6 +14,6 @@ package solutions.bellatrix.playwright.utilities.functionalinterfaces; @FunctionalInterface -public interface Action { +public interface Assertable { void perform(); -} +} \ No newline at end of file diff --git a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/utilities/functionalinterfaces/AssertionMethod.java b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/utilities/functionalinterfaces/AssertionMethod.java deleted file mode 100644 index 66018e0c..00000000 --- a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/utilities/functionalinterfaces/AssertionMethod.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2024 Automate The Planet Ltd. - * Author: Miriam Kyoseva - * Licensed under the Apache License, Version 2.0 (the "License"); - * You may not use this file except in compliance with the License. - * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package solutions.bellatrix.playwright.utilities.functionalinterfaces; - -@FunctionalInterface -public interface AssertionMethod { - void perform(); -} diff --git a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/utilities/functionalinterfaces/ComparatorMethod.java b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/utilities/functionalinterfaces/ComparatorMethod.java deleted file mode 100644 index 93658538..00000000 --- a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/utilities/functionalinterfaces/ComparatorMethod.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2024 Automate The Planet Ltd. - * Author: Miriam Kyoseva - * Licensed under the Apache License, Version 2.0 (the "License"); - * You may not use this file except in compliance with the License. - * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package solutions.bellatrix.playwright.utilities.functionalinterfaces; - -@FunctionalInterface -public interface ComparatorMethod { - boolean evaluate(); -} diff --git a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/utilities/functionalinterfaces/EvaluationMethod.java b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/utilities/functionalinterfaces/Evaluable.java similarity index 95% rename from bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/utilities/functionalinterfaces/EvaluationMethod.java rename to bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/utilities/functionalinterfaces/Evaluable.java index 03d7bb63..cda25c94 100644 --- a/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/utilities/functionalinterfaces/EvaluationMethod.java +++ b/bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/utilities/functionalinterfaces/Evaluable.java @@ -14,6 +14,6 @@ package solutions.bellatrix.playwright.utilities.functionalinterfaces; @FunctionalInterface -public interface EvaluationMethod { +public interface Evaluable { Object evaluate(); } From 5eaf643f4ac968f6ed258317e2c6d42ab14ca43c Mon Sep 17 00:00:00 2001 From: MiriamKyoseva Date: Wed, 12 Jun 2024 12:17:55 +0300 Subject: [PATCH 18/94] Corrected bellatrix.web.getting.started --- .../ValidateAssertions.java | 4 +- .../BDDLoggingTests.java | 42 +++++++++---------- .../O12_page_objects/cart_page/CartPage.java | 4 +- .../java/O12_page_objects/cart_page/Map.java | 4 +- .../O12_page_objects/checkoutpage/Map.java | 40 +++++++++--------- .../LayoutTestingTests.java | 2 +- .../test/java/O17_logging/LoggingTests.java | 2 +- .../CustomTestCaseExtensionTests.java | 6 +-- .../ElementActionHooksTests.java | 4 +- .../ExtendExistingComponent.java | 6 +-- .../ExtendExistingCommonServicesTests.java | 6 +-- .../LocateElementsTests.java | 4 +- .../dialog_service_02/DialogServiceTests.java | 5 ++- .../O8_web_components/WebComponentsTests.java | 26 ++++++------ .../NormalAssertions.java | 4 +- 15 files changed, 81 insertions(+), 78 deletions(-) diff --git a/bellatrix.web.getting.started/src/test/java/O10_validate_assertions/ValidateAssertions.java b/bellatrix.web.getting.started/src/test/java/O10_validate_assertions/ValidateAssertions.java index 0963e223..29944138 100644 --- a/bellatrix.web.getting.started/src/test/java/O10_validate_assertions/ValidateAssertions.java +++ b/bellatrix.web.getting.started/src/test/java/O10_validate_assertions/ValidateAssertions.java @@ -11,9 +11,9 @@ public void assertValidateCartPageFields() { app().navigate().to("http://demos.bellatrix.solutions/cart/"); - TextField couponCodeTextField = app().create().byId(TextField.class, "coupon_code"); + TextInput couponCodeTextInput = app().create().byId(TextInput.class, "coupon_code"); - couponCodeTextField.validatePlaceholderIs("Coupon code"); + couponCodeTextInput.validatePlaceholderIs("Coupon code"); // If we use the validate methods, BELLATRIX waits some time for the condition to pass. After this period if it // is not successful, a beautified meaningful exception message is displayed: // The component's placeholder should be 'Discount code' but was 'Coupon code'. The test failed on URL: diff --git a/bellatrix.web.getting.started/src/test/java/O11_behaviour_driven_development/BDDLoggingTests.java b/bellatrix.web.getting.started/src/test/java/O11_behaviour_driven_development/BDDLoggingTests.java index 09493458..a64e35ba 100644 --- a/bellatrix.web.getting.started/src/test/java/O11_behaviour_driven_development/BDDLoggingTests.java +++ b/bellatrix.web.getting.started/src/test/java/O11_behaviour_driven_development/BDDLoggingTests.java @@ -9,7 +9,7 @@ public class BDDLoggingTests extends WebTest { public void purchaseRocketWithLogs() { app().navigate().to("http://demos.bellatrix.solutions/"); - Select sortDropDown = app().create().byNameEndingWith(Select.class, "orderby"); + Select sortDropDown = app().create().byNameEnding(Select.class, "orderby"); Anchor protonMReadMoreButton = app().create().byInnerTextContaining(Anchor.class, "Read more"); Anchor addToCartFalcon9 = app().create().byAttributeContaining(Anchor.class, "data-product_id", "28").toBeClickable(); @@ -22,7 +22,7 @@ public void purchaseRocketWithLogs() { addToCartFalcon9.click(); viewCartButton.click(); - TextField couponCodeTextField = app().create().byId(TextField.class, "coupon_code"); + TextInput couponCodeTextInput = app().create().byId(TextInput.class, "coupon_code"); Button applyCouponButton = app().create().byValueContaining(Button.class, "Apply coupon"); Div messageAlert = app().create().byClassContaining(Div.class, "woocommerce-message"); NumberInput quantityBox = app().create().byClassContaining(NumberInput.class, "input-text qty text"); @@ -31,7 +31,7 @@ public void purchaseRocketWithLogs() { Anchor proceedToCheckout = app().create().byClassContaining(Anchor.class, "checkout-button button alt wc-forward"); - couponCodeTextField.setText("happybirthday"); + couponCodeTextInput.setText("happybirthday"); applyCouponButton.click(); messageAlert.toBeVisible().waitToBe(); messageAlert.validateTextIs("Coupon code applied successfully."); @@ -43,17 +43,17 @@ public void purchaseRocketWithLogs() { Heading billingDetailsHeading = app().create().byInnerTextContaining(Heading.class, "Billing details"); Anchor showLogin = app().create().byInnerTextContaining(Anchor.class, "Click here to login"); TextArea orderCommentsTextArea = app().create().byId(TextArea.class, "order_comments"); - TextField billingFirstName = app().create().byId(TextField.class, "billing_first_name"); - TextField billingLastName = app().create().byId(TextField.class, "billing_last_name"); - TextField billingCompany = app().create().byId(TextField.class, "billing_company"); + TextInput billingFirstName = app().create().byId(TextInput.class, "billing_first_name"); + TextInput billingLastName = app().create().byId(TextInput.class, "billing_last_name"); + TextInput billingCompany = app().create().byId(TextInput.class, "billing_company"); Select billingCountry = app().create().byId(Select.class, "billing_country"); - TextField billingAddress1 = app().create().byId(TextField.class, "billing_address_1"); - TextField billingAddress2 = app().create().byId(TextField.class, "billing_address_2"); - TextField billingCity = app().create().byId(TextField.class, "billing_city"); + TextInput billingAddress1 = app().create().byId(TextInput.class, "billing_address_1"); + TextInput billingAddress2 = app().create().byId(TextInput.class, "billing_address_2"); + TextInput billingCity = app().create().byId(TextInput.class, "billing_city"); Select billingState = app().create().byId(Select.class, "billing_state").toBeVisible().toBeClickable(); - TextField billingZip = app().create().byId(TextField.class, "billing_postcode"); + TextInput billingZip = app().create().byId(TextInput.class, "billing_postcode"); PhoneInput billingPhone = app().create().byId(PhoneInput.class, "billing_phone"); - EmailField billingEmail = app().create().byId(EmailField.class, "billing_email"); + EmailInput billingEmail = app().create().byId(EmailInput.class, "billing_email"); CheckBox createAccountCheckBox = app().create().byId(CheckBox.class, "createaccount"); RadioButton checkPaymentsRadioButton = app().create().byAttributeContaining(RadioButton.class, "for", "payment_method_cheque"); @@ -83,7 +83,7 @@ public void purchaseRocketWithLogs() { // focusing Anchor (data-product_id containing 28) // clicking Anchor (data-product_id containing 28) // clicking Anchor (class containing added_to_cart wc-forward) - // typing 'happybirthday' in TextField (id = coupon_code) + // typing 'happybirthday' in TextInput (id = coupon_code) // clicking Button (value containing Apply coupon) // validating Div (class containing woocommerce-message)'s inner text is 'Coupon code applied successfully.' // typing '0.0' in NumberInput (class containing input-text qty text) @@ -93,18 +93,18 @@ public void purchaseRocketWithLogs() { // validating Anchor (text containing Click here to login)'s href is 'https://demos.bellatrix.solutions/checkout/#' // scrolling to TextArea (id = order_comments) // typing 'Please send the rocket to my door step!' in TextArea (id = order_comments) - // typing 'In' in TextField (id = billing_first_name) - // typing 'Deepthought' in TextField (id = billing_last_name) - // typing 'Automate The Planet Ltd.' in TextField (id = billing_company) + // typing 'In' in TextInput (id = billing_first_name) + // typing 'Deepthought' in TextInput (id = billing_last_name) + // typing 'Automate The Planet Ltd.' in TextInput (id = billing_company) // selecting 'Bulgaria' from Select (id = billing_country) - // validating TextField (id = billing_address_1)'s placeholder is 'House number and street name' - // typing 'bul. Yerusalim 5' in TextField (id = billing_address_1) - // typing 'bul. Yerusalim 6' in TextField (id = billing_address_2) - // typing 'Sofia' in TextField (id = billing_city) + // validating TextInput (id = billing_address_1)'s placeholder is 'House number and street name' + // typing 'bul. Yerusalim 5' in TextInput (id = billing_address_1) + // typing 'bul. Yerusalim 6' in TextInput (id = billing_address_2) + // typing 'Sofia' in TextInput (id = billing_city) // selecting 'Sofia-Grad' from Select (id = billing_state) - // typing '1000' in TextField (id = billing_postcode) + // typing '1000' in TextInput (id = billing_postcode) // typing '+00359894646464' in PhoneField (id = billing_phone) - // typing 'info@bellatrix.solutions' in EmailField (id = billing_email) + // typing 'info@bellatrix.solutions' in EmailInput (id = billing_email) // checking CheckBox (id = createaccount) // clicking RadioButton (for containing payment_method_cheque) diff --git a/bellatrix.web.getting.started/src/test/java/O12_page_objects/cart_page/CartPage.java b/bellatrix.web.getting.started/src/test/java/O12_page_objects/cart_page/CartPage.java index 7bc96061..e2d43f34 100644 --- a/bellatrix.web.getting.started/src/test/java/O12_page_objects/cart_page/CartPage.java +++ b/bellatrix.web.getting.started/src/test/java/O12_page_objects/cart_page/CartPage.java @@ -14,7 +14,7 @@ protected String getUrl() { // Overriding the getUrl method that comes from the base page object you can later you the open method to go to the page. @Override protected void waitForPageLoad() { - map().couponCodeTextField().toExist().waitToBe(); + map().couponCodeTextInput().toExist().waitToBe(); } public void applyCoupon(String coupon) { @@ -22,7 +22,7 @@ public void applyCoupon(String coupon) { // There are many test cases where you need to apply different coupons and so on. This way you reuse the code // instead of copy-paste it. If there is a change in the way how the coupon is applied, change the workflow only // here. Even single line of code is changed in your tests. - map().couponCodeTextField().setText(coupon); + map().couponCodeTextInput().setText(coupon); map().applyCouponButton().click(); browser().waitForAjax(); } diff --git a/bellatrix.web.getting.started/src/test/java/O12_page_objects/cart_page/Map.java b/bellatrix.web.getting.started/src/test/java/O12_page_objects/cart_page/Map.java index 62186e7e..646b382c 100644 --- a/bellatrix.web.getting.started/src/test/java/O12_page_objects/cart_page/Map.java +++ b/bellatrix.web.getting.started/src/test/java/O12_page_objects/cart_page/Map.java @@ -6,8 +6,8 @@ import java.util.List; public class Map extends PageMap { - public TextField couponCodeTextField() { - return create().byId(TextField.class, "coupon_code"); + public TextInput couponCodeTextInput() { + return create().byId(TextInput.class, "coupon_code"); } public Button applyCouponButton() { diff --git a/bellatrix.web.getting.started/src/test/java/O12_page_objects/checkoutpage/Map.java b/bellatrix.web.getting.started/src/test/java/O12_page_objects/checkoutpage/Map.java index 8229aa0f..3ae943a3 100644 --- a/bellatrix.web.getting.started/src/test/java/O12_page_objects/checkoutpage/Map.java +++ b/bellatrix.web.getting.started/src/test/java/O12_page_objects/checkoutpage/Map.java @@ -17,48 +17,48 @@ import solutions.bellatrix.web.pages.PageMap; public class Map extends PageMap { - public TextField billingFirstName() { - return create().byId(TextField.class, "billing_first_name"); + public TextInput billingFirstName() { + return create().byId(TextInput.class, "billing_first_name"); } - public TextField billingLastName() { - return create().byId(TextField.class, "billing_last_name"); + public TextInput billingLastName() { + return create().byId(TextInput.class, "billing_last_name"); } - public TextField billingCompany() { - return create().byId(TextField.class, "billing_company"); + public TextInput billingCompany() { + return create().byId(TextInput.class, "billing_company"); } public Button billingCountryWrapper() { return create().byId(Button.class, "select2-billing_country-container"); } - public TextField billingCountryFilter() { - return create().byClass(TextField.class, "select2-search__field"); + public TextInput billingCountryFilter() { + return create().byClass(TextInput.class, "select2-search__field"); } - public TextField billingAddress1() { - return create().byId(TextField.class, "billing_address_1"); + public TextInput billingAddress1() { + return create().byId(TextInput.class, "billing_address_1"); } - public TextField billingAddress2() { - return create().byId(TextField.class, "billing_address_2"); + public TextInput billingAddress2() { + return create().byId(TextInput.class, "billing_address_2"); } - public TextField billingCity() { - return create().byId(TextField.class, "billing_city"); + public TextInput billingCity() { + return create().byId(TextInput.class, "billing_city"); } - public TextField billingZip() { - return create().byId(TextField.class, "billing_postcode"); + public TextInput billingZip() { + return create().byId(TextInput.class, "billing_postcode"); } - public TextField billingPhone() { - return create().byId(TextField.class, "billing_phone"); + public TextInput billingPhone() { + return create().byId(TextInput.class, "billing_phone"); } - public TextField billingEmail() { - return create().byId(TextField.class, "billing_email"); + public TextInput billingEmail() { + return create().byId(TextInput.class, "billing_email"); } public CheckBox createAccountCheckBox() { diff --git a/bellatrix.web.getting.started/src/test/java/O13_layout_testing/LayoutTestingTests.java b/bellatrix.web.getting.started/src/test/java/O13_layout_testing/LayoutTestingTests.java index bf546c9a..6d018d11 100644 --- a/bellatrix.web.getting.started/src/test/java/O13_layout_testing/LayoutTestingTests.java +++ b/bellatrix.web.getting.started/src/test/java/O13_layout_testing/LayoutTestingTests.java @@ -14,7 +14,7 @@ public class LayoutTestingTests extends WebTest { public void testPageLayout() { app().navigate().to("http://demos.bellatrix.solutions/"); - Select sortDropDown = app().create().byNameEndingWith(Select.class, "orderby"); + Select sortDropDown = app().create().byNameEnding(Select.class, "orderby"); Anchor protonRocketAnchor = app().create().byAttributeContaining(Anchor.class, "href", "/proton-rocket/"); Anchor protonMAnchor = diff --git a/bellatrix.web.getting.started/src/test/java/O17_logging/LoggingTests.java b/bellatrix.web.getting.started/src/test/java/O17_logging/LoggingTests.java index 76a0bbaf..227eddf4 100644 --- a/bellatrix.web.getting.started/src/test/java/O17_logging/LoggingTests.java +++ b/bellatrix.web.getting.started/src/test/java/O17_logging/LoggingTests.java @@ -13,7 +13,7 @@ public class LoggingTests extends WebTest { public void addCustomMessagesToLog() { app().navigate().to("http://demos.bellatrix.solutions/"); - Select sortDropDown = app().create().byNameEndingWith(Select.class, "orderby"); + Select sortDropDown = app().create().byNameEnding(Select.class, "orderby"); Anchor protonMReadMoreButton = app().create().byInnerTextContaining(Anchor.class, "Read more"); Anchor addToCartFalcon9 = app().create().byAttributeContaining(Anchor.class, "data-product_id", "28").toBeClickable(); diff --git a/bellatrix.web.getting.started/src/test/java/O19_plugins/CustomTestCaseExtensionTests.java b/bellatrix.web.getting.started/src/test/java/O19_plugins/CustomTestCaseExtensionTests.java index cfe795be..a454095e 100644 --- a/bellatrix.web.getting.started/src/test/java/O19_plugins/CustomTestCaseExtensionTests.java +++ b/bellatrix.web.getting.started/src/test/java/O19_plugins/CustomTestCaseExtensionTests.java @@ -5,7 +5,7 @@ import solutions.bellatrix.web.components.Anchor; import solutions.bellatrix.web.components.Button; import solutions.bellatrix.web.components.Span; -import solutions.bellatrix.web.components.TextField; +import solutions.bellatrix.web.components.TextInput; import solutions.bellatrix.web.infrastructure.junit.WebTest; public class CustomTestCaseExtensionTests extends WebTest { @@ -20,7 +20,7 @@ public void configure() { @Test @ManualTestCase(id = 1532) public void addProductToCart() { - var searchInput = app().create().byId(TextField.class, "woocommerce-product-search-field-0"); + var searchInput = app().create().byId(TextInput.class, "woocommerce-product-search-field-0"); searchInput.setText("Saturn V"); var addToCartSaturn = app().create().byAttributeContaining(Button.class, "aria-label", "Saturn V"); @@ -46,7 +46,7 @@ public void addProductToCart() { item.validateIsVisible(); } - var firstName = app().create().byId(TextField.class,"billing_first_name"); + var firstName = app().create().byId(TextInput.class,"billing_first_name"); firstName.validateTextIs(""); var productTotal = app().create().byClass(Span.class,"cart_item").createByClass(Span.class,"product-total"); diff --git a/bellatrix.web.getting.started/src/test/java/O20_component_action_hooks/ElementActionHooksTests.java b/bellatrix.web.getting.started/src/test/java/O20_component_action_hooks/ElementActionHooksTests.java index 776f7dfa..820c7fe6 100644 --- a/bellatrix.web.getting.started/src/test/java/O20_component_action_hooks/ElementActionHooksTests.java +++ b/bellatrix.web.getting.started/src/test/java/O20_component_action_hooks/ElementActionHooksTests.java @@ -18,14 +18,14 @@ public void configure() { public void purchaseRocketWithGloballyOverriddenMethods() { app().navigate().to("http://demos.bellatrix.solutions/"); - Select sortDropDown = app().create().byNameEndingWith(Select.class, "orderby"); + Select sortDropDown = app().create().byNameEnding(Select.class, "orderby"); Anchor protonMReadMoreButton = app().create().byInnerTextContaining(Anchor.class, "Read more"); Anchor addToCartFalcon9 = app().create().byAttributeContaining(Anchor.class, "data-product_id", "28").toBeClickable(); Anchor viewCartButton = app().create().byClassContaining(Anchor.class, "added_to_cart wc-forward").toBeClickable(); - TextField couponCodeTextField = app().create().byId(TextField.class, "coupon_code"); + TextInput couponCodeTextInput = app().create().byId(TextInput.class, "coupon_code"); Button applyCouponButton = app().create().byValueContaining(Button.class, "Apply coupon"); NumberInput quantityBox = app().create().byClassContaining(NumberInput.class, "input-text qty text"); Div messageAlert = app().create().byClassContaining(Div.class, "woocommerce-message"); diff --git a/bellatrix.web.getting.started/src/test/java/O21_extend_components/ExtendExistingComponent.java b/bellatrix.web.getting.started/src/test/java/O21_extend_components/ExtendExistingComponent.java index 6dce5679..4a7c8d52 100644 --- a/bellatrix.web.getting.started/src/test/java/O21_extend_components/ExtendExistingComponent.java +++ b/bellatrix.web.getting.started/src/test/java/O21_extend_components/ExtendExistingComponent.java @@ -9,11 +9,11 @@ public class ExtendExistingComponent extends WebTest { public void PurchaseRocket() { app().navigate().to("http://demos.bellatrix.solutions/"); - Select sortDropDown = app().create().byNameEndingWith(Select.class, "orderby"); + Select sortDropDown = app().create().byNameEnding(Select.class, "orderby"); Anchor protonMReadMoreButton = app().create().byInnerTextContaining(Anchor.class, "Read more"); Anchor addToCartFalcon9 = app().create().byAttributeContaining(Anchor.class, "data-product_id", "28").toBeClickable(); Anchor viewCartButton = app().create().byClassContaining(Anchor.class, "added_to_cart wc-forward").toBeClickable(); - TextField couponCodeTextField = app().create().byId(TextField.class, "coupon_code"); + TextInput couponCodeTextInput = app().create().byId(TextInput.class, "coupon_code"); Button applyCouponButton = app().create().byValueContaining(Button.class, "Apply coupon"); NumberInput quantityBox = app().create().byClassContaining(NumberInput.class, "input-text qty text"); Div messageAlert = app().create().byClassContaining(Div.class, "woocommerce-message"); @@ -28,7 +28,7 @@ public void PurchaseRocket() { addToCartFalcon9.focus(); addToCartFalcon9.click(); viewCartButton.click(); - couponCodeTextField.setText("happybirthday"); + couponCodeTextInput.setText("happybirthday"); applyCouponButton.click(); messageAlert.toBeVisible().waitToBe(); diff --git a/bellatrix.web.getting.started/src/test/java/O22_extend_common_services/ExtendExistingCommonServicesTests.java b/bellatrix.web.getting.started/src/test/java/O22_extend_common_services/ExtendExistingCommonServicesTests.java index 35454951..8d782074 100644 --- a/bellatrix.web.getting.started/src/test/java/O22_extend_common_services/ExtendExistingCommonServicesTests.java +++ b/bellatrix.web.getting.started/src/test/java/O22_extend_common_services/ExtendExistingCommonServicesTests.java @@ -15,14 +15,14 @@ public ExtendedApp app() { public void purchaseRocket() { app().navigate().viaJavaScript("http://demos.bellatrix.solutions/"); - Select sortDropDown = app().create().byNameEndingWith(Select.class, "orderby"); + Select sortDropDown = app().create().byNameEnding(Select.class, "orderby"); Anchor protonMReadMoreButton = app().create().byInnerTextContaining(Anchor.class, "Read more"); Anchor addToCartFalcon9 = app().create().byAttributeContaining(Anchor.class, "data-product_id", "28").toBeClickable(); Anchor viewCartButton = app().create().byClassContaining(Anchor.class, "added_to_cart wc-forward").toBeClickable(); - TextField couponCodeTextField = app().create().byId(TextField.class, "coupon_code"); + TextInput couponCodeTextInput = app().create().byId(TextInput.class, "coupon_code"); Button applyCouponButton = app().create().byValueContaining(Button.class, "Apply coupon"); NumberInput quantityBox = app().create().byClassContaining(NumberInput.class, "input-text qty text"); Div messageAlert = app().create().byClassContaining(Div.class, "woocommerce-message"); @@ -38,7 +38,7 @@ public void purchaseRocket() { addToCartFalcon9.focus(); addToCartFalcon9.click(); viewCartButton.click(); - couponCodeTextField.setText("happybirthday"); + couponCodeTextInput.setText("happybirthday"); applyCouponButton.click(); messageAlert.toHaveContent().toBeVisible().waitToBe(); diff --git a/bellatrix.web.getting.started/src/test/java/O4_locate_components/LocateElementsTests.java b/bellatrix.web.getting.started/src/test/java/O4_locate_components/LocateElementsTests.java index eca79ef8..c820d964 100644 --- a/bellatrix.web.getting.started/src/test/java/O4_locate_components/LocateElementsTests.java +++ b/bellatrix.web.getting.started/src/test/java/O4_locate_components/LocateElementsTests.java @@ -63,7 +63,7 @@ public void blogPageOpened_When_PromotionsButtonClicked() { // CreateByInnerTextContaining --> app().create().byInnerTextContaining(Div.class, "Showing all"); // Searches the component by its inner text content, including all child HTML elements. - // CreateByNameEndingWith --> app().create().byNameEndingWith(SearchField.class, "a"); + // CreateByNameEnding --> app().create().byNameEnding(SearchField.class, "a"); // Searches the component by its name containing the specified text. // CreateByAttributesContaining --> app().create().byAttributeContaining(Anchor.class, "data-product_id", "31"); @@ -114,7 +114,7 @@ public void checkAllAddToCartButtons() { // CreateAllByInnerTextContaining --> app().create().allByInnerTextContaining(Div.class, "Showing all"); // Searches the components by its inner text content, including all child HTML elements. - // CreateAllByNameEndingWith --> app().create().allByNameEndingWith(SearchField.class, "a"); + // CreateAllByNameEnding --> app().create().allByNameEnding(SearchField.class, "a"); // Searches the components by its name containing the specified text. // CreateAllByAttributesContaining --> app().create().allByAttributeContaining(Anchor.class, "data-product_id", "31"); diff --git a/bellatrix.web.getting.started/src/test/java/O7_common_services/dialog_service_02/DialogServiceTests.java b/bellatrix.web.getting.started/src/test/java/O7_common_services/dialog_service_02/DialogServiceTests.java index f70cdf2c..f1b5777c 100644 --- a/bellatrix.web.getting.started/src/test/java/O7_common_services/dialog_service_02/DialogServiceTests.java +++ b/bellatrix.web.getting.started/src/test/java/O7_common_services/dialog_service_02/DialogServiceTests.java @@ -1,11 +1,14 @@ package O7_common_services.dialog_service_02; import org.junit.jupiter.api.Test; +import org.openqa.selenium.Alert; import org.testng.Assert; import solutions.bellatrix.web.components.Button; import solutions.bellatrix.web.infrastructure.junit.WebTest; import solutions.bellatrix.web.services.DialogButton; +import java.util.function.Consumer; + public class DialogServiceTests extends WebTest { @Test @@ -16,7 +19,7 @@ public void happyBirthdayCouponDisplayed_When_ClickOnCouponButton() { var couponButton = app().create().byId(Button.class, "couponBtn"); couponButton.click(); - app().dialogs().handle(a -> Assert.assertEquals(a.getText(), "Try the coupon- happybirthday"), DialogButton.OK); + app().dialogs().handle((Consumer)a -> Assert.assertEquals(a.getText(), "Try the coupon- happybirthday"), DialogButton.OK); } @Test diff --git a/bellatrix.web.getting.started/src/test/java/O8_web_components/WebComponentsTests.java b/bellatrix.web.getting.started/src/test/java/O8_web_components/WebComponentsTests.java index a7435df4..1670e65d 100644 --- a/bellatrix.web.getting.started/src/test/java/O8_web_components/WebComponentsTests.java +++ b/bellatrix.web.getting.started/src/test/java/O8_web_components/WebComponentsTests.java @@ -10,7 +10,7 @@ public class WebComponentsTests extends WebTest { public void purchaseRocket() { app().navigate().to("http://demos.bellatrix.solutions/"); - Select sortDropDown = app().create().byNameEndingWith(Select.class, "orderby"); + Select sortDropDown = app().create().byNameEnding(Select.class, "orderby"); // Create methods accept a generic parameter the type of the web control. Then only the methods for this specific // control are accessible. Here we tell BELLATRIX to find your component by name attribute ending with ‘orderby’. // + +
+
+ + + +
+
+ + + +
+
+ + + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + + + + + + \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/button/button.js b/bellatrix.web.tests/src/main/resources/testpages/button/button.js new file mode 100644 index 00000000..91b2d45b --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/button/button.js @@ -0,0 +1,25 @@ +var buttons = document.querySelectorAll('input'); +for (var i = 0; i < buttons.length; i++) { + var self = buttons[i]; + + self.addEventListener('click', function (event) { + if (this.value === 'Start') { + this.value = 'Stop'; + } else { + this.value = 'Start'; + } + }, false); +} + +var buttons1 = document.querySelectorAll('button'); +for (var i = 0; i < buttons1.length; i++) { + var self = buttons1[i]; + + self.addEventListener('click', function (event) { + if (this.innerHTML === 'Start') { + this.innerHTML = 'Stop'; + } else { + this.innerHTML = 'Start'; + } + }, false); +} \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/checkbox/checkBox.css b/bellatrix.web.tests/src/main/resources/testpages/checkbox/checkBox.css new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/checkbox/checkBox.html b/bellatrix.web.tests/src/main/resources/testpages/checkbox/checkBox.html new file mode 100644 index 00000000..e537ec44 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/checkbox/checkBox.html @@ -0,0 +1,30 @@ + + + + Url HTML Control Demo + + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + + + + \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/checkbox/checkBox.js b/bellatrix.web.tests/src/main/resources/testpages/checkbox/checkBox.js new file mode 100644 index 00000000..d6a85479 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/checkbox/checkBox.js @@ -0,0 +1,14 @@ +window.onscroll = function (ev) { + var docHeight = document.body.offsetHeight; + docHeight = docHeight == undefined ? window.document.documentElement.scrollHeight : docHeight; + + var winheight = window.innerHeight; + winheight = winheight == undefined ? document.documentElement.clientHeight : winheight; + + var scrollpoint = window.scrollY; + scrollpoint = scrollpoint == undefined ? window.document.documentElement.scrollTop : scrollpoint; + + if ((scrollpoint + winheight) >= docHeight) { + document.getElementById("myURL12").style.color = "red"; + } +}; \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/color/color.css b/bellatrix.web.tests/src/main/resources/testpages/color/color.css new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/color/color.html b/bellatrix.web.tests/src/main/resources/testpages/color/color.html new file mode 100644 index 00000000..4356f368 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/color/color.html @@ -0,0 +1,53 @@ + + + + Url HTML Control Demo + + + + + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + + + + \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/color/color.js b/bellatrix.web.tests/src/main/resources/testpages/color/color.js new file mode 100644 index 00000000..d6a85479 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/color/color.js @@ -0,0 +1,14 @@ +window.onscroll = function (ev) { + var docHeight = document.body.offsetHeight; + docHeight = docHeight == undefined ? window.document.documentElement.scrollHeight : docHeight; + + var winheight = window.innerHeight; + winheight = winheight == undefined ? document.documentElement.clientHeight : winheight; + + var scrollpoint = window.scrollY; + scrollpoint = scrollpoint == undefined ? window.document.documentElement.scrollTop : scrollpoint; + + if ((scrollpoint + winheight) >= docHeight) { + document.getElementById("myURL12").style.color = "red"; + } +}; \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/date/date.css b/bellatrix.web.tests/src/main/resources/testpages/date/date.css new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/date/date.html b/bellatrix.web.tests/src/main/resources/testpages/date/date.html new file mode 100644 index 00000000..8da304e1 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/date/date.html @@ -0,0 +1,58 @@ + + + + Url HTML Control Demo + + + + + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + + + + \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/date/date.js b/bellatrix.web.tests/src/main/resources/testpages/date/date.js new file mode 100644 index 00000000..d6a85479 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/date/date.js @@ -0,0 +1,14 @@ +window.onscroll = function (ev) { + var docHeight = document.body.offsetHeight; + docHeight = docHeight == undefined ? window.document.documentElement.scrollHeight : docHeight; + + var winheight = window.innerHeight; + winheight = winheight == undefined ? document.documentElement.clientHeight : winheight; + + var scrollpoint = window.scrollY; + scrollpoint = scrollpoint == undefined ? window.document.documentElement.scrollTop : scrollpoint; + + if ((scrollpoint + winheight) >= docHeight) { + document.getElementById("myURL12").style.color = "red"; + } +}; \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/datetimelocal/dateTimeLocal.css b/bellatrix.web.tests/src/main/resources/testpages/datetimelocal/dateTimeLocal.css new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/datetimelocal/dateTimeLocal.html b/bellatrix.web.tests/src/main/resources/testpages/datetimelocal/dateTimeLocal.html new file mode 100644 index 00000000..33453388 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/datetimelocal/dateTimeLocal.html @@ -0,0 +1,58 @@ + + + + Url HTML Control Demo + + + + + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + + + + \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/datetimelocal/dateTimeLocal.js b/bellatrix.web.tests/src/main/resources/testpages/datetimelocal/dateTimeLocal.js new file mode 100644 index 00000000..d6a85479 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/datetimelocal/dateTimeLocal.js @@ -0,0 +1,14 @@ +window.onscroll = function (ev) { + var docHeight = document.body.offsetHeight; + docHeight = docHeight == undefined ? window.document.documentElement.scrollHeight : docHeight; + + var winheight = window.innerHeight; + winheight = winheight == undefined ? document.documentElement.clientHeight : winheight; + + var scrollpoint = window.scrollY; + scrollpoint = scrollpoint == undefined ? window.document.documentElement.scrollTop : scrollpoint; + + if ((scrollpoint + winheight) >= docHeight) { + document.getElementById("myURL12").style.color = "red"; + } +}; \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/div/div.css b/bellatrix.web.tests/src/main/resources/testpages/div/div.css new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/div/div.html b/bellatrix.web.tests/src/main/resources/testpages/div/div.html new file mode 100644 index 00000000..06d1abcc --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/div/div.html @@ -0,0 +1,29 @@ + + + + Week HTML Control Demo + + + + +
Bellatrix
+ +
+
+ +
Automate The Planet
+ +
+
+ +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/div/div.js b/bellatrix.web.tests/src/main/resources/testpages/div/div.js new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/email/email.css b/bellatrix.web.tests/src/main/resources/testpages/email/email.css new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/email/email.html b/bellatrix.web.tests/src/main/resources/testpages/email/email.html new file mode 100644 index 00000000..ddb63f08 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/email/email.html @@ -0,0 +1,65 @@ + + + + Url HTML Control Demo + + + + + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+
+ + +
+ + + + \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/email/email.js b/bellatrix.web.tests/src/main/resources/testpages/email/email.js new file mode 100644 index 00000000..d6a85479 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/email/email.js @@ -0,0 +1,14 @@ +window.onscroll = function (ev) { + var docHeight = document.body.offsetHeight; + docHeight = docHeight == undefined ? window.document.documentElement.scrollHeight : docHeight; + + var winheight = window.innerHeight; + winheight = winheight == undefined ? document.documentElement.clientHeight : winheight; + + var scrollpoint = window.scrollY; + scrollpoint = scrollpoint == undefined ? window.document.documentElement.scrollTop : scrollpoint; + + if ((scrollpoint + winheight) >= docHeight) { + document.getElementById("myURL12").style.color = "red"; + } +}; \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/grid/Grid.html b/bellatrix.web.tests/src/main/resources/testpages/grid/Grid.html new file mode 100644 index 00000000..7ec524ef --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/grid/Grid.html @@ -0,0 +1,75 @@ + + + + Grid Example + + + + + + + + + +
+

Grid Example

+

In the case of data displayed in a grid, we not onlly have to verify data in cells, but to perform actions in specific cells that contain buttons, inputs or other types of controls.

+

The .table-hover class enables a hover state on table rows:

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OrderFirstnameLastnameEmailActions
PersonalBusiness
JohnDoejohn.doe@gmail.comjdoe@corp.com
MaryMoemary@hotmail.com
JulyDooleyjuly@mscorp.com
+
+
+ + + diff --git a/bellatrix.web.tests/src/main/resources/testpages/heading/heading.css b/bellatrix.web.tests/src/main/resources/testpages/heading/heading.css new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/heading/heading.html b/bellatrix.web.tests/src/main/resources/testpages/heading/heading.html new file mode 100644 index 00000000..71e9a11e --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/heading/heading.html @@ -0,0 +1,28 @@ + + + + Week HTML Control Demo + + + + +

Automate The Planet

+ +
+
+ +

Automate The Planet

+ +
+
+ +

+ +
+
+ +

+ + + + \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/heading/heading.js b/bellatrix.web.tests/src/main/resources/testpages/heading/heading.js new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/image/image.css b/bellatrix.web.tests/src/main/resources/testpages/image/image.css new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/image/image.html b/bellatrix.web.tests/src/main/resources/testpages/image/image.html new file mode 100644 index 00000000..f1c64411 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/image/image.html @@ -0,0 +1,32 @@ + + + + Week HTML Control Demo + + + + + MDN + +
+
+ + MDN + +
+
+ + Clock + +
+
+ + MDN + +
+
+ + + + + \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/image/image.js b/bellatrix.web.tests/src/main/resources/testpages/image/image.js new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/label/label.css b/bellatrix.web.tests/src/main/resources/testpages/label/label.css new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/label/label.html b/bellatrix.web.tests/src/main/resources/testpages/label/label.html new file mode 100644 index 00000000..14b5492f --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/label/label.html @@ -0,0 +1,20 @@ + + + + Week HTML Control Demo + + + + + +
+
+ + +
+
+ + + + + \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/label/laberl.js b/bellatrix.web.tests/src/main/resources/testpages/label/laberl.js new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/layout/bootstrap-solid.svg b/bellatrix.web.tests/src/main/resources/testpages/layout/bootstrap-solid.svg new file mode 100644 index 00000000..b624a024 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/layout/bootstrap-solid.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/bellatrix.web.tests/src/main/resources/testpages/layout/bootstrap.min.css b/bellatrix.web.tests/src/main/resources/testpages/layout/bootstrap.min.css new file mode 100644 index 00000000..6561b6f4 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/layout/bootstrap.min.css @@ -0,0 +1,7 @@ +/*! + * Bootstrap v4.0.0 (https://getbootstrap.com) + * Copyright 2011-2018 The Bootstrap Authors + * Copyright 2011-2018 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */:root{--blue:#007bff;--indigo:#6610f2;--purple:#6f42c1;--pink:#e83e8c;--red:#dc3545;--orange:#fd7e14;--yellow:#ffc107;--green:#28a745;--teal:#20c997;--cyan:#17a2b8;--white:#fff;--gray:#6c757d;--gray-dark:#343a40;--primary:#007bff;--secondary:#6c757d;--success:#28a745;--info:#17a2b8;--warning:#ffc107;--danger:#dc3545;--light:#f8f9fa;--dark:#343a40;--breakpoint-xs:0;--breakpoint-sm:576px;--breakpoint-md:768px;--breakpoint-lg:992px;--breakpoint-xl:1200px;--font-family-sans-serif:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-family:inherit;font-weight:500;line-height:1.2;color:inherit}.h1,h1{font-size:2.5rem}.h2,h2{font-size:2rem}.h3,h3{font-size:1.75rem}.h4,h4{font-size:1.5rem}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem;font-weight:300;line-height:1.2}.display-2{font-size:5.5rem;font-weight:300;line-height:1.2}.display-3{font-size:4.5rem;font-weight:300;line-height:1.2}.display-4{font-size:3.5rem;font-weight:300;line-height:1.2}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small,small{font-size:80%;font-weight:400}.mark,mark{padding:.2em;background-color:#fcf8e3}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:90%;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote-footer{display:block;font-size:80%;color:#6c757d}.blockquote-footer::before{content:"\2014 \00A0"}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#6c757d}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}code{font-size:87.5%;color:#e83e8c;word-break:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:87.5%;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:100%;font-weight:700}pre{display:block;font-size:87.5%;color:#212529}pre code{font-size:inherit;color:inherit;word-break:normal}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:576px){.container{max-width:540px}}@media (min-width:768px){.container{max-width:720px}}@media (min-width:992px){.container{max-width:960px}}@media (min-width:1200px){.container{max-width:1140px}}.container-fluid{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto{position:relative;width:100%;min-height:1px;padding-right:15px;padding-left:15px}.col{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-auto{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-1{-webkit-box-flex:0;-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-2{-webkit-box-flex:0;-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-3{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-4{-webkit-box-flex:0;-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-5{-webkit-box-flex:0;-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-6{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-7{-webkit-box-flex:0;-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-8{-webkit-box-flex:0;-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-9{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-10{-webkit-box-flex:0;-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-11{-webkit-box-flex:0;-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-12{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.order-last{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.order-0{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.order-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.order-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.order-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.offset-1{margin-left:8.333333%}.offset-2{margin-left:16.666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.333333%}.offset-5{margin-left:41.666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.333333%}.offset-8{margin-left:66.666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.333333%}.offset-11{margin-left:91.666667%}@media (min-width:576px){.col-sm{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-sm-auto{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-sm-1{-webkit-box-flex:0;-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-sm-2{-webkit-box-flex:0;-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-sm-3{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-sm-4{-webkit-box-flex:0;-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-sm-5{-webkit-box-flex:0;-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-sm-6{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-sm-7{-webkit-box-flex:0;-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-sm-8{-webkit-box-flex:0;-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-sm-9{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-sm-10{-webkit-box-flex:0;-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-sm-11{-webkit-box-flex:0;-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-sm-12{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-sm-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.order-sm-last{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.order-sm-0{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-sm-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-sm-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-sm-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-sm-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-sm-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-sm-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-sm-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-sm-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-sm-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.order-sm-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.order-sm-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.order-sm-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.333333%}.offset-sm-2{margin-left:16.666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.333333%}.offset-sm-5{margin-left:41.666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.333333%}.offset-sm-8{margin-left:66.666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.333333%}.offset-sm-11{margin-left:91.666667%}}@media (min-width:768px){.col-md{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-md-auto{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-md-1{-webkit-box-flex:0;-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-md-2{-webkit-box-flex:0;-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-md-3{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-md-4{-webkit-box-flex:0;-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-md-5{-webkit-box-flex:0;-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-md-6{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-md-7{-webkit-box-flex:0;-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-md-8{-webkit-box-flex:0;-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-md-9{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-md-10{-webkit-box-flex:0;-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-md-11{-webkit-box-flex:0;-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-md-12{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-md-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.order-md-last{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.order-md-0{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-md-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-md-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-md-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-md-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-md-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-md-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-md-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-md-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-md-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.order-md-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.order-md-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.order-md-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.333333%}.offset-md-2{margin-left:16.666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.333333%}.offset-md-5{margin-left:41.666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.333333%}.offset-md-8{margin-left:66.666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.333333%}.offset-md-11{margin-left:91.666667%}}@media (min-width:992px){.col-lg{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-lg-auto{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-lg-1{-webkit-box-flex:0;-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-lg-2{-webkit-box-flex:0;-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-lg-3{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-lg-4{-webkit-box-flex:0;-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-lg-5{-webkit-box-flex:0;-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-lg-6{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-lg-7{-webkit-box-flex:0;-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-lg-8{-webkit-box-flex:0;-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-lg-9{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-lg-10{-webkit-box-flex:0;-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-lg-11{-webkit-box-flex:0;-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-lg-12{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-lg-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.order-lg-last{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.order-lg-0{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-lg-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-lg-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-lg-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-lg-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-lg-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-lg-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-lg-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-lg-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-lg-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.order-lg-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.order-lg-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.order-lg-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.333333%}.offset-lg-2{margin-left:16.666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.333333%}.offset-lg-5{margin-left:41.666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.333333%}.offset-lg-8{margin-left:66.666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.333333%}.offset-lg-11{margin-left:91.666667%}}@media (min-width:1200px){.col-xl{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-xl-auto{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:none}.col-xl-1{-webkit-box-flex:0;-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-xl-2{-webkit-box-flex:0;-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-xl-3{-webkit-box-flex:0;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-xl-4{-webkit-box-flex:0;-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-xl-5{-webkit-box-flex:0;-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-xl-6{-webkit-box-flex:0;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-xl-7{-webkit-box-flex:0;-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-xl-8{-webkit-box-flex:0;-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-xl-9{-webkit-box-flex:0;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-xl-10{-webkit-box-flex:0;-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-xl-11{-webkit-box-flex:0;-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-xl-12{-webkit-box-flex:0;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-xl-first{-webkit-box-ordinal-group:0;-ms-flex-order:-1;order:-1}.order-xl-last{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.order-xl-0{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-xl-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-xl-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-xl-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-xl-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-xl-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-xl-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-xl-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-xl-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-xl-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.order-xl-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.order-xl-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.order-xl-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.333333%}.offset-xl-2{margin-left:16.666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.333333%}.offset-xl-5{margin-left:41.666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.333333%}.offset-xl-8{margin-left:66.666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.333333%}.offset-xl-11{margin-left:91.666667%}}.table{width:100%;max-width:100%;margin-bottom:1rem;background-color:transparent}.table td,.table th{padding:.75rem;vertical-align:top;border-top:1px solid #dee2e6}.table thead th{vertical-align:bottom;border-bottom:2px solid #dee2e6}.table tbody+tbody{border-top:2px solid #dee2e6}.table .table{background-color:#fff}.table-sm td,.table-sm th{padding:.3rem}.table-bordered{border:1px solid #dee2e6}.table-bordered td,.table-bordered th{border:1px solid #dee2e6}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-striped tbody tr:nth-of-type(odd){background-color:rgba(0,0,0,.05)}.table-hover tbody tr:hover{background-color:rgba(0,0,0,.075)}.table-primary,.table-primary>td,.table-primary>th{background-color:#b8daff}.table-hover .table-primary:hover{background-color:#9fcdff}.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#9fcdff}.table-secondary,.table-secondary>td,.table-secondary>th{background-color:#d6d8db}.table-hover .table-secondary:hover{background-color:#c8cbcf}.table-hover .table-secondary:hover>td,.table-hover .table-secondary:hover>th{background-color:#c8cbcf}.table-success,.table-success>td,.table-success>th{background-color:#c3e6cb}.table-hover .table-success:hover{background-color:#b1dfbb}.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#b1dfbb}.table-info,.table-info>td,.table-info>th{background-color:#bee5eb}.table-hover .table-info:hover{background-color:#abdde5}.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#abdde5}.table-warning,.table-warning>td,.table-warning>th{background-color:#ffeeba}.table-hover .table-warning:hover{background-color:#ffe8a1}.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#ffe8a1}.table-danger,.table-danger>td,.table-danger>th{background-color:#f5c6cb}.table-hover .table-danger:hover{background-color:#f1b0b7}.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#f1b0b7}.table-light,.table-light>td,.table-light>th{background-color:#fdfdfe}.table-hover .table-light:hover{background-color:#ececf6}.table-hover .table-light:hover>td,.table-hover .table-light:hover>th{background-color:#ececf6}.table-dark,.table-dark>td,.table-dark>th{background-color:#c6c8ca}.table-hover .table-dark:hover{background-color:#b9bbbe}.table-hover .table-dark:hover>td,.table-hover .table-dark:hover>th{background-color:#b9bbbe}.table-active,.table-active>td,.table-active>th{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:rgba(0,0,0,.075)}.table .thead-dark th{color:#fff;background-color:#212529;border-color:#32383e}.table .thead-light th{color:#495057;background-color:#e9ecef;border-color:#dee2e6}.table-dark{color:#fff;background-color:#212529}.table-dark td,.table-dark th,.table-dark thead th{border-color:#32383e}.table-dark.table-bordered{border:0}.table-dark.table-striped tbody tr:nth-of-type(odd){background-color:rgba(255,255,255,.05)}.table-dark.table-hover tbody tr:hover{background-color:rgba(255,255,255,.075)}@media (max-width:575.98px){.table-responsive-sm{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-sm>.table-bordered{border:0}}@media (max-width:767.98px){.table-responsive-md{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-md>.table-bordered{border:0}}@media (max-width:991.98px){.table-responsive-lg{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-lg>.table-bordered{border:0}}@media (max-width:1199.98px){.table-responsive-xl{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-xl>.table-bordered{border:0}}.table-responsive{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive>.table-bordered{border:0}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;line-height:1.5;color:#495057;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{color:#495057;background-color:#fff;border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.form-control::-webkit-input-placeholder{color:#6c757d;opacity:1}.form-control::-moz-placeholder{color:#6c757d;opacity:1}.form-control:-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}select.form-control:not([size]):not([multiple]){height:calc(2.25rem + 2px)}select.form-control:focus::-ms-value{color:#495057;background-color:#fff}.form-control-file,.form-control-range{display:block;width:100%}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem;line-height:1.5}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem;line-height:1.5}.form-control-plaintext{display:block;width:100%;padding-top:.375rem;padding-bottom:.375rem;margin-bottom:0;line-height:1.5;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm,.input-group-lg>.form-control-plaintext.form-control,.input-group-lg>.input-group-append>.form-control-plaintext.btn,.input-group-lg>.input-group-append>.form-control-plaintext.input-group-text,.input-group-lg>.input-group-prepend>.form-control-plaintext.btn,.input-group-lg>.input-group-prepend>.form-control-plaintext.input-group-text,.input-group-sm>.form-control-plaintext.form-control,.input-group-sm>.input-group-append>.form-control-plaintext.btn,.input-group-sm>.input-group-append>.form-control-plaintext.input-group-text,.input-group-sm>.input-group-prepend>.form-control-plaintext.btn,.input-group-sm>.input-group-prepend>.form-control-plaintext.input-group-text{padding-right:0;padding-left:0}.form-control-sm,.input-group-sm>.form-control,.input-group-sm>.input-group-append>.btn,.input-group-sm>.input-group-append>.input-group-text,.input-group-sm>.input-group-prepend>.btn,.input-group-sm>.input-group-prepend>.input-group-text{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.input-group-sm>.input-group-append>select.btn:not([size]):not([multiple]),.input-group-sm>.input-group-append>select.input-group-text:not([size]):not([multiple]),.input-group-sm>.input-group-prepend>select.btn:not([size]):not([multiple]),.input-group-sm>.input-group-prepend>select.input-group-text:not([size]):not([multiple]),.input-group-sm>select.form-control:not([size]):not([multiple]),select.form-control-sm:not([size]):not([multiple]){height:calc(1.8125rem + 2px)}.form-control-lg,.input-group-lg>.form-control,.input-group-lg>.input-group-append>.btn,.input-group-lg>.input-group-append>.input-group-text,.input-group-lg>.input-group-prepend>.btn,.input-group-lg>.input-group-prepend>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.input-group-lg>.input-group-append>select.btn:not([size]):not([multiple]),.input-group-lg>.input-group-append>select.input-group-text:not([size]):not([multiple]),.input-group-lg>.input-group-prepend>select.btn:not([size]):not([multiple]),.input-group-lg>.input-group-prepend>select.input-group-text:not([size]):not([multiple]),.input-group-lg>select.form-control:not([size]):not([multiple]),select.form-control-lg:not([size]):not([multiple]){height:calc(2.875rem + 2px)}.form-group{margin-bottom:1rem}.form-text{display:block;margin-top:.25rem}.form-row{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-5px;margin-left:-5px}.form-row>.col,.form-row>[class*=col-]{padding-right:5px;padding-left:5px}.form-check{position:relative;display:block;padding-left:1.25rem}.form-check-input{position:absolute;margin-top:.3rem;margin-left:-1.25rem}.form-check-input:disabled~.form-check-label{color:#6c757d}.form-check-label{margin-bottom:0}.form-check-inline{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding-left:0;margin-right:.75rem}.form-check-inline .form-check-input{position:static;margin-top:0;margin-right:.3125rem;margin-left:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#28a745}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.5rem;margin-top:.1rem;font-size:.875rem;line-height:1;color:#fff;background-color:rgba(40,167,69,.8);border-radius:.2rem}.custom-select.is-valid,.form-control.is-valid,.was-validated .custom-select:valid,.was-validated .form-control:valid{border-color:#28a745}.custom-select.is-valid:focus,.form-control.is-valid:focus,.was-validated .custom-select:valid:focus,.was-validated .form-control:valid:focus{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.custom-select.is-valid~.valid-feedback,.custom-select.is-valid~.valid-tooltip,.form-control.is-valid~.valid-feedback,.form-control.is-valid~.valid-tooltip,.was-validated .custom-select:valid~.valid-feedback,.was-validated .custom-select:valid~.valid-tooltip,.was-validated .form-control:valid~.valid-feedback,.was-validated .form-control:valid~.valid-tooltip{display:block}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#28a745}.form-check-input.is-valid~.valid-feedback,.form-check-input.is-valid~.valid-tooltip,.was-validated .form-check-input:valid~.valid-feedback,.was-validated .form-check-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid~.custom-control-label,.was-validated .custom-control-input:valid~.custom-control-label{color:#28a745}.custom-control-input.is-valid~.custom-control-label::before,.was-validated .custom-control-input:valid~.custom-control-label::before{background-color:#71dd8a}.custom-control-input.is-valid~.valid-feedback,.custom-control-input.is-valid~.valid-tooltip,.was-validated .custom-control-input:valid~.valid-feedback,.was-validated .custom-control-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid:checked~.custom-control-label::before,.was-validated .custom-control-input:valid:checked~.custom-control-label::before{background-color:#34ce57}.custom-control-input.is-valid:focus~.custom-control-label::before,.was-validated .custom-control-input:valid:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(40,167,69,.25)}.custom-file-input.is-valid~.custom-file-label,.was-validated .custom-file-input:valid~.custom-file-label{border-color:#28a745}.custom-file-input.is-valid~.custom-file-label::before,.was-validated .custom-file-input:valid~.custom-file-label::before{border-color:inherit}.custom-file-input.is-valid~.valid-feedback,.custom-file-input.is-valid~.valid-tooltip,.was-validated .custom-file-input:valid~.valid-feedback,.was-validated .custom-file-input:valid~.valid-tooltip{display:block}.custom-file-input.is-valid:focus~.custom-file-label,.was-validated .custom-file-input:valid:focus~.custom-file-label{box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.5rem;margin-top:.1rem;font-size:.875rem;line-height:1;color:#fff;background-color:rgba(220,53,69,.8);border-radius:.2rem}.custom-select.is-invalid,.form-control.is-invalid,.was-validated .custom-select:invalid,.was-validated .form-control:invalid{border-color:#dc3545}.custom-select.is-invalid:focus,.form-control.is-invalid:focus,.was-validated .custom-select:invalid:focus,.was-validated .form-control:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.custom-select.is-invalid~.invalid-feedback,.custom-select.is-invalid~.invalid-tooltip,.form-control.is-invalid~.invalid-feedback,.form-control.is-invalid~.invalid-tooltip,.was-validated .custom-select:invalid~.invalid-feedback,.was-validated .custom-select:invalid~.invalid-tooltip,.was-validated .form-control:invalid~.invalid-feedback,.was-validated .form-control:invalid~.invalid-tooltip{display:block}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#dc3545}.form-check-input.is-invalid~.invalid-feedback,.form-check-input.is-invalid~.invalid-tooltip,.was-validated .form-check-input:invalid~.invalid-feedback,.was-validated .form-check-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid~.custom-control-label,.was-validated .custom-control-input:invalid~.custom-control-label{color:#dc3545}.custom-control-input.is-invalid~.custom-control-label::before,.was-validated .custom-control-input:invalid~.custom-control-label::before{background-color:#efa2a9}.custom-control-input.is-invalid~.invalid-feedback,.custom-control-input.is-invalid~.invalid-tooltip,.was-validated .custom-control-input:invalid~.invalid-feedback,.was-validated .custom-control-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid:checked~.custom-control-label::before,.was-validated .custom-control-input:invalid:checked~.custom-control-label::before{background-color:#e4606d}.custom-control-input.is-invalid:focus~.custom-control-label::before,.was-validated .custom-control-input:invalid:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(220,53,69,.25)}.custom-file-input.is-invalid~.custom-file-label,.was-validated .custom-file-input:invalid~.custom-file-label{border-color:#dc3545}.custom-file-input.is-invalid~.custom-file-label::before,.was-validated .custom-file-input:invalid~.custom-file-label::before{border-color:inherit}.custom-file-input.is-invalid~.invalid-feedback,.custom-file-input.is-invalid~.invalid-tooltip,.was-validated .custom-file-input:invalid~.invalid-feedback,.was-validated .custom-file-input:invalid~.invalid-tooltip{display:block}.custom-file-input.is-invalid:focus~.custom-file-label,.was-validated .custom-file-input:invalid:focus~.custom-file-label{box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.form-inline{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row wrap;flex-flow:row wrap;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.form-inline .form-check{width:100%}@media (min-width:576px){.form-inline label{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row wrap;flex-flow:row wrap;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin-bottom:0}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .input-group{width:auto}.form-inline .form-check{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.form-inline .custom-control-label{margin-bottom:0}}.btn{display:inline-block;font-weight:400;text-align:center;white-space:nowrap;vertical-align:middle;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;line-height:1.5;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}.btn:focus,.btn:hover{text-decoration:none}.btn.focus,.btn:focus{outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.btn.disabled,.btn:disabled{opacity:.65}.btn:not(:disabled):not(.disabled){cursor:pointer}.btn:not(:disabled):not(.disabled).active,.btn:not(:disabled):not(.disabled):active{background-image:none}a.btn.disabled,fieldset:disabled a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:hover{color:#fff;background-color:#0069d9;border-color:#0062cc}.btn-primary.focus,.btn-primary:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:not(:disabled):not(.disabled).active,.btn-primary:not(:disabled):not(.disabled):active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#0062cc;border-color:#005cbf}.btn-primary:not(:disabled):not(.disabled).active:focus,.btn-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-secondary{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:hover{color:#fff;background-color:#5a6268;border-color:#545b62}.btn-secondary.focus,.btn-secondary:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:not(:disabled):not(.disabled).active,.btn-secondary:not(:disabled):not(.disabled):active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#545b62;border-color:#4e555b}.btn-secondary:not(:disabled):not(.disabled).active:focus,.btn-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-success{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:hover{color:#fff;background-color:#218838;border-color:#1e7e34}.btn-success.focus,.btn-success:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:not(:disabled):not(.disabled).active,.btn-success:not(:disabled):not(.disabled):active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#1e7e34;border-color:#1c7430}.btn-success:not(:disabled):not(.disabled).active:focus,.btn-success:not(:disabled):not(.disabled):active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-info{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:hover{color:#fff;background-color:#138496;border-color:#117a8b}.btn-info.focus,.btn-info:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-info.disabled,.btn-info:disabled{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:not(:disabled):not(.disabled).active,.btn-info:not(:disabled):not(.disabled):active,.show>.btn-info.dropdown-toggle{color:#fff;background-color:#117a8b;border-color:#10707f}.btn-info:not(:disabled):not(.disabled).active:focus,.btn-info:not(:disabled):not(.disabled):active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-warning{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#212529;background-color:#e0a800;border-color:#d39e00}.btn-warning.focus,.btn-warning:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-warning.disabled,.btn-warning:disabled{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:not(:disabled):not(.disabled).active,.btn-warning:not(:disabled):not(.disabled):active,.show>.btn-warning.dropdown-toggle{color:#212529;background-color:#d39e00;border-color:#c69500}.btn-warning:not(:disabled):not(.disabled).active:focus,.btn-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#c82333;border-color:#bd2130}.btn-danger.focus,.btn-danger:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:not(:disabled):not(.disabled).active,.btn-danger:not(:disabled):not(.disabled):active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#bd2130;border-color:#b21f2d}.btn-danger:not(:disabled):not(.disabled).active:focus,.btn-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-light{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#212529;background-color:#e2e6ea;border-color:#dae0e5}.btn-light.focus,.btn-light:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-light.disabled,.btn-light:disabled{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:not(:disabled):not(.disabled).active,.btn-light:not(:disabled):not(.disabled):active,.show>.btn-light.dropdown-toggle{color:#212529;background-color:#dae0e5;border-color:#d3d9df}.btn-light:not(:disabled):not(.disabled).active:focus,.btn-light:not(:disabled):not(.disabled):active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-dark{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:hover{color:#fff;background-color:#23272b;border-color:#1d2124}.btn-dark.focus,.btn-dark:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-dark.disabled,.btn-dark:disabled{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:not(:disabled):not(.disabled).active,.btn-dark:not(:disabled):not(.disabled):active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1d2124;border-color:#171a1d}.btn-dark:not(:disabled):not(.disabled).active:focus,.btn-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-outline-primary{color:#007bff;background-color:transparent;background-image:none;border-color:#007bff}.btn-outline-primary:hover{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary.focus,.btn-outline-primary:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#007bff;background-color:transparent}.btn-outline-primary:not(:disabled):not(.disabled).active,.btn-outline-primary:not(:disabled):not(.disabled):active,.show>.btn-outline-primary.dropdown-toggle{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary:not(:disabled):not(.disabled).active:focus,.btn-outline-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-secondary{color:#6c757d;background-color:transparent;background-image:none;border-color:#6c757d}.btn-outline-secondary:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary.focus,.btn-outline-secondary:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#6c757d;background-color:transparent}.btn-outline-secondary:not(:disabled):not(.disabled).active,.btn-outline-secondary:not(:disabled):not(.disabled):active,.show>.btn-outline-secondary.dropdown-toggle{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary:not(:disabled):not(.disabled).active:focus,.btn-outline-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-success{color:#28a745;background-color:transparent;background-image:none;border-color:#28a745}.btn-outline-success:hover{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success.focus,.btn-outline-success:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#28a745;background-color:transparent}.btn-outline-success:not(:disabled):not(.disabled).active,.btn-outline-success:not(:disabled):not(.disabled):active,.show>.btn-outline-success.dropdown-toggle{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success:not(:disabled):not(.disabled).active:focus,.btn-outline-success:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-info{color:#17a2b8;background-color:transparent;background-image:none;border-color:#17a2b8}.btn-outline-info:hover{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info.focus,.btn-outline-info:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#17a2b8;background-color:transparent}.btn-outline-info:not(:disabled):not(.disabled).active,.btn-outline-info:not(:disabled):not(.disabled):active,.show>.btn-outline-info.dropdown-toggle{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info:not(:disabled):not(.disabled).active:focus,.btn-outline-info:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-warning{color:#ffc107;background-color:transparent;background-image:none;border-color:#ffc107}.btn-outline-warning:hover{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning.focus,.btn-outline-warning:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-warning:not(:disabled):not(.disabled).active,.btn-outline-warning:not(:disabled):not(.disabled):active,.show>.btn-outline-warning.dropdown-toggle{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning:not(:disabled):not(.disabled).active:focus,.btn-outline-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-danger{color:#dc3545;background-color:transparent;background-image:none;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger.focus,.btn-outline-danger:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-danger:not(:disabled):not(.disabled).active,.btn-outline-danger:not(:disabled):not(.disabled):active,.show>.btn-outline-danger.dropdown-toggle{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger:not(:disabled):not(.disabled).active:focus,.btn-outline-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-light{color:#f8f9fa;background-color:transparent;background-image:none;border-color:#f8f9fa}.btn-outline-light:hover{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light.focus,.btn-outline-light:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-light:not(:disabled):not(.disabled).active,.btn-outline-light:not(:disabled):not(.disabled):active,.show>.btn-outline-light.dropdown-toggle{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:not(:disabled):not(.disabled).active:focus,.btn-outline-light:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-dark{color:#343a40;background-color:transparent;background-image:none;border-color:#343a40}.btn-outline-dark:hover{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark.focus,.btn-outline-dark:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#343a40;background-color:transparent}.btn-outline-dark:not(:disabled):not(.disabled).active,.btn-outline-dark:not(:disabled):not(.disabled):active,.show>.btn-outline-dark.dropdown-toggle{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark:not(:disabled):not(.disabled).active:focus,.btn-outline-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-link{font-weight:400;color:#007bff;background-color:transparent}.btn-link:hover{color:#0056b3;text-decoration:underline;background-color:transparent;border-color:transparent}.btn-link.focus,.btn-link:focus{text-decoration:underline;border-color:transparent;box-shadow:none}.btn-link.disabled,.btn-link:disabled{color:#6c757d}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;transition:opacity .15s linear}.fade.show{opacity:1}.collapse{display:none}.collapse.show{display:block}tr.collapse.show{display:table-row}tbody.collapse.show{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;transition:height .35s ease}.dropdown,.dropup{position:relative}.dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropup .dropdown-menu{margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-menu{margin-top:0;margin-left:.125rem}.dropright .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-bottom:.3em solid transparent;border-left:.3em solid}.dropright .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-toggle::after{vertical-align:0}.dropleft .dropdown-menu{margin-top:0;margin-right:.125rem}.dropleft .dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.255em;vertical-align:.255em;content:""}.dropleft .dropdown-toggle::after{display:none}.dropleft .dropdown-toggle::before{display:inline-block;width:0;height:0;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropleft .dropdown-toggle:empty::after{margin-left:0}.dropleft .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid #e9ecef}.dropdown-item{display:block;width:100%;padding:.25rem 1.5rem;clear:both;font-weight:400;color:#212529;text-align:inherit;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#16181b;text-decoration:none;background-color:#f8f9fa}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#007bff}.dropdown-item.disabled,.dropdown-item:disabled{color:#6c757d;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1.5rem;margin-bottom:0;font-size:.875rem;color:#6c757d;white-space:nowrap}.btn-group,.btn-group-vertical{position:relative;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;-webkit-box-flex:0;-ms-flex:0 1 auto;flex:0 1 auto}.btn-group-vertical>.btn:hover,.btn-group>.btn:hover{z-index:1}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus{z-index:1}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group,.btn-group-vertical .btn+.btn,.btn-group-vertical .btn+.btn-group,.btn-group-vertical .btn-group+.btn,.btn-group-vertical .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after{margin-left:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.btn-group-vertical .btn,.btn-group-vertical .btn-group{width:100%}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}.btn-group-toggle>.btn,.btn-group-toggle>.btn-group>.btn{margin-bottom:0}.btn-group-toggle>.btn input[type=checkbox],.btn-group-toggle>.btn input[type=radio],.btn-group-toggle>.btn-group>.btn input[type=checkbox],.btn-group-toggle>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch;width:100%}.input-group>.custom-file,.input-group>.custom-select,.input-group>.form-control{position:relative;-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;width:1%;margin-bottom:0}.input-group>.custom-file:focus,.input-group>.custom-select:focus,.input-group>.form-control:focus{z-index:3}.input-group>.custom-file+.custom-file,.input-group>.custom-file+.custom-select,.input-group>.custom-file+.form-control,.input-group>.custom-select+.custom-file,.input-group>.custom-select+.custom-select,.input-group>.custom-select+.form-control,.input-group>.form-control+.custom-file,.input-group>.form-control+.custom-select,.input-group>.form-control+.form-control{margin-left:-1px}.input-group>.custom-select:not(:last-child),.input-group>.form-control:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-select:not(:first-child),.input-group>.form-control:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.custom-file{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.input-group>.custom-file:not(:last-child) .custom-file-label,.input-group>.custom-file:not(:last-child) .custom-file-label::before{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-file:not(:first-child) .custom-file-label,.input-group>.custom-file:not(:first-child) .custom-file-label::before{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-append,.input-group-prepend{display:-webkit-box;display:-ms-flexbox;display:flex}.input-group-append .btn,.input-group-prepend .btn{position:relative;z-index:2}.input-group-append .btn+.btn,.input-group-append .btn+.input-group-text,.input-group-append .input-group-text+.btn,.input-group-append .input-group-text+.input-group-text,.input-group-prepend .btn+.btn,.input-group-prepend .btn+.input-group-text,.input-group-prepend .input-group-text+.btn,.input-group-prepend .input-group-text+.input-group-text{margin-left:-1px}.input-group-prepend{margin-right:-1px}.input-group-append{margin-left:-1px}.input-group-text{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:.375rem .75rem;margin-bottom:0;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.input-group-text input[type=checkbox],.input-group-text input[type=radio]{margin-top:0}.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group>.input-group-append:last-child>.input-group-text:not(:last-child),.input-group>.input-group-append:not(:last-child)>.btn,.input-group>.input-group-append:not(:last-child)>.input-group-text,.input-group>.input-group-prepend>.btn,.input-group>.input-group-prepend>.input-group-text{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.input-group-append>.btn,.input-group>.input-group-append>.input-group-text,.input-group>.input-group-prepend:first-child>.btn:not(:first-child),.input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child),.input-group>.input-group-prepend:not(:first-child)>.btn,.input-group>.input-group-prepend:not(:first-child)>.input-group-text{border-top-left-radius:0;border-bottom-left-radius:0}.custom-control{position:relative;display:block;min-height:1.5rem;padding-left:1.5rem}.custom-control-inline{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;margin-right:1rem}.custom-control-input{position:absolute;z-index:-1;opacity:0}.custom-control-input:checked~.custom-control-label::before{color:#fff;background-color:#007bff}.custom-control-input:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-control-input:active~.custom-control-label::before{color:#fff;background-color:#b3d7ff}.custom-control-input:disabled~.custom-control-label{color:#6c757d}.custom-control-input:disabled~.custom-control-label::before{background-color:#e9ecef}.custom-control-label{margin-bottom:0}.custom-control-label::before{position:absolute;top:.25rem;left:0;display:block;width:1rem;height:1rem;pointer-events:none;content:"";-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#dee2e6}.custom-control-label::after{position:absolute;top:.25rem;left:0;display:block;width:1rem;height:1rem;content:"";background-repeat:no-repeat;background-position:center center;background-size:50% 50%}.custom-checkbox .custom-control-label::before{border-radius:.25rem}.custom-checkbox .custom-control-input:checked~.custom-control-label::before{background-color:#007bff}.custom-checkbox .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::before{background-color:#007bff}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3E%3Cpath stroke='%23fff' d='M0 2h4'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-radio .custom-control-label::before{border-radius:50%}.custom-radio .custom-control-input:checked~.custom-control-label::before{background-color:#007bff}.custom-radio .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='%23fff'/%3E%3C/svg%3E")}.custom-radio .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-select{display:inline-block;width:100%;height:calc(2.25rem + 2px);padding:.375rem 1.75rem .375rem .75rem;line-height:1.5;color:#495057;vertical-align:middle;background:#fff url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right .75rem center;background-size:8px 10px;border:1px solid #ced4da;border-radius:.25rem;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-select:focus{border-color:#80bdff;outline:0;box-shadow:inset 0 1px 2px rgba(0,0,0,.075),0 0 5px rgba(128,189,255,.5)}.custom-select:focus::-ms-value{color:#495057;background-color:#fff}.custom-select[multiple],.custom-select[size]:not([size="1"]){height:auto;padding-right:.75rem;background-image:none}.custom-select:disabled{color:#6c757d;background-color:#e9ecef}.custom-select::-ms-expand{opacity:0}.custom-select-sm{height:calc(1.8125rem + 2px);padding-top:.375rem;padding-bottom:.375rem;font-size:75%}.custom-select-lg{height:calc(2.875rem + 2px);padding-top:.375rem;padding-bottom:.375rem;font-size:125%}.custom-file{position:relative;display:inline-block;width:100%;height:calc(2.25rem + 2px);margin-bottom:0}.custom-file-input{position:relative;z-index:2;width:100%;height:calc(2.25rem + 2px);margin:0;opacity:0}.custom-file-input:focus~.custom-file-control{border-color:#80bdff;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-file-input:focus~.custom-file-control::before{border-color:#80bdff}.custom-file-input:lang(en)~.custom-file-label::after{content:"Browse"}.custom-file-label{position:absolute;top:0;right:0;left:0;z-index:1;height:calc(2.25rem + 2px);padding:.375rem .75rem;line-height:1.5;color:#495057;background-color:#fff;border:1px solid #ced4da;border-radius:.25rem}.custom-file-label::after{position:absolute;top:0;right:0;bottom:0;z-index:3;display:block;height:calc(calc(2.25rem + 2px) - 1px * 2);padding:.375rem .75rem;line-height:1.5;color:#495057;content:"Browse";background-color:#e9ecef;border-left:1px solid #ced4da;border-radius:0 .25rem .25rem 0}.nav{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#6c757d}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-item{margin-bottom:-1px}.nav-tabs .nav-link{border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #dee2e6}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#007bff}.nav-fill .nav-item{-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;text-align:center}.nav-justified .nav-item{-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;padding:.5rem 1rem}.navbar>.container,.navbar>.container-fluid{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.navbar-brand{display:inline-block;padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;line-height:inherit;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-nav{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static;float:none}.navbar-text{display:inline-block;padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{-ms-flex-preferred-size:100%;flex-basis:100%;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}.navbar-toggler:not(:disabled):not(.disabled){cursor:pointer}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;content:"";background:no-repeat center center;background-size:100% 100%}@media (max-width:575.98px){.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:576px){.navbar-expand-sm{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-sm .navbar-nav{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-sm .navbar-collapse{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .dropup .dropdown-menu{top:auto;bottom:100%}}@media (max-width:767.98px){.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:768px){.navbar-expand-md{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-md .navbar-nav{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-md .navbar-collapse{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .dropup .dropdown-menu{top:auto;bottom:100%}}@media (max-width:991.98px){.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:992px){.navbar-expand-lg{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-lg .navbar-nav{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-lg .navbar-collapse{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .dropup .dropdown-menu{top:auto;bottom:100%}}@media (max-width:1199.98px){.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:1200px){.navbar-expand-xl{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-xl .navbar-nav{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-xl .navbar-collapse{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .dropup .dropdown-menu{top:auto;bottom:100%}}.navbar-expand{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid{padding-right:0;padding-left:0}.navbar-expand .navbar-nav{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .dropdown-menu-right{right:0;left:auto}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand>.container,.navbar-expand>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand .navbar-collapse{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .dropup .dropdown-menu{top:auto;bottom:100%}.navbar-light .navbar-brand{color:rgba(0,0,0,.9)}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.5)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.5);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(0, 0, 0, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-light .navbar-text{color:rgba(0,0,0,.5)}.navbar-light .navbar-text a{color:rgba(0,0,0,.9)}.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:rgba(0,0,0,.9)}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.5)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:rgba(255,255,255,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .nav-link.show,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.5);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-dark .navbar-text{color:rgba(255,255,255,.5)}.navbar-dark .navbar-text a{color:#fff}.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group:first-child .list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card>.list-group:last-child .list-group-item:last-child{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-body{-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card-header{padding:.75rem 1.25rem;margin-bottom:0;background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-header+.list-group .list-group-item:first-child{border-top:0}.card-footer{padding:.75rem 1.25rem;background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.625rem;margin-bottom:-.75rem;margin-left:-.625rem;border-bottom:0}.card-header-pills{margin-right:-.625rem;margin-left:-.625rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem}.card-img{width:100%;border-radius:calc(.25rem - 1px)}.card-img-top{width:100%;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img-bottom{width:100%;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-deck{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.card-deck .card{margin-bottom:15px}@media (min-width:576px){.card-deck{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row wrap;flex-flow:row wrap;margin-right:-15px;margin-left:-15px}.card-deck .card{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-flex:1;-ms-flex:1 0 0%;flex:1 0 0%;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;margin-right:15px;margin-bottom:0;margin-left:15px}}.card-group{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.card-group>.card{margin-bottom:15px}@media (min-width:576px){.card-group{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row wrap;flex-flow:row wrap}.card-group>.card{-webkit-box-flex:1;-ms-flex:1 0 0%;flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:first-child .card-header,.card-group>.card:first-child .card-img-top{border-top-right-radius:0}.card-group>.card:first-child .card-footer,.card-group>.card:first-child .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:last-child .card-header,.card-group>.card:last-child .card-img-top{border-top-left-radius:0}.card-group>.card:last-child .card-footer,.card-group>.card:last-child .card-img-bottom{border-bottom-left-radius:0}.card-group>.card:only-child{border-radius:.25rem}.card-group>.card:only-child .card-header,.card-group>.card:only-child .card-img-top{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card-group>.card:only-child .card-footer,.card-group>.card:only-child .card-img-bottom{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-group>.card:not(:first-child):not(:last-child):not(:only-child){border-radius:0}.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-footer,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-header,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-img-bottom,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-img-top{border-radius:0}}.card-columns .card{margin-bottom:.75rem}@media (min-width:576px){.card-columns{-webkit-column-count:3;-moz-column-count:3;column-count:3;-webkit-column-gap:1.25rem;-moz-column-gap:1.25rem;column-gap:1.25rem}.card-columns .card{display:inline-block;width:100%}}.breadcrumb{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#e9ecef;border-radius:.25rem}.breadcrumb-item+.breadcrumb-item::before{display:inline-block;padding-right:.5rem;padding-left:.5rem;color:#6c757d;content:"/"}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:underline}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:none}.breadcrumb-item.active{color:#6c757d}.pagination{display:-webkit-box;display:-ms-flexbox;display:flex;padding-left:0;list-style:none;border-radius:.25rem}.page-link{position:relative;display:block;padding:.5rem .75rem;margin-left:-1px;line-height:1.25;color:#007bff;background-color:#fff;border:1px solid #dee2e6}.page-link:hover{color:#0056b3;text-decoration:none;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:2;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.page-link:not(:disabled):not(.disabled){cursor:pointer}.page-item:first-child .page-link{margin-left:0;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.page-item.active .page-link{z-index:1;color:#fff;background-color:#007bff;border-color:#007bff}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;cursor:auto;background-color:#fff;border-color:#dee2e6}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem;line-height:1.5}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem;line-height:1.5}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.badge-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.badge-primary{color:#fff;background-color:#007bff}.badge-primary[href]:focus,.badge-primary[href]:hover{color:#fff;text-decoration:none;background-color:#0062cc}.badge-secondary{color:#fff;background-color:#6c757d}.badge-secondary[href]:focus,.badge-secondary[href]:hover{color:#fff;text-decoration:none;background-color:#545b62}.badge-success{color:#fff;background-color:#28a745}.badge-success[href]:focus,.badge-success[href]:hover{color:#fff;text-decoration:none;background-color:#1e7e34}.badge-info{color:#fff;background-color:#17a2b8}.badge-info[href]:focus,.badge-info[href]:hover{color:#fff;text-decoration:none;background-color:#117a8b}.badge-warning{color:#212529;background-color:#ffc107}.badge-warning[href]:focus,.badge-warning[href]:hover{color:#212529;text-decoration:none;background-color:#d39e00}.badge-danger{color:#fff;background-color:#dc3545}.badge-danger[href]:focus,.badge-danger[href]:hover{color:#fff;text-decoration:none;background-color:#bd2130}.badge-light{color:#212529;background-color:#f8f9fa}.badge-light[href]:focus,.badge-light[href]:hover{color:#212529;text-decoration:none;background-color:#dae0e5}.badge-dark{color:#fff;background-color:#343a40}.badge-dark[href]:focus,.badge-dark[href]:hover{color:#fff;text-decoration:none;background-color:#1d2124}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#e9ecef;border-radius:.3rem}@media (min-width:576px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:4rem}.alert-dismissible .close{position:absolute;top:0;right:0;padding:.75rem 1.25rem;color:inherit}.alert-primary{color:#004085;background-color:#cce5ff;border-color:#b8daff}.alert-primary hr{border-top-color:#9fcdff}.alert-primary .alert-link{color:#002752}.alert-secondary{color:#383d41;background-color:#e2e3e5;border-color:#d6d8db}.alert-secondary hr{border-top-color:#c8cbcf}.alert-secondary .alert-link{color:#202326}.alert-success{color:#155724;background-color:#d4edda;border-color:#c3e6cb}.alert-success hr{border-top-color:#b1dfbb}.alert-success .alert-link{color:#0b2e13}.alert-info{color:#0c5460;background-color:#d1ecf1;border-color:#bee5eb}.alert-info hr{border-top-color:#abdde5}.alert-info .alert-link{color:#062c33}.alert-warning{color:#856404;background-color:#fff3cd;border-color:#ffeeba}.alert-warning hr{border-top-color:#ffe8a1}.alert-warning .alert-link{color:#533f03}.alert-danger{color:#721c24;background-color:#f8d7da;border-color:#f5c6cb}.alert-danger hr{border-top-color:#f1b0b7}.alert-danger .alert-link{color:#491217}.alert-light{color:#818182;background-color:#fefefe;border-color:#fdfdfe}.alert-light hr{border-top-color:#ececf6}.alert-light .alert-link{color:#686868}.alert-dark{color:#1b1e21;background-color:#d6d8d9;border-color:#c6c8ca}.alert-dark hr{border-top-color:#b9bbbe}.alert-dark .alert-link{color:#040505}@-webkit-keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}.progress{display:-webkit-box;display:-ms-flexbox;display:flex;height:1rem;overflow:hidden;font-size:.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;color:#fff;text-align:center;background-color:#007bff;transition:width .6s ease}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{-webkit-animation:progress-bar-stripes 1s linear infinite;animation:progress-bar-stripes 1s linear infinite}.media{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.media-body{-webkit-box-flex:1;-ms-flex:1;flex:1}.list-group{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;margin-bottom:-1px;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.list-group-item:focus,.list-group-item:hover{z-index:1;text-decoration:none}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#007bff;border-color:#007bff}.list-group-flush .list-group-item{border-right:0;border-left:0;border-radius:0}.list-group-flush:first-child .list-group-item:first-child{border-top:0}.list-group-flush:last-child .list-group-item:last-child{border-bottom:0}.list-group-item-primary{color:#004085;background-color:#b8daff}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#004085;background-color:#9fcdff}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#004085;border-color:#004085}.list-group-item-secondary{color:#383d41;background-color:#d6d8db}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#383d41;background-color:#c8cbcf}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#383d41;border-color:#383d41}.list-group-item-success{color:#155724;background-color:#c3e6cb}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#155724;background-color:#b1dfbb}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#155724;border-color:#155724}.list-group-item-info{color:#0c5460;background-color:#bee5eb}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#0c5460;background-color:#abdde5}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#0c5460;border-color:#0c5460}.list-group-item-warning{color:#856404;background-color:#ffeeba}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{color:#856404;background-color:#ffe8a1}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#856404;border-color:#856404}.list-group-item-danger{color:#721c24;background-color:#f5c6cb}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#721c24;background-color:#f1b0b7}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#721c24;border-color:#721c24}.list-group-item-light{color:#818182;background-color:#fdfdfe}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:#818182;background-color:#ececf6}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#818182;border-color:#818182}.list-group-item-dark{color:#1b1e21;background-color:#c6c8ca}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{color:#1b1e21;background-color:#b9bbbe}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#1b1e21;border-color:#1b1e21}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.5}.close:focus,.close:hover{color:#000;text-decoration:none;opacity:.75}.close:not(:disabled):not(.disabled){cursor:pointer}button.close{padding:0;background-color:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;outline:0}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:-webkit-transform .3s ease-out;transition:transform .3s ease-out;transition:transform .3s ease-out,-webkit-transform .3s ease-out;-webkit-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.show .modal-dialog{-webkit-transform:translate(0,0);transform:translate(0,0)}.modal-dialog-centered{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;min-height:calc(100% - (.5rem * 2))}.modal-content{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;padding:1rem;border-bottom:1px solid #e9ecef;border-top-left-radius:.3rem;border-top-right-radius:.3rem}.modal-header .close{padding:1rem;margin:-1rem -1rem -1rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem}.modal-footer{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end;padding:1rem;border-top:1px solid #e9ecef}.modal-footer>:not(:first-child){margin-left:.25rem}.modal-footer>:not(:last-child){margin-right:.25rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-centered{min-height:calc(100% - (1.75rem * 2))}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg{max-width:800px}}.tooltip{position:absolute;z-index:1070;display:block;margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[x-placement^=top],.bs-tooltip-top{padding:.4rem 0}.bs-tooltip-auto[x-placement^=top] .arrow,.bs-tooltip-top .arrow{bottom:0}.bs-tooltip-auto[x-placement^=top] .arrow::before,.bs-tooltip-top .arrow::before{top:0;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-auto[x-placement^=right],.bs-tooltip-right{padding:0 .4rem}.bs-tooltip-auto[x-placement^=right] .arrow,.bs-tooltip-right .arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=right] .arrow::before,.bs-tooltip-right .arrow::before{right:0;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-auto[x-placement^=bottom],.bs-tooltip-bottom{padding:.4rem 0}.bs-tooltip-auto[x-placement^=bottom] .arrow,.bs-tooltip-bottom .arrow{top:0}.bs-tooltip-auto[x-placement^=bottom] .arrow::before,.bs-tooltip-bottom .arrow::before{bottom:0;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-auto[x-placement^=left],.bs-tooltip-left{padding:0 .4rem}.bs-tooltip-auto[x-placement^=left] .arrow,.bs-tooltip-left .arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=left] .arrow::before,.bs-tooltip-left .arrow::before{left:0;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .arrow{position:absolute;display:block;width:1rem;height:.5rem;margin:0 .3rem}.popover .arrow::after,.popover .arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-auto[x-placement^=top],.bs-popover-top{margin-bottom:.5rem}.bs-popover-auto[x-placement^=top] .arrow,.bs-popover-top .arrow{bottom:calc((.5rem + 1px) * -1)}.bs-popover-auto[x-placement^=top] .arrow::after,.bs-popover-auto[x-placement^=top] .arrow::before,.bs-popover-top .arrow::after,.bs-popover-top .arrow::before{border-width:.5rem .5rem 0}.bs-popover-auto[x-placement^=top] .arrow::before,.bs-popover-top .arrow::before{bottom:0;border-top-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=top] .arrow::after,.bs-popover-top .arrow::after{bottom:1px;border-top-color:#fff}.bs-popover-auto[x-placement^=right],.bs-popover-right{margin-left:.5rem}.bs-popover-auto[x-placement^=right] .arrow,.bs-popover-right .arrow{left:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=right] .arrow::after,.bs-popover-auto[x-placement^=right] .arrow::before,.bs-popover-right .arrow::after,.bs-popover-right .arrow::before{border-width:.5rem .5rem .5rem 0}.bs-popover-auto[x-placement^=right] .arrow::before,.bs-popover-right .arrow::before{left:0;border-right-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=right] .arrow::after,.bs-popover-right .arrow::after{left:1px;border-right-color:#fff}.bs-popover-auto[x-placement^=bottom],.bs-popover-bottom{margin-top:.5rem}.bs-popover-auto[x-placement^=bottom] .arrow,.bs-popover-bottom .arrow{top:calc((.5rem + 1px) * -1)}.bs-popover-auto[x-placement^=bottom] .arrow::after,.bs-popover-auto[x-placement^=bottom] .arrow::before,.bs-popover-bottom .arrow::after,.bs-popover-bottom .arrow::before{border-width:0 .5rem .5rem .5rem}.bs-popover-auto[x-placement^=bottom] .arrow::before,.bs-popover-bottom .arrow::before{top:0;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=bottom] .arrow::after,.bs-popover-bottom .arrow::after{top:1px;border-bottom-color:#fff}.bs-popover-auto[x-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #f7f7f7}.bs-popover-auto[x-placement^=left],.bs-popover-left{margin-right:.5rem}.bs-popover-auto[x-placement^=left] .arrow,.bs-popover-left .arrow{right:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=left] .arrow::after,.bs-popover-auto[x-placement^=left] .arrow::before,.bs-popover-left .arrow::after,.bs-popover-left .arrow::before{border-width:.5rem 0 .5rem .5rem}.bs-popover-auto[x-placement^=left] .arrow::before,.bs-popover-left .arrow::before{right:0;border-left-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=left] .arrow::after,.bs-popover-left .arrow::after{right:1px;border-left-color:#fff}.popover-header{padding:.5rem .75rem;margin-bottom:0;font-size:1rem;color:inherit;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:.5rem .75rem;color:#212529}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-item{position:relative;display:none;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:100%;transition:-webkit-transform .6s ease;transition:transform .6s ease;transition:transform .6s ease,-webkit-transform .6s ease;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.carousel-item-next,.carousel-item-prev{position:absolute;top:0}.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{-webkit-transform:translateX(0);transform:translateX(0)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.carousel-item-next.carousel-item-left,.carousel-item-prev.carousel-item-right{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.active.carousel-item-right,.carousel-item-next{-webkit-transform:translateX(100%);transform:translateX(100%)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.active.carousel-item-right,.carousel-item-next{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}.active.carousel-item-left,.carousel-item-prev{-webkit-transform:translateX(-100%);transform:translateX(-100%)}@supports ((-webkit-transform-style:preserve-3d) or (transform-style:preserve-3d)){.active.carousel-item-left,.carousel-item-prev{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;width:15%;color:#fff;text-align:center;opacity:.5}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:20px;height:20px;background:transparent no-repeat center center;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3E%3C/svg%3E")}.carousel-control-next-icon{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3E%3C/svg%3E")}.carousel-indicators{position:absolute;right:0;bottom:10px;left:0;z-index:15;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{position:relative;-webkit-box-flex:0;-ms-flex:0 1 auto;flex:0 1 auto;width:30px;height:3px;margin-right:3px;margin-left:3px;text-indent:-999px;background-color:rgba(255,255,255,.5)}.carousel-indicators li::before{position:absolute;top:-10px;left:0;display:inline-block;width:100%;height:10px;content:""}.carousel-indicators li::after{position:absolute;bottom:-10px;left:0;display:inline-block;width:100%;height:10px;content:""}.carousel-indicators .active{background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-primary{background-color:#007bff!important}a.bg-primary:focus,a.bg-primary:hover,button.bg-primary:focus,button.bg-primary:hover{background-color:#0062cc!important}.bg-secondary{background-color:#6c757d!important}a.bg-secondary:focus,a.bg-secondary:hover,button.bg-secondary:focus,button.bg-secondary:hover{background-color:#545b62!important}.bg-success{background-color:#28a745!important}a.bg-success:focus,a.bg-success:hover,button.bg-success:focus,button.bg-success:hover{background-color:#1e7e34!important}.bg-info{background-color:#17a2b8!important}a.bg-info:focus,a.bg-info:hover,button.bg-info:focus,button.bg-info:hover{background-color:#117a8b!important}.bg-warning{background-color:#ffc107!important}a.bg-warning:focus,a.bg-warning:hover,button.bg-warning:focus,button.bg-warning:hover{background-color:#d39e00!important}.bg-danger{background-color:#dc3545!important}a.bg-danger:focus,a.bg-danger:hover,button.bg-danger:focus,button.bg-danger:hover{background-color:#bd2130!important}.bg-light{background-color:#f8f9fa!important}a.bg-light:focus,a.bg-light:hover,button.bg-light:focus,button.bg-light:hover{background-color:#dae0e5!important}.bg-dark{background-color:#343a40!important}a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover{background-color:#1d2124!important}.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.border{border:1px solid #dee2e6!important}.border-top{border-top:1px solid #dee2e6!important}.border-right{border-right:1px solid #dee2e6!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-left{border-left:1px solid #dee2e6!important}.border-0{border:0!important}.border-top-0{border-top:0!important}.border-right-0{border-right:0!important}.border-bottom-0{border-bottom:0!important}.border-left-0{border-left:0!important}.border-primary{border-color:#007bff!important}.border-secondary{border-color:#6c757d!important}.border-success{border-color:#28a745!important}.border-info{border-color:#17a2b8!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#343a40!important}.border-white{border-color:#fff!important}.rounded{border-radius:.25rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-right{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-left{border-top-left-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-circle{border-radius:50%!important}.rounded-0{border-radius:0!important}.clearfix::after{display:block;clear:both;content:""}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.d-inline-flex{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important}@media (min-width:576px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.d-sm-inline-flex{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.d-md-inline-flex{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:992px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.d-lg-inline-flex{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.d-xl-inline-flex{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important}}@media print{.d-print-none{display:none!important}.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.d-print-inline-flex{display:-webkit-inline-box!important;display:-ms-inline-flexbox!important;display:inline-flex!important}}.embed-responsive{position:relative;display:block;width:100%;padding:0;overflow:hidden}.embed-responsive::before{display:block;content:""}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-21by9::before{padding-top:42.857143%}.embed-responsive-16by9::before{padding-top:56.25%}.embed-responsive-4by3::before{padding-top:75%}.embed-responsive-1by1::before{padding-top:100%}.flex-row{-webkit-box-orient:horizontal!important;-webkit-box-direction:normal!important;-ms-flex-direction:row!important;flex-direction:row!important}.flex-column{-webkit-box-orient:vertical!important;-webkit-box-direction:normal!important;-ms-flex-direction:column!important;flex-direction:column!important}.flex-row-reverse{-webkit-box-orient:horizontal!important;-webkit-box-direction:reverse!important;-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-column-reverse{-webkit-box-orient:vertical!important;-webkit-box-direction:reverse!important;-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-start{-webkit-box-pack:start!important;-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-end{-webkit-box-pack:end!important;-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-center{-webkit-box-pack:center!important;-ms-flex-pack:center!important;justify-content:center!important}.justify-content-between{-webkit-box-pack:justify!important;-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-start{-webkit-box-align:start!important;-ms-flex-align:start!important;align-items:flex-start!important}.align-items-end{-webkit-box-align:end!important;-ms-flex-align:end!important;align-items:flex-end!important}.align-items-center{-webkit-box-align:center!important;-ms-flex-align:center!important;align-items:center!important}.align-items-baseline{-webkit-box-align:baseline!important;-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-stretch{-webkit-box-align:stretch!important;-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}@media (min-width:576px){.flex-sm-row{-webkit-box-orient:horizontal!important;-webkit-box-direction:normal!important;-ms-flex-direction:row!important;flex-direction:row!important}.flex-sm-column{-webkit-box-orient:vertical!important;-webkit-box-direction:normal!important;-ms-flex-direction:column!important;flex-direction:column!important}.flex-sm-row-reverse{-webkit-box-orient:horizontal!important;-webkit-box-direction:reverse!important;-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-sm-column-reverse{-webkit-box-orient:vertical!important;-webkit-box-direction:reverse!important;-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-sm-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-sm-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-sm-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-sm-start{-webkit-box-pack:start!important;-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-sm-end{-webkit-box-pack:end!important;-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-sm-center{-webkit-box-pack:center!important;-ms-flex-pack:center!important;justify-content:center!important}.justify-content-sm-between{-webkit-box-pack:justify!important;-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-sm-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-sm-start{-webkit-box-align:start!important;-ms-flex-align:start!important;align-items:flex-start!important}.align-items-sm-end{-webkit-box-align:end!important;-ms-flex-align:end!important;align-items:flex-end!important}.align-items-sm-center{-webkit-box-align:center!important;-ms-flex-align:center!important;align-items:center!important}.align-items-sm-baseline{-webkit-box-align:baseline!important;-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-sm-stretch{-webkit-box-align:stretch!important;-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-sm-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-sm-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-sm-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-sm-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-sm-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-sm-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-sm-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-sm-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-sm-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-sm-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-sm-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-sm-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:768px){.flex-md-row{-webkit-box-orient:horizontal!important;-webkit-box-direction:normal!important;-ms-flex-direction:row!important;flex-direction:row!important}.flex-md-column{-webkit-box-orient:vertical!important;-webkit-box-direction:normal!important;-ms-flex-direction:column!important;flex-direction:column!important}.flex-md-row-reverse{-webkit-box-orient:horizontal!important;-webkit-box-direction:reverse!important;-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-md-column-reverse{-webkit-box-orient:vertical!important;-webkit-box-direction:reverse!important;-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-md-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-md-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-md-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-md-start{-webkit-box-pack:start!important;-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-md-end{-webkit-box-pack:end!important;-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-md-center{-webkit-box-pack:center!important;-ms-flex-pack:center!important;justify-content:center!important}.justify-content-md-between{-webkit-box-pack:justify!important;-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-md-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-md-start{-webkit-box-align:start!important;-ms-flex-align:start!important;align-items:flex-start!important}.align-items-md-end{-webkit-box-align:end!important;-ms-flex-align:end!important;align-items:flex-end!important}.align-items-md-center{-webkit-box-align:center!important;-ms-flex-align:center!important;align-items:center!important}.align-items-md-baseline{-webkit-box-align:baseline!important;-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-md-stretch{-webkit-box-align:stretch!important;-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-md-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-md-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-md-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-md-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-md-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-md-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-md-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-md-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-md-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-md-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-md-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-md-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:992px){.flex-lg-row{-webkit-box-orient:horizontal!important;-webkit-box-direction:normal!important;-ms-flex-direction:row!important;flex-direction:row!important}.flex-lg-column{-webkit-box-orient:vertical!important;-webkit-box-direction:normal!important;-ms-flex-direction:column!important;flex-direction:column!important}.flex-lg-row-reverse{-webkit-box-orient:horizontal!important;-webkit-box-direction:reverse!important;-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-lg-column-reverse{-webkit-box-orient:vertical!important;-webkit-box-direction:reverse!important;-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-lg-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-lg-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-lg-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-lg-start{-webkit-box-pack:start!important;-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-lg-end{-webkit-box-pack:end!important;-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-lg-center{-webkit-box-pack:center!important;-ms-flex-pack:center!important;justify-content:center!important}.justify-content-lg-between{-webkit-box-pack:justify!important;-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-lg-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-lg-start{-webkit-box-align:start!important;-ms-flex-align:start!important;align-items:flex-start!important}.align-items-lg-end{-webkit-box-align:end!important;-ms-flex-align:end!important;align-items:flex-end!important}.align-items-lg-center{-webkit-box-align:center!important;-ms-flex-align:center!important;align-items:center!important}.align-items-lg-baseline{-webkit-box-align:baseline!important;-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-lg-stretch{-webkit-box-align:stretch!important;-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-lg-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-lg-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-lg-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-lg-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-lg-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-lg-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-lg-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-lg-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-lg-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-lg-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-lg-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-lg-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:1200px){.flex-xl-row{-webkit-box-orient:horizontal!important;-webkit-box-direction:normal!important;-ms-flex-direction:row!important;flex-direction:row!important}.flex-xl-column{-webkit-box-orient:vertical!important;-webkit-box-direction:normal!important;-ms-flex-direction:column!important;flex-direction:column!important}.flex-xl-row-reverse{-webkit-box-orient:horizontal!important;-webkit-box-direction:reverse!important;-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-xl-column-reverse{-webkit-box-orient:vertical!important;-webkit-box-direction:reverse!important;-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-xl-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-xl-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-xl-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.justify-content-xl-start{-webkit-box-pack:start!important;-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-xl-end{-webkit-box-pack:end!important;-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-xl-center{-webkit-box-pack:center!important;-ms-flex-pack:center!important;justify-content:center!important}.justify-content-xl-between{-webkit-box-pack:justify!important;-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-xl-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-xl-start{-webkit-box-align:start!important;-ms-flex-align:start!important;align-items:flex-start!important}.align-items-xl-end{-webkit-box-align:end!important;-ms-flex-align:end!important;align-items:flex-end!important}.align-items-xl-center{-webkit-box-align:center!important;-ms-flex-align:center!important;align-items:center!important}.align-items-xl-baseline{-webkit-box-align:baseline!important;-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-xl-stretch{-webkit-box-align:stretch!important;-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-xl-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-xl-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-xl-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-xl-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-xl-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-xl-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-xl-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-xl-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-xl-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-xl-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-xl-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-xl-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}.float-left{float:left!important}.float-right{float:right!important}.float-none{float:none!important}@media (min-width:576px){.float-sm-left{float:left!important}.float-sm-right{float:right!important}.float-sm-none{float:none!important}}@media (min-width:768px){.float-md-left{float:left!important}.float-md-right{float:right!important}.float-md-none{float:none!important}}@media (min-width:992px){.float-lg-left{float:left!important}.float-lg-right{float:right!important}.float-lg-none{float:none!important}}@media (min-width:1200px){.float-xl-left{float:left!important}.float-xl-right{float:right!important}.float-xl-none{float:none!important}}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}@supports ((position:-webkit-sticky) or (position:sticky)){.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}.sr-only{position:absolute;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;-webkit-clip-path:inset(50%);clip-path:inset(50%);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;overflow:visible;clip:auto;white-space:normal;-webkit-clip-path:none;clip-path:none}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.m-0{margin:0!important}.mt-0,.my-0{margin-top:0!important}.mr-0,.mx-0{margin-right:0!important}.mb-0,.my-0{margin-bottom:0!important}.ml-0,.mx-0{margin-left:0!important}.m-1{margin:.25rem!important}.mt-1,.my-1{margin-top:.25rem!important}.mr-1,.mx-1{margin-right:.25rem!important}.mb-1,.my-1{margin-bottom:.25rem!important}.ml-1,.mx-1{margin-left:.25rem!important}.m-2{margin:.5rem!important}.mt-2,.my-2{margin-top:.5rem!important}.mr-2,.mx-2{margin-right:.5rem!important}.mb-2,.my-2{margin-bottom:.5rem!important}.ml-2,.mx-2{margin-left:.5rem!important}.m-3{margin:1rem!important}.mt-3,.my-3{margin-top:1rem!important}.mr-3,.mx-3{margin-right:1rem!important}.mb-3,.my-3{margin-bottom:1rem!important}.ml-3,.mx-3{margin-left:1rem!important}.m-4{margin:1.5rem!important}.mt-4,.my-4{margin-top:1.5rem!important}.mr-4,.mx-4{margin-right:1.5rem!important}.mb-4,.my-4{margin-bottom:1.5rem!important}.ml-4,.mx-4{margin-left:1.5rem!important}.m-5{margin:3rem!important}.mt-5,.my-5{margin-top:3rem!important}.mr-5,.mx-5{margin-right:3rem!important}.mb-5,.my-5{margin-bottom:3rem!important}.ml-5,.mx-5{margin-left:3rem!important}.p-0{padding:0!important}.pt-0,.py-0{padding-top:0!important}.pr-0,.px-0{padding-right:0!important}.pb-0,.py-0{padding-bottom:0!important}.pl-0,.px-0{padding-left:0!important}.p-1{padding:.25rem!important}.pt-1,.py-1{padding-top:.25rem!important}.pr-1,.px-1{padding-right:.25rem!important}.pb-1,.py-1{padding-bottom:.25rem!important}.pl-1,.px-1{padding-left:.25rem!important}.p-2{padding:.5rem!important}.pt-2,.py-2{padding-top:.5rem!important}.pr-2,.px-2{padding-right:.5rem!important}.pb-2,.py-2{padding-bottom:.5rem!important}.pl-2,.px-2{padding-left:.5rem!important}.p-3{padding:1rem!important}.pt-3,.py-3{padding-top:1rem!important}.pr-3,.px-3{padding-right:1rem!important}.pb-3,.py-3{padding-bottom:1rem!important}.pl-3,.px-3{padding-left:1rem!important}.p-4{padding:1.5rem!important}.pt-4,.py-4{padding-top:1.5rem!important}.pr-4,.px-4{padding-right:1.5rem!important}.pb-4,.py-4{padding-bottom:1.5rem!important}.pl-4,.px-4{padding-left:1.5rem!important}.p-5{padding:3rem!important}.pt-5,.py-5{padding-top:3rem!important}.pr-5,.px-5{padding-right:3rem!important}.pb-5,.py-5{padding-bottom:3rem!important}.pl-5,.px-5{padding-left:3rem!important}.m-auto{margin:auto!important}.mt-auto,.my-auto{margin-top:auto!important}.mr-auto,.mx-auto{margin-right:auto!important}.mb-auto,.my-auto{margin-bottom:auto!important}.ml-auto,.mx-auto{margin-left:auto!important}@media (min-width:576px){.m-sm-0{margin:0!important}.mt-sm-0,.my-sm-0{margin-top:0!important}.mr-sm-0,.mx-sm-0{margin-right:0!important}.mb-sm-0,.my-sm-0{margin-bottom:0!important}.ml-sm-0,.mx-sm-0{margin-left:0!important}.m-sm-1{margin:.25rem!important}.mt-sm-1,.my-sm-1{margin-top:.25rem!important}.mr-sm-1,.mx-sm-1{margin-right:.25rem!important}.mb-sm-1,.my-sm-1{margin-bottom:.25rem!important}.ml-sm-1,.mx-sm-1{margin-left:.25rem!important}.m-sm-2{margin:.5rem!important}.mt-sm-2,.my-sm-2{margin-top:.5rem!important}.mr-sm-2,.mx-sm-2{margin-right:.5rem!important}.mb-sm-2,.my-sm-2{margin-bottom:.5rem!important}.ml-sm-2,.mx-sm-2{margin-left:.5rem!important}.m-sm-3{margin:1rem!important}.mt-sm-3,.my-sm-3{margin-top:1rem!important}.mr-sm-3,.mx-sm-3{margin-right:1rem!important}.mb-sm-3,.my-sm-3{margin-bottom:1rem!important}.ml-sm-3,.mx-sm-3{margin-left:1rem!important}.m-sm-4{margin:1.5rem!important}.mt-sm-4,.my-sm-4{margin-top:1.5rem!important}.mr-sm-4,.mx-sm-4{margin-right:1.5rem!important}.mb-sm-4,.my-sm-4{margin-bottom:1.5rem!important}.ml-sm-4,.mx-sm-4{margin-left:1.5rem!important}.m-sm-5{margin:3rem!important}.mt-sm-5,.my-sm-5{margin-top:3rem!important}.mr-sm-5,.mx-sm-5{margin-right:3rem!important}.mb-sm-5,.my-sm-5{margin-bottom:3rem!important}.ml-sm-5,.mx-sm-5{margin-left:3rem!important}.p-sm-0{padding:0!important}.pt-sm-0,.py-sm-0{padding-top:0!important}.pr-sm-0,.px-sm-0{padding-right:0!important}.pb-sm-0,.py-sm-0{padding-bottom:0!important}.pl-sm-0,.px-sm-0{padding-left:0!important}.p-sm-1{padding:.25rem!important}.pt-sm-1,.py-sm-1{padding-top:.25rem!important}.pr-sm-1,.px-sm-1{padding-right:.25rem!important}.pb-sm-1,.py-sm-1{padding-bottom:.25rem!important}.pl-sm-1,.px-sm-1{padding-left:.25rem!important}.p-sm-2{padding:.5rem!important}.pt-sm-2,.py-sm-2{padding-top:.5rem!important}.pr-sm-2,.px-sm-2{padding-right:.5rem!important}.pb-sm-2,.py-sm-2{padding-bottom:.5rem!important}.pl-sm-2,.px-sm-2{padding-left:.5rem!important}.p-sm-3{padding:1rem!important}.pt-sm-3,.py-sm-3{padding-top:1rem!important}.pr-sm-3,.px-sm-3{padding-right:1rem!important}.pb-sm-3,.py-sm-3{padding-bottom:1rem!important}.pl-sm-3,.px-sm-3{padding-left:1rem!important}.p-sm-4{padding:1.5rem!important}.pt-sm-4,.py-sm-4{padding-top:1.5rem!important}.pr-sm-4,.px-sm-4{padding-right:1.5rem!important}.pb-sm-4,.py-sm-4{padding-bottom:1.5rem!important}.pl-sm-4,.px-sm-4{padding-left:1.5rem!important}.p-sm-5{padding:3rem!important}.pt-sm-5,.py-sm-5{padding-top:3rem!important}.pr-sm-5,.px-sm-5{padding-right:3rem!important}.pb-sm-5,.py-sm-5{padding-bottom:3rem!important}.pl-sm-5,.px-sm-5{padding-left:3rem!important}.m-sm-auto{margin:auto!important}.mt-sm-auto,.my-sm-auto{margin-top:auto!important}.mr-sm-auto,.mx-sm-auto{margin-right:auto!important}.mb-sm-auto,.my-sm-auto{margin-bottom:auto!important}.ml-sm-auto,.mx-sm-auto{margin-left:auto!important}}@media (min-width:768px){.m-md-0{margin:0!important}.mt-md-0,.my-md-0{margin-top:0!important}.mr-md-0,.mx-md-0{margin-right:0!important}.mb-md-0,.my-md-0{margin-bottom:0!important}.ml-md-0,.mx-md-0{margin-left:0!important}.m-md-1{margin:.25rem!important}.mt-md-1,.my-md-1{margin-top:.25rem!important}.mr-md-1,.mx-md-1{margin-right:.25rem!important}.mb-md-1,.my-md-1{margin-bottom:.25rem!important}.ml-md-1,.mx-md-1{margin-left:.25rem!important}.m-md-2{margin:.5rem!important}.mt-md-2,.my-md-2{margin-top:.5rem!important}.mr-md-2,.mx-md-2{margin-right:.5rem!important}.mb-md-2,.my-md-2{margin-bottom:.5rem!important}.ml-md-2,.mx-md-2{margin-left:.5rem!important}.m-md-3{margin:1rem!important}.mt-md-3,.my-md-3{margin-top:1rem!important}.mr-md-3,.mx-md-3{margin-right:1rem!important}.mb-md-3,.my-md-3{margin-bottom:1rem!important}.ml-md-3,.mx-md-3{margin-left:1rem!important}.m-md-4{margin:1.5rem!important}.mt-md-4,.my-md-4{margin-top:1.5rem!important}.mr-md-4,.mx-md-4{margin-right:1.5rem!important}.mb-md-4,.my-md-4{margin-bottom:1.5rem!important}.ml-md-4,.mx-md-4{margin-left:1.5rem!important}.m-md-5{margin:3rem!important}.mt-md-5,.my-md-5{margin-top:3rem!important}.mr-md-5,.mx-md-5{margin-right:3rem!important}.mb-md-5,.my-md-5{margin-bottom:3rem!important}.ml-md-5,.mx-md-5{margin-left:3rem!important}.p-md-0{padding:0!important}.pt-md-0,.py-md-0{padding-top:0!important}.pr-md-0,.px-md-0{padding-right:0!important}.pb-md-0,.py-md-0{padding-bottom:0!important}.pl-md-0,.px-md-0{padding-left:0!important}.p-md-1{padding:.25rem!important}.pt-md-1,.py-md-1{padding-top:.25rem!important}.pr-md-1,.px-md-1{padding-right:.25rem!important}.pb-md-1,.py-md-1{padding-bottom:.25rem!important}.pl-md-1,.px-md-1{padding-left:.25rem!important}.p-md-2{padding:.5rem!important}.pt-md-2,.py-md-2{padding-top:.5rem!important}.pr-md-2,.px-md-2{padding-right:.5rem!important}.pb-md-2,.py-md-2{padding-bottom:.5rem!important}.pl-md-2,.px-md-2{padding-left:.5rem!important}.p-md-3{padding:1rem!important}.pt-md-3,.py-md-3{padding-top:1rem!important}.pr-md-3,.px-md-3{padding-right:1rem!important}.pb-md-3,.py-md-3{padding-bottom:1rem!important}.pl-md-3,.px-md-3{padding-left:1rem!important}.p-md-4{padding:1.5rem!important}.pt-md-4,.py-md-4{padding-top:1.5rem!important}.pr-md-4,.px-md-4{padding-right:1.5rem!important}.pb-md-4,.py-md-4{padding-bottom:1.5rem!important}.pl-md-4,.px-md-4{padding-left:1.5rem!important}.p-md-5{padding:3rem!important}.pt-md-5,.py-md-5{padding-top:3rem!important}.pr-md-5,.px-md-5{padding-right:3rem!important}.pb-md-5,.py-md-5{padding-bottom:3rem!important}.pl-md-5,.px-md-5{padding-left:3rem!important}.m-md-auto{margin:auto!important}.mt-md-auto,.my-md-auto{margin-top:auto!important}.mr-md-auto,.mx-md-auto{margin-right:auto!important}.mb-md-auto,.my-md-auto{margin-bottom:auto!important}.ml-md-auto,.mx-md-auto{margin-left:auto!important}}@media (min-width:992px){.m-lg-0{margin:0!important}.mt-lg-0,.my-lg-0{margin-top:0!important}.mr-lg-0,.mx-lg-0{margin-right:0!important}.mb-lg-0,.my-lg-0{margin-bottom:0!important}.ml-lg-0,.mx-lg-0{margin-left:0!important}.m-lg-1{margin:.25rem!important}.mt-lg-1,.my-lg-1{margin-top:.25rem!important}.mr-lg-1,.mx-lg-1{margin-right:.25rem!important}.mb-lg-1,.my-lg-1{margin-bottom:.25rem!important}.ml-lg-1,.mx-lg-1{margin-left:.25rem!important}.m-lg-2{margin:.5rem!important}.mt-lg-2,.my-lg-2{margin-top:.5rem!important}.mr-lg-2,.mx-lg-2{margin-right:.5rem!important}.mb-lg-2,.my-lg-2{margin-bottom:.5rem!important}.ml-lg-2,.mx-lg-2{margin-left:.5rem!important}.m-lg-3{margin:1rem!important}.mt-lg-3,.my-lg-3{margin-top:1rem!important}.mr-lg-3,.mx-lg-3{margin-right:1rem!important}.mb-lg-3,.my-lg-3{margin-bottom:1rem!important}.ml-lg-3,.mx-lg-3{margin-left:1rem!important}.m-lg-4{margin:1.5rem!important}.mt-lg-4,.my-lg-4{margin-top:1.5rem!important}.mr-lg-4,.mx-lg-4{margin-right:1.5rem!important}.mb-lg-4,.my-lg-4{margin-bottom:1.5rem!important}.ml-lg-4,.mx-lg-4{margin-left:1.5rem!important}.m-lg-5{margin:3rem!important}.mt-lg-5,.my-lg-5{margin-top:3rem!important}.mr-lg-5,.mx-lg-5{margin-right:3rem!important}.mb-lg-5,.my-lg-5{margin-bottom:3rem!important}.ml-lg-5,.mx-lg-5{margin-left:3rem!important}.p-lg-0{padding:0!important}.pt-lg-0,.py-lg-0{padding-top:0!important}.pr-lg-0,.px-lg-0{padding-right:0!important}.pb-lg-0,.py-lg-0{padding-bottom:0!important}.pl-lg-0,.px-lg-0{padding-left:0!important}.p-lg-1{padding:.25rem!important}.pt-lg-1,.py-lg-1{padding-top:.25rem!important}.pr-lg-1,.px-lg-1{padding-right:.25rem!important}.pb-lg-1,.py-lg-1{padding-bottom:.25rem!important}.pl-lg-1,.px-lg-1{padding-left:.25rem!important}.p-lg-2{padding:.5rem!important}.pt-lg-2,.py-lg-2{padding-top:.5rem!important}.pr-lg-2,.px-lg-2{padding-right:.5rem!important}.pb-lg-2,.py-lg-2{padding-bottom:.5rem!important}.pl-lg-2,.px-lg-2{padding-left:.5rem!important}.p-lg-3{padding:1rem!important}.pt-lg-3,.py-lg-3{padding-top:1rem!important}.pr-lg-3,.px-lg-3{padding-right:1rem!important}.pb-lg-3,.py-lg-3{padding-bottom:1rem!important}.pl-lg-3,.px-lg-3{padding-left:1rem!important}.p-lg-4{padding:1.5rem!important}.pt-lg-4,.py-lg-4{padding-top:1.5rem!important}.pr-lg-4,.px-lg-4{padding-right:1.5rem!important}.pb-lg-4,.py-lg-4{padding-bottom:1.5rem!important}.pl-lg-4,.px-lg-4{padding-left:1.5rem!important}.p-lg-5{padding:3rem!important}.pt-lg-5,.py-lg-5{padding-top:3rem!important}.pr-lg-5,.px-lg-5{padding-right:3rem!important}.pb-lg-5,.py-lg-5{padding-bottom:3rem!important}.pl-lg-5,.px-lg-5{padding-left:3rem!important}.m-lg-auto{margin:auto!important}.mt-lg-auto,.my-lg-auto{margin-top:auto!important}.mr-lg-auto,.mx-lg-auto{margin-right:auto!important}.mb-lg-auto,.my-lg-auto{margin-bottom:auto!important}.ml-lg-auto,.mx-lg-auto{margin-left:auto!important}}@media (min-width:1200px){.m-xl-0{margin:0!important}.mt-xl-0,.my-xl-0{margin-top:0!important}.mr-xl-0,.mx-xl-0{margin-right:0!important}.mb-xl-0,.my-xl-0{margin-bottom:0!important}.ml-xl-0,.mx-xl-0{margin-left:0!important}.m-xl-1{margin:.25rem!important}.mt-xl-1,.my-xl-1{margin-top:.25rem!important}.mr-xl-1,.mx-xl-1{margin-right:.25rem!important}.mb-xl-1,.my-xl-1{margin-bottom:.25rem!important}.ml-xl-1,.mx-xl-1{margin-left:.25rem!important}.m-xl-2{margin:.5rem!important}.mt-xl-2,.my-xl-2{margin-top:.5rem!important}.mr-xl-2,.mx-xl-2{margin-right:.5rem!important}.mb-xl-2,.my-xl-2{margin-bottom:.5rem!important}.ml-xl-2,.mx-xl-2{margin-left:.5rem!important}.m-xl-3{margin:1rem!important}.mt-xl-3,.my-xl-3{margin-top:1rem!important}.mr-xl-3,.mx-xl-3{margin-right:1rem!important}.mb-xl-3,.my-xl-3{margin-bottom:1rem!important}.ml-xl-3,.mx-xl-3{margin-left:1rem!important}.m-xl-4{margin:1.5rem!important}.mt-xl-4,.my-xl-4{margin-top:1.5rem!important}.mr-xl-4,.mx-xl-4{margin-right:1.5rem!important}.mb-xl-4,.my-xl-4{margin-bottom:1.5rem!important}.ml-xl-4,.mx-xl-4{margin-left:1.5rem!important}.m-xl-5{margin:3rem!important}.mt-xl-5,.my-xl-5{margin-top:3rem!important}.mr-xl-5,.mx-xl-5{margin-right:3rem!important}.mb-xl-5,.my-xl-5{margin-bottom:3rem!important}.ml-xl-5,.mx-xl-5{margin-left:3rem!important}.p-xl-0{padding:0!important}.pt-xl-0,.py-xl-0{padding-top:0!important}.pr-xl-0,.px-xl-0{padding-right:0!important}.pb-xl-0,.py-xl-0{padding-bottom:0!important}.pl-xl-0,.px-xl-0{padding-left:0!important}.p-xl-1{padding:.25rem!important}.pt-xl-1,.py-xl-1{padding-top:.25rem!important}.pr-xl-1,.px-xl-1{padding-right:.25rem!important}.pb-xl-1,.py-xl-1{padding-bottom:.25rem!important}.pl-xl-1,.px-xl-1{padding-left:.25rem!important}.p-xl-2{padding:.5rem!important}.pt-xl-2,.py-xl-2{padding-top:.5rem!important}.pr-xl-2,.px-xl-2{padding-right:.5rem!important}.pb-xl-2,.py-xl-2{padding-bottom:.5rem!important}.pl-xl-2,.px-xl-2{padding-left:.5rem!important}.p-xl-3{padding:1rem!important}.pt-xl-3,.py-xl-3{padding-top:1rem!important}.pr-xl-3,.px-xl-3{padding-right:1rem!important}.pb-xl-3,.py-xl-3{padding-bottom:1rem!important}.pl-xl-3,.px-xl-3{padding-left:1rem!important}.p-xl-4{padding:1.5rem!important}.pt-xl-4,.py-xl-4{padding-top:1.5rem!important}.pr-xl-4,.px-xl-4{padding-right:1.5rem!important}.pb-xl-4,.py-xl-4{padding-bottom:1.5rem!important}.pl-xl-4,.px-xl-4{padding-left:1.5rem!important}.p-xl-5{padding:3rem!important}.pt-xl-5,.py-xl-5{padding-top:3rem!important}.pr-xl-5,.px-xl-5{padding-right:3rem!important}.pb-xl-5,.py-xl-5{padding-bottom:3rem!important}.pl-xl-5,.px-xl-5{padding-left:3rem!important}.m-xl-auto{margin:auto!important}.mt-xl-auto,.my-xl-auto{margin-top:auto!important}.mr-xl-auto,.mx-xl-auto{margin-right:auto!important}.mb-xl-auto,.my-xl-auto{margin-bottom:auto!important}.ml-xl-auto,.mx-xl-auto{margin-left:auto!important}}.text-justify{text-align:justify!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left!important}.text-right{text-align:right!important}.text-center{text-align:center!important}@media (min-width:576px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-light{font-weight:300!important}.font-weight-normal{font-weight:400!important}.font-weight-bold{font-weight:700!important}.font-italic{font-style:italic!important}.text-white{color:#fff!important}.text-primary{color:#007bff!important}a.text-primary:focus,a.text-primary:hover{color:#0062cc!important}.text-secondary{color:#6c757d!important}a.text-secondary:focus,a.text-secondary:hover{color:#545b62!important}.text-success{color:#28a745!important}a.text-success:focus,a.text-success:hover{color:#1e7e34!important}.text-info{color:#17a2b8!important}a.text-info:focus,a.text-info:hover{color:#117a8b!important}.text-warning{color:#ffc107!important}a.text-warning:focus,a.text-warning:hover{color:#d39e00!important}.text-danger{color:#dc3545!important}a.text-danger:focus,a.text-danger:hover{color:#bd2130!important}.text-light{color:#f8f9fa!important}a.text-light:focus,a.text-light:hover{color:#dae0e5!important}.text-dark{color:#343a40!important}a.text-dark:focus,a.text-dark:hover{color:#1d2124!important}.text-muted{color:#6c757d!important}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media print{*,::after,::before{text-shadow:none!important;box-shadow:none!important}a:not(.btn){text-decoration:underline}abbr[title]::after{content:" (" attr(title) ")"}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}@page{size:a3}body{min-width:992px!important}.container{min-width:992px!important}.navbar{display:none}.badge{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}} +/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/layout/bootstrap.min.js b/bellatrix.web.tests/src/main/resources/testpages/layout/bootstrap.min.js new file mode 100644 index 00000000..534d5334 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/layout/bootstrap.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v4.0.0 (https://getbootstrap.com) + * Copyright 2011-2018 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ +!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})}); +//# sourceMappingURL=bootstrap.min.js.map \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/layout/favicon.ico b/bellatrix.web.tests/src/main/resources/testpages/layout/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..b48b3442ad90fd9b5bcbef8a9f703c1852de1561 GIT binary patch literal 5430 zcmchb`BM}}6vrn=RerU~e}JE;{1#6HHI^o#f*c}>As#Wtm_$)Ph+G1TXayBe6BCaj zBvFZYti~%*t5QJ(qGiBR5RfGTyDo=F)D_J}U0&Yn+3uO1JtUi$srpv;&d&7rGu>}y z-Wx@ENqJcb3R18QQYuF%O0c3RBe134AHS+74cLDj_u(PRR21!J8}2u50HBb1J8i-H z^GnJy-(Fx}HF~CN<)|6J^~tDkV0r`F0EJ_@GTutC@5?VP>+P@wb6;w&{Zbd38W!W= ze*Rj)LQDa&q=ZI0uKrvT%db0iVypwN8I1DBq5m%sCSss@IAAI*OG0mw(cjx|y|2Ii zaF}QV#&}i&4y?7>yht*>uTqszL3?#w9`!A4Z<>(o%HDl46i*XPO*DN?& zb`b9M^*>*|{m|8FfeVLE!M5e;>^k)8=WDIjjEw|M5!hG7nJyeUiDCNBwxOXRXuNnC zGN#S<8B?4mdE9JB9v2D8$U)Lr)P8jU{+za>sTGn#qWs2o3iBrhy)+)9{~fCxj&9xU z)-G&!!HFGTLyh?iIR3cLtwmc=xLu7YA90j2J_=IC&sK#D#G_}bK6FZqMIB51b;BHK zYnC^A2{PQ1j&H2K>^HVk(O)l>M`QBlFV@Vbk$#>yQ|#@a7WaH<^Ca#$WJ(K(L4T6Q!TZE>@$hMBJPY}= zHPhyZui3gO@i5TcD;-a9;XSrhp0o)uAW873Oh$iOYddUTmabD8?EEMb4i@eJEB>e7 zT+g1t*2Qal#x`-KPly$gINV${hU?dl@2~H2x!_poUca$TYxZgA9H#V8SHqH^P+ore`&~wWw7>02EzsdYeFz}e>EoaI=f0E$P z_mRh&zn)LOX2**62!HCd)YW^$w()+;m^c@N!m!VzF?sqod7UR>I=cBQ$^VYcF3pv< z_|8Osy#xz!AxrJiAEhzd8_?e{N3?E*(aXTzc1t>z)`Q29w>2Z4tV!|cZ?+Yr}0hH@s)ccGAh%fLfy1}1r~v~}ZarnOoeQH&d78-Kfs z=B(%;e{TwmN#l85Y;THLZa=;>VAT__liOn98CMPQolSFYlORrV7lW##0>eLEH9wJJq<#YCS8{-=$+ zs?f6&z3DpzeU=D9iSHEn4a2zMGiBu7wFTzY<073@yA0=hMAFy@=N>$Votw77Eb1}c zw+&tg`5TkQNC}B@vf9*L8;h~rb-R8X-sd$qaj?2hmxH%mxdwj@K9ckh-z`+P6}`KP z)opwnYFU1*tI;~KwxW%4pBuGTptVZ_u;qTt=VdsCFRV4C$s;9-fAMBM=kVy!~kovz!EF=d`RZ&qtT_5G>kr(HMHW9fZ7(A|gi`CXu#m#%$FVv>}5QhmUm z_dLh5y3en~yq)I;2Xc#<|L>S%sCkmRCc!#{J-c=J5kLP>;pZYB+LyhVoj-X0ff$ot zcb1f6%mse_gZ=^N>#)Iqy%(rnppEi2DPO=mTz*H#!&S^Jy4yP?*_tgZU)m74RL&_w z;~;NpqEme~xt~cM?=~b;aDKnO#LS+}hG(*IOzqw1eh=YwAIRQneste4 nvNEsKToAs>>0;if("function"!=typeof e)throw TypeError();var r,i=arguments[1];for(r=0;r>16&255)),i.push(String.fromCharCode(o>>8&255)),i.push(String.fromCharCode(255&o)),a=0,o=0),r+=1;return 12===a?(o>>=4,i.push(String.fromCharCode(255&o))):18===a&&(o>>=2,i.push(String.fromCharCode(o>>8&255)),i.push(String.fromCharCode(255&o))),i.join("")},e.btoa=e.btoa||function(e){e=String(e);var n,r,i,o,a,s,l,h=0,u=[];if(/[^\x00-\xFF]/.test(e))throw Error("InvalidCharacterError");for(;h>2,a=(3&n)<<4|r>>4,s=(15&r)<<2|i>>6,l=63&i,h===e.length+2?(s=64,l=64):h===e.length+1&&(l=64),u.push(t.charAt(o),t.charAt(a),t.charAt(s),t.charAt(l));return u.join("")}}(e),Object.prototype.hasOwnProperty||(Object.prototype.hasOwnProperty=function(e){var t=this.__proto__||this.constructor.prototype;return e in this&&(!(e in t)||t[e]!==this[e])}),function(){if("performance"in e==!1&&(e.performance={}),Date.now=Date.now||function(){return(new Date).getTime()},"now"in e.performance==!1){var t=Date.now();performance.timing&&performance.timing.navigationStart&&(t=performance.timing.navigationStart),e.performance.now=function(){return Date.now()-t}}}(),e.requestAnimationFrame||(e.webkitRequestAnimationFrame&&e.webkitCancelAnimationFrame?!function(e){e.requestAnimationFrame=function(t){return webkitRequestAnimationFrame(function(){t(e.performance.now())})},e.cancelAnimationFrame=e.webkitCancelAnimationFrame}(e):e.mozRequestAnimationFrame&&e.mozCancelAnimationFrame?!function(e){e.requestAnimationFrame=function(t){return mozRequestAnimationFrame(function(){t(e.performance.now())})},e.cancelAnimationFrame=e.mozCancelAnimationFrame}(e):!function(e){e.requestAnimationFrame=function(t){return e.setTimeout(t,1e3/60)},e.cancelAnimationFrame=e.clearTimeout}(e))}}(this),function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Holder=t():e.Holder=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var i=n[r]={exports:{},id:r,loaded:!1};return e[r].call(i.exports,i,i.exports,t),i.loaded=!0,i.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){e.exports=n(1)},function(e,t,n){(function(t){function r(e,t,n,r){var a=i(n.substr(n.lastIndexOf(e.domain)),e);a&&o({mode:null,el:r,flags:a,engineSettings:t})}function i(e,t){var n={theme:k(O.settings.themes.gray,null),stylesheets:t.stylesheets,instanceOptions:t},r=e.indexOf("?"),i=[e];r!==-1&&(i=[e.slice(0,r),e.slice(r+1)]);var o=i[0].split("/");n.holderURL=e;var a=o[1],s=a.match(/([\d]+p?)x([\d]+p?)/);if(!s)return!1;if(n.fluid=a.indexOf("p")!==-1,n.dimensions={width:s[1].replace("p","%"),height:s[2].replace("p","%")},2===i.length){var l=v.parse(i[1]);if(w.truthy(l.ratio)){n.fluid=!0;var h=parseFloat(n.dimensions.width.replace("%","")),u=parseFloat(n.dimensions.height.replace("%",""));u=Math.floor(100*(u/h)),h=100,n.dimensions.width=h+"%",n.dimensions.height=u+"%"}if(n.auto=w.truthy(l.auto),l.bg&&(n.theme.bg=w.parseColor(l.bg)),l.fg&&(n.theme.fg=w.parseColor(l.fg)),l.bg&&!l.fg&&(n.autoFg=!0),l.theme&&n.instanceOptions.themes.hasOwnProperty(l.theme)&&(n.theme=k(n.instanceOptions.themes[l.theme],null)),l.text&&(n.text=l.text),l.textmode&&(n.textmode=l.textmode),l.size&&(n.size=l.size),l.font&&(n.font=l.font),l.align&&(n.align=l.align),l.lineWrap&&(n.lineWrap=l.lineWrap),n.nowrap=w.truthy(l.nowrap),n.outline=w.truthy(l.outline),w.truthy(l.random)){O.vars.cache.themeKeys=O.vars.cache.themeKeys||Object.keys(n.instanceOptions.themes);var c=O.vars.cache.themeKeys[0|Math.random()*O.vars.cache.themeKeys.length];n.theme=k(n.instanceOptions.themes[c],null)}}return n}function o(e){var t=e.mode,n=e.el,r=e.flags,i=e.engineSettings,o=r.dimensions,s=r.theme,l=o.width+"x"+o.height;t=null==t?r.fluid?"fluid":"image":t;var c=/holder_([a-z]+)/g,d=!1;if(null!=r.text&&(s.text=r.text,"object"===n.nodeName.toLowerCase())){for(var f=s.text.split("\\n"),p=0;p1){var b,x=0,A=0,C=0;w=new s.Group("line"+C),"left"!==e.align&&"right"!==e.align||(o=e.width*(1-2*(1-r)));for(var E=0;E=o||T===!0)&&(t(g,w,x,g.properties.leading),g.add(w),x=0,A+=g.properties.leading,C+=1,w=new s.Group("line"+C),w.y=A),T!==!0&&(v.moveTo(x,0),x+=m.spaceWidth+k.width,w.add(v))}if(t(g,w,x,g.properties.leading),g.add(w),"left"===e.align)g.moveTo(e.width-i,null,null);else if("right"===e.align){for(b in g.children)w=g.children[b],w.moveTo(e.width-w.width,null,null);g.moveTo(0-(e.width-i),null,null)}else{for(b in g.children)w=g.children[b],w.moveTo((g.width-w.width)/2,null,null);g.moveTo((e.width-g.width)/2,null,null)}g.moveTo(null,(e.height-g.height)/2,null),(e.height-g.height)/2<0&&g.moveTo(null,0,null)}else v=new s.Text(e.text),w=new s.Group("line0"),w.add(v),g.add(w),"left"===e.align?g.moveTo(e.width-i,null,null):"right"===e.align?g.moveTo(0-(e.width-i),null,null):g.moveTo((e.width-m.boundingBox.width)/2,null,null),g.moveTo(null,(e.height-m.boundingBox.height)/2,null);return a}function l(e,t,n,r){var i=parseInt(e,10),o=parseInt(t,10),a=Math.max(i,o),s=Math.min(i,o),l=.8*Math.min(s,a*r);return Math.round(Math.max(n,l))}function h(e){var t;t=null==e||null==e.nodeType?O.vars.resizableImages:[e];for(var n=0,r=t.length;n1){n.nodeValue="";for(var v=0;v=0?t:1)}function o(e){x?i(e):S.push(e)}null==document.readyState&&document.addEventListener&&(document.addEventListener("DOMContentLoaded",function C(){document.removeEventListener("DOMContentLoaded",C,!1),document.readyState="complete"},!1),document.readyState="loading");var a=e.document,s=a.documentElement,l="load",h=!1,u="on"+l,c="complete",d="readyState",f="attachEvent",p="detachEvent",g="addEventListener",m="DOMContentLoaded",v="onreadystatechange",y="removeEventListener",w=g in a,b=h,x=h,S=[];if(a[d]===c)i(t);else if(w)a[g](m,n,h),e[g](l,n,h);else{a[f](v,n),e[f](u,n);try{b=null==e.frameElement&&s}catch(A){}b&&b.doScroll&&!function E(){if(!x){try{b.doScroll("left")}catch(e){return i(E,50)}r(),t()}}()}return o.version="1.4.0",o.isReady=function(){return x},o}e.exports="undefined"!=typeof window&&n(window)},function(e,t,n){var r=encodeURIComponent,i=decodeURIComponent,o=n(4),a=n(5),s=/(\w+)\[(\d+)\]/,l=/\w+\.\w+/;t.parse=function(e){if("string"!=typeof e)return{};if(e=o(e),""===e)return{};"?"===e.charAt(0)&&(e=e.slice(1));for(var t={},n=e.split("&"),r=0;r=0;r--)n=e.charCodeAt(r),n>128?t.unshift(["&#",n,";"].join("")):t.unshift(e[r]);return t.join("")},t.imageExists=function(e,t){var n=new Image;n.onerror=function(){t.call(this,!1)},n.onload=function(){t.call(this,!0)},n.src=e},t.decodeHtmlEntity=function(e){return e.replace(/&#(\d+);/g,function(e,t){return String.fromCharCode(t)})},t.dimensionCheck=function(e){var t={height:e.clientHeight,width:e.clientWidth};return!(!t.height||!t.width)&&t},t.truthy=function(e){return"string"==typeof e?"true"===e||"yes"===e||"1"===e||"on"===e||"✓"===e:!!e},t.parseColor=function(e){var t,n=/(^(?:#?)[0-9a-f]{6}$)|(^(?:#?)[0-9a-f]{3}$)/i,r=/^rgb\((\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/,i=/^rgba\((\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(0\.\d{1,}|1)\)$/,o=e.match(n);return null!==o?(t=o[1]||o[2],"#"!==t[0]?"#"+t:t):(o=e.match(r),null!==o?t="rgb("+o.slice(1).join(",")+")":(o=e.match(i),null!==o?t="rgba("+o.slice(1).join(",")+")":null))},t.canvasRatio=function(){var t=1,n=1;if(e.document){var r=e.document.createElement("canvas");if(r.getContext){var i=r.getContext("2d");t=e.devicePixelRatio||1,n=i.webkitBackingStorePixelRatio||i.mozBackingStorePixelRatio||i.msBackingStorePixelRatio||i.oBackingStorePixelRatio||i.backingStorePixelRatio||1}}return t/n}}).call(t,function(){return this}())},function(e,t,n){(function(e){var r=n(9),i="http://www.w3.org/2000/svg",o=8;t.initSVG=function(e,t,n){var a,s,l=!1;e&&e.querySelector?(s=e.querySelector("style"),null===s&&(l=!0)):(e=r.newEl("svg",i),l=!0),l&&(a=r.newEl("defs",i),s=r.newEl("style",i),r.setAttr(s,{type:"text/css"}),a.appendChild(s),e.appendChild(a)),e.webkitMatchesSelector&&e.setAttribute("xmlns",i);for(var h=0;h=0;l--){var h=s.createProcessingInstruction("xml-stylesheet",'href="'+a[l]+'" rel="stylesheet"');s.insertBefore(h,s.firstChild)}s.removeChild(s.documentElement),o=i.serializeToString(s)}var u=i.serializeToString(t);return u=u.replace(/\&(\#[0-9]{2,}\;)/g,"&$1"),o+u}}}).call(t,function(){return this}())},function(e,t){(function(e){t.newEl=function(t,n){if(e.document)return null==n?e.document.createElement(t):e.document.createElementNS(n,t)},t.setAttr=function(e,t){for(var n in t)e.setAttribute(n,t[n])},t.createXML=function(){if(e.DOMParser)return(new DOMParser).parseFromString("","application/xml")},t.getNodeArray=function(t){var n=null;return"string"==typeof t?n=document.querySelectorAll(t):e.NodeList&&t instanceof e.NodeList?n=t:e.Node&&t instanceof e.Node?n=[t]:e.HTMLCollection&&t instanceof e.HTMLCollection?n=t:t instanceof Array?n=t:null===t&&(n=[]),n=Array.prototype.slice.call(n)}}).call(t,function(){return this}())},function(e,t){var n=function(e,t){"string"==typeof e&&(this.original=e,"#"===e.charAt(0)&&(e=e.slice(1)),/[^a-f0-9]+/i.test(e)||(3===e.length&&(e=e.replace(/./g,"$&$&")),6===e.length&&(this.alpha=1,t&&t.alpha&&(this.alpha=t.alpha),this.set(parseInt(e,16)))))};n.rgb2hex=function(e,t,n){function r(e){var t=(0|e).toString(16);return e<16&&(t="0"+t),t}return[e,t,n].map(r).join("")},n.hsl2rgb=function(e,t,n){var r=e/60,i=(1-Math.abs(2*n-1))*t,o=i*(1-Math.abs(parseInt(r)%2-1)),a=n-i/2,s=0,l=0,h=0;return r>=0&&r<1?(s=i,l=o):r>=1&&r<2?(s=o,l=i):r>=2&&r<3?(l=i,h=o):r>=3&&r<4?(l=o,h=i):r>=4&&r<5?(s=o,h=i):r>=5&&r<6&&(s=i,h=o),s+=a,l+=a,h+=a,s=parseInt(255*s),l=parseInt(255*l),h=parseInt(255*h),[s,l,h]},n.prototype.set=function(e){this.raw=e;var t=(16711680&this.raw)>>16,n=(65280&this.raw)>>8,r=255&this.raw,i=.2126*t+.7152*n+.0722*r,o=-.09991*t-.33609*n+.436*r,a=.615*t-.55861*n-.05639*r;return this.rgb={r:t,g:n,b:r},this.yuv={y:i,u:o,v:a},this},n.prototype.lighten=function(e){var t=Math.min(1,Math.max(0,Math.abs(e)))*(e<0?-1:1),r=255*t|0,i=Math.min(255,Math.max(0,this.rgb.r+r)),o=Math.min(255,Math.max(0,this.rgb.g+r)),a=Math.min(255,Math.max(0,this.rgb.b+r)),s=n.rgb2hex(i,o,a);return new n(s)},n.prototype.toHex=function(e){return(e?"#":"")+this.raw.toString(16)},n.prototype.lighterThan=function(e){return e instanceof n||(e=new n(e)),this.yuv.y>e.yuv.y},n.prototype.blendAlpha=function(e){e instanceof n||(e=new n(e));var t=e,r=this,i=t.alpha*t.rgb.r+(1-t.alpha)*r.rgb.r,o=t.alpha*t.rgb.g+(1-t.alpha)*r.rgb.g,a=t.alpha*t.rgb.b+(1-t.alpha)*r.rgb.b;return new n(n.rgb2hex(i,o,a))},e.exports=n},function(e,t){e.exports={version:"2.9.4",svg_ns:"http://www.w3.org/2000/svg"}},function(e,t,n){function r(e,t){return c.element({tag:t,width:e.width,height:e.height,fill:e.properties.fill})}function i(e){return h.cssProps({fill:e.fill,"font-weight":e.font.weight,"font-family":e.font.family+", monospace","font-size":e.font.size+e.font.units})}function o(e,t,n){var r=n/2;return["M",r,r,"H",e-r,"V",t-r,"H",r,"V",0,"M",0,r,"L",e,t-r,"M",0,t-r,"L",e,r].join(" ")}var a=n(13),s=n(8),l=n(11),h=n(7),u=l.svg_ns,c={element:function(e){var t=e.tag,n=e.content||"";return delete e.tag,delete e.content,[t,n,e]}};e.exports=function(e,t){var n=t.engineSettings,l=n.stylesheets,h=l.map(function(e){return''}).join("\n"),d="holder_"+Number(new Date).toString(16),f=e.root,p=f.children.holderTextGroup,g="#"+d+" text { "+i(p.properties)+" } ";p.y+=.8*p.textPositionData.boundingBox.height;var m=[];Object.keys(p.children).forEach(function(e){var t=p.children[e];Object.keys(t.children).forEach(function(e){var n=t.children[e],r=p.x+t.x+n.x,i=p.y+t.y+n.y,o=c.element({tag:"text",content:n.properties.text,x:r,y:i});m.push(o)})});var v=c.element({tag:"g",content:m}),y=null;if(f.children.holderBg.properties.outline){var w=f.children.holderBg.properties.outline;y=c.element({tag:"path",d:o(f.children.holderBg.width,f.children.holderBg.height,w.width),"stroke-width":w.width,stroke:w.fill,fill:"none"})}var b=r(f.children.holderBg,"rect"),x=[];x.push(b),w&&x.push(y),x.push(v);var S=c.element({tag:"g",id:d,content:x}),A=c.element({tag:"style",content:g,type:"text/css"}),C=c.element({tag:"defs",content:A}),E=c.element({tag:"svg",content:[C,S],width:f.properties.width,height:f.properties.height,xmlns:u,viewBox:[0,0,f.properties.width,f.properties.height].join(" "),preserveAspectRatio:"none"}),k=a(E);k=h+k[0];var T=s.svgStringToDataURI(k,"background"===t.mode);return T}},function(e,t,n){n(14);e.exports=function r(e,t,n){"use strict";function i(e){var t=e.match(/^[\w-]+/),r={tag:t?t[0]:"div",attr:{},children:[]},i=e.match(/#([\w-]+)/),o=e.match(/\$([\w-]+)/),a=e.match(/\.[\w-]+/g);return i&&(r.attr.id=i[1],n[i[1]]=r),o&&(n[o[1]]=r),a&&(r.attr["class"]=a.join(" ").replace(/\./g,"")),e.match(/&$/g)&&(f=!1),r}function o(e,t){if(null!==t&&t!==!1&&void 0!==t)return"string"!=typeof t&&"object"!=typeof t?String(t):t}function a(e){return e||0===e?String(e).replace(/&/g,"&").replace(/"/g,"""):""}function s(e){return String(e).replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(//g,">")}var l,h,u,c,d=1,f=!0;if(n=n||{},"string"==typeof e[0])e[0]=i(e[0]);else{if(!Array.isArray(e[0]))throw new Error("First element of array must be a string, or an array and not "+JSON.stringify(e[0]));d=0}for(;d",e[0]=l}return n[0]=e[0],u&&u(e[0]),n}},function(e,t){"use strict";function n(e){var t=""+e,n=r.exec(t);if(!n)return t;var i,o="",a=0,s=0;for(a=n.index;a]/;e.exports=n},function(e,t,n){var r=n(9),i=n(7);e.exports=function(){var e=r.newEl("canvas"),t=null;return function(n){null==t&&(t=e.getContext("2d"));var r=i.canvasRatio(),o=n.root;e.width=r*o.properties.width,e.height=r*o.properties.height,t.textBaseline="middle";var a=o.children.holderBg,s=r*a.width,l=r*a.height,h=2,u=h/2;t.fillStyle=a.properties.fill,t.fillRect(0,0,s,l),a.properties.outline&&(t.strokeStyle=a.properties.outline.fill,t.lineWidth=a.properties.outline.width,t.moveTo(u,u),t.lineTo(s-u,u),t.lineTo(s-u,l-u),t.lineTo(u,l-u),t.lineTo(u,u),t.moveTo(0,u),t.lineTo(s,l-u),t.moveTo(0,l-u),t.lineTo(s,u),t.stroke());var c=o.children.holderTextGroup;t.font=c.properties.font.weight+" "+r*c.properties.font.size+c.properties.font.units+" "+c.properties.font.family+", monospace",t.fillStyle=c.properties.fill;for(var d in c.children){var f=c.children[d];for(var p in f.children){var g=f.children[p],m=r*(c.x+f.x+g.x),v=r*(c.y+f.y+g.y+c.properties.leading/2);t.fillText(g.properties.text,m,v)}}return e.toDataURL("image/png")}}()}])}),function(e,t){t&&(Holder=e.Holder); +}(this,"undefined"!=typeof Meteor&&"undefined"!=typeof Package); \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/layout/jquery-3.2.1.slim.min.js b/bellatrix.web.tests/src/main/resources/testpages/layout/jquery-3.2.1.slim.min.js new file mode 100644 index 00000000..196710ef --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/layout/jquery-3.2.1.slim.min.js @@ -0,0 +1,4 @@ +/*! jQuery v3.2.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/parseXML,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-event/ajax,-effects,-effects/Tween,-effects/animatedSelector | (c) JS Foundation and other contributors | jquery.org/license */ +!function(a,b){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){"use strict";var c=[],d=a.document,e=Object.getPrototypeOf,f=c.slice,g=c.concat,h=c.push,i=c.indexOf,j={},k=j.toString,l=j.hasOwnProperty,m=l.toString,n=m.call(Object),o={};function p(a,b){b=b||d;var c=b.createElement("script");c.text=a,b.head.appendChild(c).parentNode.removeChild(c)}var q="3.2.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/parseXML,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-event/ajax,-effects,-effects/Tween,-effects/animatedSelector",r=function(a,b){return new r.fn.init(a,b)},s=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,t=/^-ms-/,u=/-([a-z])/g,v=function(a,b){return b.toUpperCase()};r.fn=r.prototype={jquery:q,constructor:r,length:0,toArray:function(){return f.call(this)},get:function(a){return null==a?f.call(this):a<0?this[a+this.length]:this[a]},pushStack:function(a){var b=r.merge(this.constructor(),a);return b.prevObject=this,b},each:function(a){return r.each(this,a)},map:function(a){return this.pushStack(r.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(f.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(a<0?b:0);return this.pushStack(c>=0&&c0&&b-1 in a)}var x=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=function(a,b){for(var c=0,d=a.length;c+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(N),U=new RegExp("^"+L+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+N),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),aa=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:d<0?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ba=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ca=function(a,b){return b?"\0"===a?"\ufffd":a.slice(0,-1)+"\\"+a.charCodeAt(a.length-1).toString(16)+" ":"\\"+a},da=function(){m()},ea=ta(function(a){return a.disabled===!0&&("form"in a||"label"in a)},{dir:"parentNode",next:"legend"});try{G.apply(D=H.call(v.childNodes),v.childNodes),D[v.childNodes.length].nodeType}catch(fa){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s=b&&b.ownerDocument,w=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==w&&9!==w&&11!==w)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==w&&(l=Z.exec(a)))if(f=l[1]){if(9===w){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(s&&(j=s.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(l[2])return G.apply(d,b.getElementsByTagName(a)),d;if((f=l[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==w)s=b,r=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(ba,ca):b.setAttribute("id",k=u),o=g(a),h=o.length;while(h--)o[h]="#"+k+" "+sa(o[h]);r=o.join(","),s=$.test(a)&&qa(b.parentNode)||b}if(r)try{return G.apply(d,s.querySelectorAll(r)),d}catch(x){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(P,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("fieldset");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&a.sourceIndex-b.sourceIndex;if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return function(b){return"form"in b?b.parentNode&&b.disabled===!1?"label"in b?"label"in b.parentNode?b.parentNode.disabled===a:b.disabled===a:b.isDisabled===a||b.isDisabled!==!a&&ea(b)===a:b.disabled===a:"label"in b&&b.disabled===a}}function pa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function qa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return!!b&&"HTML"!==b.nodeName},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),v!==n&&(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(n.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){return a.getAttribute("id")===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}}):(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c,d,e,f=b.getElementById(a);if(f){if(c=f.getAttributeNode("id"),c&&c.value===a)return[f];e=b.getElementsByName(a),d=0;while(f=e[d++])if(c=f.getAttributeNode("id"),c&&c.value===a)return[f]}return[]}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){if("undefined"!=typeof b.getElementsByClassName&&p)return b.getElementsByClassName(a)},r=[],q=[],(c.qsa=Y.test(n.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){a.innerHTML="";var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+K+"*[*^$|!~]?="),2!==a.querySelectorAll(":enabled").length&&q.push(":enabled",":disabled"),o.appendChild(a).disabled=!0,2!==a.querySelectorAll(":disabled").length&&q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Y.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"*"),s.call(a,"[s!='']:x"),r.push("!=",N)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Y.test(o.compareDocumentPosition),t=b||Y.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?I(k,a)-I(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?I(k,a)-I(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?la(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(S,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.escape=function(a){return(a+"").replace(ba,ca)},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(_,aa),a[3]=(a[3]||a[4]||a[5]||"").replace(_,aa),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return V.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&T.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(_,aa).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:!b||(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(O," ")+" ").indexOf(c)>-1:"|="===b&&(e===c||e.slice(0,c.length+1)===c+"-"))}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(P,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(_,aa),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return U.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(_,aa).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:oa(!1),disabled:oa(!0),checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:pa(function(){return[0]}),last:pa(function(a,b){return[b-1]}),eq:pa(function(a,b,c){return[c<0?c+b:c]}),even:pa(function(a,b){for(var c=0;c=0;)a.push(d);return a}),gt:pa(function(a,b,c){for(var d=c<0?c+b:c;++d1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function va(a,b,c){for(var d=0,e=b.length;d-1&&(f[j]=!(g[j]=l))}}else r=wa(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ya(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ta(function(a){return a===b},h,!0),l=ta(function(a){return I(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];i1&&ua(m),i>1&&sa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(P,"$1"),c,i0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=E.call(i));u=wa(u)}G.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&ga.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=ya(b[c]),f[u]?d.push(f):e.push(f);f=A(a,za(e,d)),f.selector=a}return f},i=ga.select=function(a,b,c,e){var f,i,j,k,l,m="function"==typeof a&&a,n=!e&&g(a=m.selector||a);if(c=c||[],1===n.length){if(i=n[0]=n[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&9===b.nodeType&&p&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(_,aa),b)||[])[0],!b)return c;m&&(b=b.parentNode),a=a.slice(i.shift().value.length)}f=V.needsContext.test(a)?0:i.length;while(f--){if(j=i[f],d.relative[k=j.type])break;if((l=d.find[k])&&(e=l(j.matches[0].replace(_,aa),$.test(i[0].type)&&qa(b.parentNode)||b))){if(i.splice(f,1),a=e.length&&sa(i),!a)return G.apply(c,e),c;break}}}return(m||h(a,n))(e,b,!p,c,!b||$.test(a)&&qa(b.parentNode)||b),c},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("fieldset"))}),ja(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){if(!c)return a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){if(!c&&"input"===a.nodeName.toLowerCase())return a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(J,function(a,b,c){var d;if(!c)return a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);r.find=x,r.expr=x.selectors,r.expr[":"]=r.expr.pseudos,r.uniqueSort=r.unique=x.uniqueSort,r.text=x.getText,r.isXMLDoc=x.isXML,r.contains=x.contains,r.escapeSelector=x.escape;var y=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&r(a).is(c))break;d.push(a)}return d},z=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},A=r.expr.match.needsContext;function B(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()}var C=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i,D=/^.[^:#\[\.,]*$/;function E(a,b,c){return r.isFunction(b)?r.grep(a,function(a,d){return!!b.call(a,d,a)!==c}):b.nodeType?r.grep(a,function(a){return a===b!==c}):"string"!=typeof b?r.grep(a,function(a){return i.call(b,a)>-1!==c}):D.test(b)?r.filter(b,a,c):(b=r.filter(b,a),r.grep(a,function(a){return i.call(b,a)>-1!==c&&1===a.nodeType}))}r.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?r.find.matchesSelector(d,a)?[d]:[]:r.find.matches(a,r.grep(b,function(a){return 1===a.nodeType}))},r.fn.extend({find:function(a){var b,c,d=this.length,e=this;if("string"!=typeof a)return this.pushStack(r(a).filter(function(){for(b=0;b1?r.uniqueSort(c):c},filter:function(a){return this.pushStack(E(this,a||[],!1))},not:function(a){return this.pushStack(E(this,a||[],!0))},is:function(a){return!!E(this,"string"==typeof a&&A.test(a)?r(a):a||[],!1).length}});var F,G=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,H=r.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||F,"string"==typeof a){if(e="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:G.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof r?b[0]:b,r.merge(this,r.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),C.test(e[1])&&r.isPlainObject(b))for(e in b)r.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}return f=d.getElementById(e[2]),f&&(this[0]=f,this.length=1),this}return a.nodeType?(this[0]=a,this.length=1,this):r.isFunction(a)?void 0!==c.ready?c.ready(a):a(r):r.makeArray(a,this)};H.prototype=r.fn,F=r(d);var I=/^(?:parents|prev(?:Until|All))/,J={children:!0,contents:!0,next:!0,prev:!0};r.fn.extend({has:function(a){var b=r(a,this),c=b.length;return this.filter(function(){for(var a=0;a-1:1===c.nodeType&&r.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?r.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?i.call(r(a),this[0]):i.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(r.uniqueSort(r.merge(this.get(),r(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function K(a,b){while((a=a[b])&&1!==a.nodeType);return a}r.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return y(a,"parentNode")},parentsUntil:function(a,b,c){return y(a,"parentNode",c)},next:function(a){return K(a,"nextSibling")},prev:function(a){return K(a,"previousSibling")},nextAll:function(a){return y(a,"nextSibling")},prevAll:function(a){return y(a,"previousSibling")},nextUntil:function(a,b,c){return y(a,"nextSibling",c)},prevUntil:function(a,b,c){return y(a,"previousSibling",c)},siblings:function(a){return z((a.parentNode||{}).firstChild,a)},children:function(a){return z(a.firstChild)},contents:function(a){return B(a,"iframe")?a.contentDocument:(B(a,"template")&&(a=a.content||a),r.merge([],a.childNodes))}},function(a,b){r.fn[a]=function(c,d){var e=r.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=r.filter(d,e)),this.length>1&&(J[a]||r.uniqueSort(e),I.test(a)&&e.reverse()),this.pushStack(e)}});var L=/[^\x20\t\r\n\f]+/g;function M(a){var b={};return r.each(a.match(L)||[],function(a,c){b[c]=!0}),b}r.Callbacks=function(a){a="string"==typeof a?M(a):r.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=e||a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h-1)f.splice(c,1),c<=h&&h--}),this},has:function(a){return a?r.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=g=[],c||b||(f=c=""),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j};function N(a){return a}function O(a){throw a}function P(a,b,c,d){var e;try{a&&r.isFunction(e=a.promise)?e.call(a).done(b).fail(c):a&&r.isFunction(e=a.then)?e.call(a,b,c):b.apply(void 0,[a].slice(d))}catch(a){c.apply(void 0,[a])}}r.extend({Deferred:function(b){var c=[["notify","progress",r.Callbacks("memory"),r.Callbacks("memory"),2],["resolve","done",r.Callbacks("once memory"),r.Callbacks("once memory"),0,"resolved"],["reject","fail",r.Callbacks("once memory"),r.Callbacks("once memory"),1,"rejected"]],d="pending",e={state:function(){return d},always:function(){return f.done(arguments).fail(arguments),this},"catch":function(a){return e.then(null,a)},pipe:function(){var a=arguments;return r.Deferred(function(b){r.each(c,function(c,d){var e=r.isFunction(a[d[4]])&&a[d[4]];f[d[1]](function(){var a=e&&e.apply(this,arguments);a&&r.isFunction(a.promise)?a.promise().progress(b.notify).done(b.resolve).fail(b.reject):b[d[0]+"With"](this,e?[a]:arguments)})}),a=null}).promise()},then:function(b,d,e){var f=0;function g(b,c,d,e){return function(){var h=this,i=arguments,j=function(){var a,j;if(!(b=f&&(d!==O&&(h=void 0,i=[a]),c.rejectWith(h,i))}};b?k():(r.Deferred.getStackHook&&(k.stackTrace=r.Deferred.getStackHook()),a.setTimeout(k))}}return r.Deferred(function(a){c[0][3].add(g(0,a,r.isFunction(e)?e:N,a.notifyWith)),c[1][3].add(g(0,a,r.isFunction(b)?b:N)),c[2][3].add(g(0,a,r.isFunction(d)?d:O))}).promise()},promise:function(a){return null!=a?r.extend(a,e):e}},f={};return r.each(c,function(a,b){var g=b[2],h=b[5];e[b[1]]=g.add,h&&g.add(function(){d=h},c[3-a][2].disable,c[0][2].lock),g.add(b[3].fire),f[b[0]]=function(){return f[b[0]+"With"](this===f?void 0:this,arguments),this},f[b[0]+"With"]=g.fireWith}),e.promise(f),b&&b.call(f,f),f},when:function(a){var b=arguments.length,c=b,d=Array(c),e=f.call(arguments),g=r.Deferred(),h=function(a){return function(c){d[a]=this,e[a]=arguments.length>1?f.call(arguments):c,--b||g.resolveWith(d,e)}};if(b<=1&&(P(a,g.done(h(c)).resolve,g.reject,!b),"pending"===g.state()||r.isFunction(e[c]&&e[c].then)))return g.then();while(c--)P(e[c],h(c),g.reject);return g.promise()}});var Q=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;r.Deferred.exceptionHook=function(b,c){a.console&&a.console.warn&&b&&Q.test(b.name)&&a.console.warn("jQuery.Deferred exception: "+b.message,b.stack,c)},r.readyException=function(b){a.setTimeout(function(){throw b})};var R=r.Deferred();r.fn.ready=function(a){return R.then(a)["catch"](function(a){r.readyException(a); +}),this},r.extend({isReady:!1,readyWait:1,ready:function(a){(a===!0?--r.readyWait:r.isReady)||(r.isReady=!0,a!==!0&&--r.readyWait>0||R.resolveWith(d,[r]))}}),r.ready.then=R.then;function S(){d.removeEventListener("DOMContentLoaded",S),a.removeEventListener("load",S),r.ready()}"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(r.ready):(d.addEventListener("DOMContentLoaded",S),a.addEventListener("load",S));var T=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===r.type(c)){e=!0;for(h in c)T(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,r.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(r(a),c)})),b))for(;h1,null,!0)},removeData:function(a){return this.each(function(){X.remove(this,a)})}}),r.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=W.get(a,b),c&&(!d||Array.isArray(c)?d=W.access(a,b,r.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=r.queue(a,b),d=c.length,e=c.shift(),f=r._queueHooks(a,b),g=function(){r.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return W.get(a,c)||W.access(a,c,{empty:r.Callbacks("once memory").add(function(){W.remove(a,[b+"queue",c])})})}}),r.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length\x20\t\r\n\f]+)/i,la=/^$|\/(?:java|ecma)script/i,ma={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ma.optgroup=ma.option,ma.tbody=ma.tfoot=ma.colgroup=ma.caption=ma.thead,ma.th=ma.td;function na(a,b){var c;return c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[],void 0===b||b&&B(a,b)?r.merge([a],c):c}function oa(a,b){for(var c=0,d=a.length;c-1)e&&e.push(f);else if(j=r.contains(f.ownerDocument,f),g=na(l.appendChild(f),"script"),j&&oa(g),c){k=0;while(f=g[k++])la.test(f.type||"")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement("div")),c=d.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),o.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="",o.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var ra=d.documentElement,sa=/^key/,ta=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,ua=/^([^.]*)(?:\.(.+)|)/;function va(){return!0}function wa(){return!1}function xa(){try{return d.activeElement}catch(a){}}function ya(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)ya(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=wa;else if(!e)return a;return 1===f&&(g=e,e=function(a){return r().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=r.guid++)),a.each(function(){r.event.add(this,b,e,d,c)})}r.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.get(a);if(q){c.handler&&(f=c,c=f.handler,e=f.selector),e&&r.find.matchesSelector(ra,e),c.guid||(c.guid=r.guid++),(i=q.events)||(i=q.events={}),(g=q.handle)||(g=q.handle=function(b){return"undefined"!=typeof r&&r.event.triggered!==b.type?r.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(L)||[""],j=b.length;while(j--)h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n&&(l=r.event.special[n]||{},n=(e?l.delegateType:l.bindType)||n,l=r.event.special[n]||{},k=r.extend({type:n,origType:p,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&r.expr.match.needsContext.test(e),namespace:o.join(".")},f),(m=i[n])||(m=i[n]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,o,g)!==!1||a.addEventListener&&a.addEventListener(n,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),r.event.global[n]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.hasData(a)&&W.get(a);if(q&&(i=q.events)){b=(b||"").match(L)||[""],j=b.length;while(j--)if(h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n){l=r.event.special[n]||{},n=(d?l.delegateType:l.bindType)||n,m=i[n]||[],h=h[2]&&new RegExp("(^|\\.)"+o.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&p!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,o,q.handle)!==!1||r.removeEvent(a,n,q.handle),delete i[n])}else for(n in i)r.event.remove(a,n+b[j],c,d,!0);r.isEmptyObject(i)&&W.remove(a,"handle events")}},dispatch:function(a){var b=r.event.fix(a),c,d,e,f,g,h,i=new Array(arguments.length),j=(W.get(this,"events")||{})[b.type]||[],k=r.event.special[b.type]||{};for(i[0]=b,c=1;c=1))for(;j!==this;j=j.parentNode||this)if(1===j.nodeType&&("click"!==a.type||j.disabled!==!0)){for(f=[],g={},c=0;c-1:r.find(e,this,null,[j]).length),g[e]&&f.push(d);f.length&&h.push({elem:j,handlers:f})}return j=this,i\x20\t\r\n\f]*)[^>]*)\/>/gi,Aa=/\s*$/g;function Ea(a,b){return B(a,"table")&&B(11!==b.nodeType?b:b.firstChild,"tr")?r(">tbody",a)[0]||a:a}function Fa(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function Ga(a){var b=Ca.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Ha(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(W.hasData(a)&&(f=W.access(a),g=W.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;c1&&"string"==typeof q&&!o.checkClone&&Ba.test(q))return a.each(function(e){var f=a.eq(e);s&&(b[0]=q.call(this,e,f.html())),Ja(f,b,c,d)});if(m&&(e=qa(b,a[0].ownerDocument,!1,a,d),f=e.firstChild,1===e.childNodes.length&&(e=f),f||d)){for(h=r.map(na(e,"script"),Fa),i=h.length;l")},clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=r.contains(a.ownerDocument,a);if(!(o.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||r.isXMLDoc(a)))for(g=na(h),f=na(a),d=0,e=f.length;d0&&oa(g,!i&&na(a,"script")),h},cleanData:function(a){for(var b,c,d,e=r.event.special,f=0;void 0!==(c=a[f]);f++)if(U(c)){if(b=c[W.expando]){if(b.events)for(d in b.events)e[d]?r.event.remove(c,d):r.removeEvent(c,d,b.handle);c[W.expando]=void 0}c[X.expando]&&(c[X.expando]=void 0)}}}),r.fn.extend({detach:function(a){return Ka(this,a,!0)},remove:function(a){return Ka(this,a)},text:function(a){return T(this,function(a){return void 0===a?r.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=a)})},null,a,arguments.length)},append:function(){return Ja(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ea(this,a);b.appendChild(a)}})},prepend:function(){return Ja(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ea(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return Ja(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return Ja(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(r.cleanData(na(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null!=a&&a,b=null==b?a:b,this.map(function(){return r.clone(this,a,b)})},html:function(a){return T(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!Aa.test(a)&&!ma[(ka.exec(a)||["",""])[1].toLowerCase()]){a=r.htmlPrefilter(a);try{for(;c1)}}),r.fn.delay=function(b,c){return b=r.fx?r.fx.speeds[b]||b:b,c=c||"fx",this.queue(c,function(c,d){var e=a.setTimeout(c,b);d.stop=function(){a.clearTimeout(e)}})},function(){var a=d.createElement("input"),b=d.createElement("select"),c=b.appendChild(d.createElement("option"));a.type="checkbox",o.checkOn=""!==a.value,o.optSelected=c.selected,a=d.createElement("input"),a.value="t",a.type="radio",o.radioValue="t"===a.value}();var _a,ab=r.expr.attrHandle;r.fn.extend({attr:function(a,b){return T(this,r.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){r.removeAttr(this,a)})}}),r.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return"undefined"==typeof a.getAttribute?r.prop(a,b,c):(1===f&&r.isXMLDoc(a)||(e=r.attrHooks[b.toLowerCase()]||(r.expr.match.bool.test(b)?_a:void 0)),void 0!==c?null===c?void r.removeAttr(a,b):e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:(a.setAttribute(b,c+""),c):e&&"get"in e&&null!==(d=e.get(a,b))?d:(d=r.find.attr(a,b),null==d?void 0:d))},attrHooks:{type:{set:function(a,b){if(!o.radioValue&&"radio"===b&&B(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}},removeAttr:function(a,b){var c,d=0,e=b&&b.match(L);if(e&&1===a.nodeType)while(c=e[d++])a.removeAttribute(c)}}),_a={set:function(a,b,c){return b===!1?r.removeAttr(a,c):a.setAttribute(c,c),c}},r.each(r.expr.match.bool.source.match(/\w+/g),function(a,b){var c=ab[b]||r.find.attr;ab[b]=function(a,b,d){var e,f,g=b.toLowerCase();return d||(f=ab[g],ab[g]=e,e=null!=c(a,b,d)?g:null,ab[g]=f),e}});var bb=/^(?:input|select|textarea|button)$/i,cb=/^(?:a|area)$/i;r.fn.extend({prop:function(a,b){return T(this,r.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[r.propFix[a]||a]})}}),r.extend({prop:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return 1===f&&r.isXMLDoc(a)||(b=r.propFix[b]||b,e=r.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=r.find.attr(a,"tabindex");return b?parseInt(b,10):bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),o.optSelected||(r.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null},set:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}}),r.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){r.propFix[this.toLowerCase()]=this});function db(a){var b=a.match(L)||[];return b.join(" ")}function eb(a){return a.getAttribute&&a.getAttribute("class")||""}r.fn.extend({addClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).addClass(a.call(this,b,eb(this)))});if("string"==typeof a&&a){b=a.match(L)||[];while(c=this[i++])if(e=eb(c),d=1===c.nodeType&&" "+db(e)+" "){g=0;while(f=b[g++])d.indexOf(" "+f+" ")<0&&(d+=f+" ");h=db(d),e!==h&&c.setAttribute("class",h)}}return this},removeClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).removeClass(a.call(this,b,eb(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof a&&a){b=a.match(L)||[];while(c=this[i++])if(e=eb(c),d=1===c.nodeType&&" "+db(e)+" "){g=0;while(f=b[g++])while(d.indexOf(" "+f+" ")>-1)d=d.replace(" "+f+" "," ");h=db(d),e!==h&&c.setAttribute("class",h)}}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):r.isFunction(a)?this.each(function(c){r(this).toggleClass(a.call(this,c,eb(this),b),b)}):this.each(function(){var b,d,e,f;if("string"===c){d=0,e=r(this),f=a.match(L)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else void 0!==a&&"boolean"!==c||(b=eb(this),b&&W.set(this,"__className__",b),this.setAttribute&&this.setAttribute("class",b||a===!1?"":W.get(this,"__className__")||""))})},hasClass:function(a){var b,c,d=0;b=" "+a+" ";while(c=this[d++])if(1===c.nodeType&&(" "+db(eb(c))+" ").indexOf(b)>-1)return!0;return!1}});var fb=/\r/g;r.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=r.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,r(this).val()):a,null==e?e="":"number"==typeof e?e+="":Array.isArray(e)&&(e=r.map(e,function(a){return null==a?"":a+""})),b=r.valHooks[this.type]||r.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=r.valHooks[e.type]||r.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(fb,""):null==c?"":c)}}}),r.extend({valHooks:{option:{get:function(a){var b=r.find.attr(a,"value");return null!=b?b:db(r.text(a))}},select:{get:function(a){var b,c,d,e=a.options,f=a.selectedIndex,g="select-one"===a.type,h=g?null:[],i=g?f+1:e.length;for(d=f<0?i:g?f:0;d-1)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),r.each(["radio","checkbox"],function(){r.valHooks[this]={set:function(a,b){if(Array.isArray(b))return a.checked=r.inArray(r(a).val(),b)>-1}},o.checkOn||(r.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var gb=/^(?:focusinfocus|focusoutblur)$/;r.extend(r.event,{trigger:function(b,c,e,f){var g,h,i,j,k,m,n,o=[e||d],p=l.call(b,"type")?b.type:b,q=l.call(b,"namespace")?b.namespace.split("."):[];if(h=i=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!gb.test(p+r.event.triggered)&&(p.indexOf(".")>-1&&(q=p.split("."),p=q.shift(),q.sort()),k=p.indexOf(":")<0&&"on"+p,b=b[r.expando]?b:new r.Event(p,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=q.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:r.makeArray(c,[b]),n=r.event.special[p]||{},f||!n.trigger||n.trigger.apply(e,c)!==!1)){if(!f&&!n.noBubble&&!r.isWindow(e)){for(j=n.delegateType||p,gb.test(j+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),i=h;i===(e.ownerDocument||d)&&o.push(i.defaultView||i.parentWindow||a)}g=0;while((h=o[g++])&&!b.isPropagationStopped())b.type=g>1?j:n.bindType||p,m=(W.get(h,"events")||{})[b.type]&&W.get(h,"handle"),m&&m.apply(h,c),m=k&&h[k],m&&m.apply&&U(h)&&(b.result=m.apply(h,c),b.result===!1&&b.preventDefault());return b.type=p,f||b.isDefaultPrevented()||n._default&&n._default.apply(o.pop(),c)!==!1||!U(e)||k&&r.isFunction(e[p])&&!r.isWindow(e)&&(i=e[k],i&&(e[k]=null),r.event.triggered=p,e[p](),r.event.triggered=void 0,i&&(e[k]=i)),b.result}},simulate:function(a,b,c){var d=r.extend(new r.Event,c,{type:a,isSimulated:!0});r.event.trigger(d,null,b)}}),r.fn.extend({trigger:function(a,b){return this.each(function(){r.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];if(c)return r.event.trigger(a,b,c,!0)}}),r.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(a,b){r.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),r.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),o.focusin="onfocusin"in a,o.focusin||r.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){r.event.simulate(b,a.target,r.event.fix(a))};r.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=W.access(d,b);e||d.addEventListener(a,c,!0),W.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=W.access(d,b)-1;e?W.access(d,b,e):(d.removeEventListener(a,c,!0),W.remove(d,b))}}});var hb=/\[\]$/,ib=/\r?\n/g,jb=/^(?:submit|button|image|reset|file)$/i,kb=/^(?:input|select|textarea|keygen)/i;function lb(a,b,c,d){var e;if(Array.isArray(b))r.each(b,function(b,e){c||hb.test(a)?d(a,e):lb(a+"["+("object"==typeof e&&null!=e?b:"")+"]",e,c,d); +});else if(c||"object"!==r.type(b))d(a,b);else for(e in b)lb(a+"["+e+"]",b[e],c,d)}r.param=function(a,b){var c,d=[],e=function(a,b){var c=r.isFunction(b)?b():b;d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(null==c?"":c)};if(Array.isArray(a)||a.jquery&&!r.isPlainObject(a))r.each(a,function(){e(this.name,this.value)});else for(c in a)lb(c,a[c],b,e);return d.join("&")},r.fn.extend({serialize:function(){return r.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=r.prop(this,"elements");return a?r.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!r(this).is(":disabled")&&kb.test(this.nodeName)&&!jb.test(a)&&(this.checked||!ja.test(a))}).map(function(a,b){var c=r(this).val();return null==c?null:Array.isArray(c)?r.map(c,function(a){return{name:b.name,value:a.replace(ib,"\r\n")}}):{name:b.name,value:c.replace(ib,"\r\n")}}).get()}}),r.fn.extend({wrapAll:function(a){var b;return this[0]&&(r.isFunction(a)&&(a=a.call(this[0])),b=r(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this},wrapInner:function(a){return r.isFunction(a)?this.each(function(b){r(this).wrapInner(a.call(this,b))}):this.each(function(){var b=r(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=r.isFunction(a);return this.each(function(c){r(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(a){return this.parent(a).not("body").each(function(){r(this).replaceWith(this.childNodes)}),this}}),r.expr.pseudos.hidden=function(a){return!r.expr.pseudos.visible(a)},r.expr.pseudos.visible=function(a){return!!(a.offsetWidth||a.offsetHeight||a.getClientRects().length)},o.createHTMLDocument=function(){var a=d.implementation.createHTMLDocument("").body;return a.innerHTML="
",2===a.childNodes.length}(),r.parseHTML=function(a,b,c){if("string"!=typeof a)return[];"boolean"==typeof b&&(c=b,b=!1);var e,f,g;return b||(o.createHTMLDocument?(b=d.implementation.createHTMLDocument(""),e=b.createElement("base"),e.href=d.location.href,b.head.appendChild(e)):b=d),f=C.exec(a),g=!c&&[],f?[b.createElement(f[1])]:(f=qa([a],b,g),g&&g.length&&r(g).remove(),r.merge([],f.childNodes))},r.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=r.css(a,"position"),l=r(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=r.css(a,"top"),i=r.css(a,"left"),j=("absolute"===k||"fixed"===k)&&(f+i).indexOf("auto")>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),r.isFunction(b)&&(b=b.call(a,c,r.extend({},h))),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},r.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){r.offset.setOffset(this,a,b)});var b,c,d,e,f=this[0];if(f)return f.getClientRects().length?(d=f.getBoundingClientRect(),b=f.ownerDocument,c=b.documentElement,e=b.defaultView,{top:d.top+e.pageYOffset-c.clientTop,left:d.left+e.pageXOffset-c.clientLeft}):{top:0,left:0}},position:function(){if(this[0]){var a,b,c=this[0],d={top:0,left:0};return"fixed"===r.css(c,"position")?b=c.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),B(a[0],"html")||(d=a.offset()),d={top:d.top+r.css(a[0],"borderTopWidth",!0),left:d.left+r.css(a[0],"borderLeftWidth",!0)}),{top:b.top-d.top-r.css(c,"marginTop",!0),left:b.left-d.left-r.css(c,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent;while(a&&"static"===r.css(a,"position"))a=a.offsetParent;return a||ra})}}),r.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c="pageYOffset"===b;r.fn[a]=function(d){return T(this,function(a,d,e){var f;return r.isWindow(a)?f=a:9===a.nodeType&&(f=a.defaultView),void 0===e?f?f[b]:a[d]:void(f?f.scrollTo(c?f.pageXOffset:e,c?e:f.pageYOffset):a[d]=e)},a,d,arguments.length)}}),r.each(["top","left"],function(a,b){r.cssHooks[b]=Pa(o.pixelPosition,function(a,c){if(c)return c=Oa(a,b),Ma.test(c)?r(a).position()[b]+"px":c})}),r.each({Height:"height",Width:"width"},function(a,b){r.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){r.fn[d]=function(e,f){var g=arguments.length&&(c||"boolean"!=typeof e),h=c||(e===!0||f===!0?"margin":"border");return T(this,function(b,c,e){var f;return r.isWindow(b)?0===d.indexOf("outer")?b["inner"+a]:b.document.documentElement["client"+a]:9===b.nodeType?(f=b.documentElement,Math.max(b.body["scroll"+a],f["scroll"+a],b.body["offset"+a],f["offset"+a],f["client"+a])):void 0===e?r.css(b,c,h):r.style(b,c,e,h)},b,g?e:void 0,g)}})}),r.fn.extend({bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}}),r.holdReady=function(a){a?r.readyWait++:r.ready(!0)},r.isArray=Array.isArray,r.parseJSON=JSON.parse,r.nodeName=B,"function"==typeof define&&define.amd&&define("jquery",[],function(){return r});var mb=a.jQuery,nb=a.$;return r.noConflict=function(b){return a.$===r&&(a.$=nb),b&&a.jQuery===r&&(a.jQuery=mb),r},b||(a.jQuery=a.$=r),r}); \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/layout/popper.min.js b/bellatrix.web.tests/src/main/resources/testpages/layout/popper.min.js new file mode 100644 index 00000000..0f20d2a8 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/layout/popper.min.js @@ -0,0 +1,5 @@ +/* + Copyright (C) Federico Zivolo 2017 + Distributed under the MIT License (license terms are at http://opensource.org/licenses/MIT). + */(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)/.test(r+s+p)?e:n(o(e))}function r(e){var o=e&&e.offsetParent,i=o&&o.nodeName;return i&&'BODY'!==i&&'HTML'!==i?-1!==['TD','TABLE'].indexOf(o.nodeName)&&'static'===t(o,'position')?r(o):o:e?e.ownerDocument.documentElement:document.documentElement}function p(e){var t=e.nodeName;return'BODY'!==t&&('HTML'===t||r(e.firstElementChild)===e)}function s(e){return null===e.parentNode?e:s(e.parentNode)}function d(e,t){if(!e||!e.nodeType||!t||!t.nodeType)return document.documentElement;var o=e.compareDocumentPosition(t)&Node.DOCUMENT_POSITION_FOLLOWING,i=o?e:t,n=o?t:e,a=document.createRange();a.setStart(i,0),a.setEnd(n,0);var l=a.commonAncestorContainer;if(e!==l&&t!==l||i.contains(n))return p(l)?l:r(l);var f=s(e);return f.host?d(f.host,t):d(e,s(t).host)}function a(e){var t=1=o.clientWidth&&i>=o.clientHeight}),l=0i[e]&&!t.escapeWithReference&&(n=_(p[o],i[e]-('right'===e?p.width:p.height))),pe({},o,n)}};return n.forEach(function(e){var t=-1===['left','top'].indexOf(e)?'secondary':'primary';p=se({},p,s[t](e))}),e.offsets.popper=p,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,i=t.reference,n=e.placement.split('-')[0],r=X,p=-1!==['top','bottom'].indexOf(n),s=p?'right':'bottom',d=p?'left':'top',a=p?'width':'height';return o[s]r(i[s])&&(e.offsets.popper[d]=r(i[s])),e}},arrow:{order:500,enabled:!0,fn:function(e,o){var i;if(!F(e.instance.modifiers,'arrow','keepTogether'))return e;var n=o.element;if('string'==typeof n){if(n=e.instance.popper.querySelector(n),!n)return e;}else if(!e.instance.popper.contains(n))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',g=a?'bottom':'right',u=L(n)[l];d[g]-us[g]&&(e.offsets.popper[m]+=d[m]+u-s[g]),e.offsets.popper=c(e.offsets.popper);var b=d[m]+d[l]/2-u/2,w=t(e.instance.popper),y=parseFloat(w['margin'+f],10),E=parseFloat(w['border'+f+'Width'],10),v=b-e.offsets.popper[m]-y-E;return v=J(_(s[l]-u,v),0),e.arrowElement=n,e.offsets.arrow=(i={},pe(i,m,Math.round(v)),pe(i,h,''),i),e},element:'[x-arrow]'},flip:{order:600,enabled:!0,fn:function(e,t){if(k(e.instance.modifiers,'inner'))return e;if(e.flipped&&e.placement===e.originalPlacement)return e;var o=y(e.instance.popper,e.instance.reference,t.padding,t.boundariesElement),i=e.placement.split('-')[0],n=x(i),r=e.placement.split('-')[1]||'',p=[];switch(t.behavior){case le.FLIP:p=[i,n];break;case le.CLOCKWISE:p=q(i);break;case le.COUNTERCLOCKWISE:p=q(i,!0);break;default:p=t.behavior;}return p.forEach(function(s,d){if(i!==s||p.length===d+1)return e;i=e.placement.split('-')[0],n=x(i);var a=e.offsets.popper,l=e.offsets.reference,f=X,m='left'===i&&f(a.right)>f(l.left)||'right'===i&&f(a.left)f(l.top)||'bottom'===i&&f(a.top)f(o.right),g=f(a.top)f(o.bottom),b='left'===i&&h||'right'===i&&c||'top'===i&&g||'bottom'===i&&u,w=-1!==['top','bottom'].indexOf(i),y=!!t.flipVariations&&(w&&'start'===r&&h||w&&'end'===r&&c||!w&&'start'===r&&g||!w&&'end'===r&&u);(m||b||y)&&(e.flipped=!0,(m||b)&&(i=p[d+1]),y&&(r=K(r)),e.placement=i+(r?'-'+r:''),e.offsets.popper=se({},e.offsets.popper,S(e.instance.popper,e.offsets.reference,e.placement)),e=C(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],i=e.offsets,n=i.popper,r=i.reference,p=-1!==['left','right'].indexOf(o),s=-1===['top','left'].indexOf(o);return n[p?'left':'top']=r[o]-(s?n[p?'width':'height']:0),e.placement=x(t),e.offsets.popper=c(n),e}},hide:{order:800,enabled:!0,fn:function(e){if(!F(e.instance.modifiers,'hide','preventOverflow'))return e;var t=e.offsets.reference,o=T(e.instance.modifiers,function(e){return'preventOverflow'===e.name}).boundaries;if(t.bottomo.right||t.top>o.bottom||t.right + + + + + + + + Pricing example for Bellatrix + + + + + + + + + + +
+
Automate The Planet
+ + Sign up +
+ +
+

Pricing

+

Quickly build an effective pricing table for your potential customers with this Bootstrap example. It's built with default Bootstrap components and utilities with little customization.

+
+ +
+
+
+
+

Free

+
+
+

$0 / mo

+
    +
  • 10 users included
  • +
  • 2 GB of storage
  • +
  • Email support
  • +
  • Help center access
  • +
+ +
+
+
+
+

Pro

+
+
+

$15 / mo

+
    +
  • 20 users included
  • +
  • 10 GB of storage
  • +
  • Priority email support
  • +
  • Help center access
  • +
+ +
+
+
+
+

Enterprise

+
+
+

$29 / mo

+
    +
  • 30 users included
  • +
  • 15 GB of storage
  • +
  • Phone and email support
  • +
  • Help center access
  • +
+ +
+
+
+ + +
+ + + + + + + + + + + + diff --git a/bellatrix.web.tests/src/main/resources/testpages/month/month.css b/bellatrix.web.tests/src/main/resources/testpages/month/month.css new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/month/month.html b/bellatrix.web.tests/src/main/resources/testpages/month/month.html new file mode 100644 index 00000000..b27b81da --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/month/month.html @@ -0,0 +1,58 @@ + + + + Url HTML Control Demo + + + + + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + + + + \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/month/month.js b/bellatrix.web.tests/src/main/resources/testpages/month/month.js new file mode 100644 index 00000000..d6a85479 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/month/month.js @@ -0,0 +1,14 @@ +window.onscroll = function (ev) { + var docHeight = document.body.offsetHeight; + docHeight = docHeight == undefined ? window.document.documentElement.scrollHeight : docHeight; + + var winheight = window.innerHeight; + winheight = winheight == undefined ? document.documentElement.clientHeight : winheight; + + var scrollpoint = window.scrollY; + scrollpoint = scrollpoint == undefined ? window.document.documentElement.scrollTop : scrollpoint; + + if ((scrollpoint + winheight) >= docHeight) { + document.getElementById("myURL12").style.color = "red"; + } +}; \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/number/number.css b/bellatrix.web.tests/src/main/resources/testpages/number/number.css new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/number/number.html b/bellatrix.web.tests/src/main/resources/testpages/number/number.html new file mode 100644 index 00000000..82e2897e --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/number/number.html @@ -0,0 +1,59 @@ + + + + Url HTML Control Demo + + + + + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + + + + + \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/number/number.js b/bellatrix.web.tests/src/main/resources/testpages/number/number.js new file mode 100644 index 00000000..d6a85479 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/number/number.js @@ -0,0 +1,14 @@ +window.onscroll = function (ev) { + var docHeight = document.body.offsetHeight; + docHeight = docHeight == undefined ? window.document.documentElement.scrollHeight : docHeight; + + var winheight = window.innerHeight; + winheight = winheight == undefined ? document.documentElement.clientHeight : winheight; + + var scrollpoint = window.scrollY; + scrollpoint = scrollpoint == undefined ? window.document.documentElement.scrollTop : scrollpoint; + + if ((scrollpoint + winheight) >= docHeight) { + document.getElementById("myURL12").style.color = "red"; + } +}; \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/output/output.css b/bellatrix.web.tests/src/main/resources/testpages/output/output.css new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/output/output.html b/bellatrix.web.tests/src/main/resources/testpages/output/output.html new file mode 100644 index 00000000..c35434e2 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/output/output.html @@ -0,0 +1,24 @@ + + + + Week HTML Control Demo + + + + + 10 + +
+
+ + + +
+
+ + + + + + + \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/output/output.js b/bellatrix.web.tests/src/main/resources/testpages/output/output.js new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/password/password.css b/bellatrix.web.tests/src/main/resources/testpages/password/password.css new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/password/password.html b/bellatrix.web.tests/src/main/resources/testpages/password/password.html new file mode 100644 index 00000000..2d757ffd --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/password/password.html @@ -0,0 +1,65 @@ + + + + Url HTML Control Demo + + + + + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+
+ + +
+ + + + \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/password/password.js b/bellatrix.web.tests/src/main/resources/testpages/password/password.js new file mode 100644 index 00000000..d6a85479 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/password/password.js @@ -0,0 +1,14 @@ +window.onscroll = function (ev) { + var docHeight = document.body.offsetHeight; + docHeight = docHeight == undefined ? window.document.documentElement.scrollHeight : docHeight; + + var winheight = window.innerHeight; + winheight = winheight == undefined ? document.documentElement.clientHeight : winheight; + + var scrollpoint = window.scrollY; + scrollpoint = scrollpoint == undefined ? window.document.documentElement.scrollTop : scrollpoint; + + if ((scrollpoint + winheight) >= docHeight) { + document.getElementById("myURL12").style.color = "red"; + } +}; \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/phone/phone.css b/bellatrix.web.tests/src/main/resources/testpages/phone/phone.css new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/phone/phone.html b/bellatrix.web.tests/src/main/resources/testpages/phone/phone.html new file mode 100644 index 00000000..90738ef0 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/phone/phone.html @@ -0,0 +1,70 @@ + + + + Url HTML Control Demo + + + + + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+
+ + +
+ +
+
+ + + + + + \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/phone/phone.js b/bellatrix.web.tests/src/main/resources/testpages/phone/phone.js new file mode 100644 index 00000000..d6a85479 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/phone/phone.js @@ -0,0 +1,14 @@ +window.onscroll = function (ev) { + var docHeight = document.body.offsetHeight; + docHeight = docHeight == undefined ? window.document.documentElement.scrollHeight : docHeight; + + var winheight = window.innerHeight; + winheight = winheight == undefined ? document.documentElement.clientHeight : winheight; + + var scrollpoint = window.scrollY; + scrollpoint = scrollpoint == undefined ? window.document.documentElement.scrollTop : scrollpoint; + + if ((scrollpoint + winheight) >= docHeight) { + document.getElementById("myURL12").style.color = "red"; + } +}; \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/progress/progress.css b/bellatrix.web.tests/src/main/resources/testpages/progress/progress.css new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/progress/progress.html b/bellatrix.web.tests/src/main/resources/testpages/progress/progress.html new file mode 100644 index 00000000..807e199c --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/progress/progress.html @@ -0,0 +1,29 @@ + + + + Week HTML Control Demo + + + + + 70 % + +
+
+ + 70 % + +
+
+ + 70 % + +
+
+ + + + + + + \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/progress/progress.js b/bellatrix.web.tests/src/main/resources/testpages/progress/progress.js new file mode 100644 index 00000000..83e56e3b --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/progress/progress.js @@ -0,0 +1,25 @@ +var buttons = document.querySelectorAll('input'); +for (var i = 0; i < buttons.length; i++) { + var self = buttons[i]; + + self.addEventListener('click', function (event) { + if (this.value === 'Start') { + this.value = 'Stop'; + } else { + this.value = 'Start'; + } + }, false); +} + +var buttons1 = document.querySelectorAll('button'); +for (var i = 0; i < buttons1.length; i++) { + var self = buttons1[i]; + + self.addEventListener('click', function (event) { + if (this.innerHTML === 'Start') { + this.innerHTML = 'Stop'; + } else { + this.innerHTML = 'Start'; + } + }, false); +} \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/radio/radio.css b/bellatrix.web.tests/src/main/resources/testpages/radio/radio.css new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/radio/radio.html b/bellatrix.web.tests/src/main/resources/testpages/radio/radio.html new file mode 100644 index 00000000..e5f63035 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/radio/radio.html @@ -0,0 +1,31 @@ + + + + Url HTML Control Demo + + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + + + + + \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/radio/radio.js b/bellatrix.web.tests/src/main/resources/testpages/radio/radio.js new file mode 100644 index 00000000..d6a85479 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/radio/radio.js @@ -0,0 +1,14 @@ +window.onscroll = function (ev) { + var docHeight = document.body.offsetHeight; + docHeight = docHeight == undefined ? window.document.documentElement.scrollHeight : docHeight; + + var winheight = window.innerHeight; + winheight = winheight == undefined ? document.documentElement.clientHeight : winheight; + + var scrollpoint = window.scrollY; + scrollpoint = scrollpoint == undefined ? window.document.documentElement.scrollTop : scrollpoint; + + if ((scrollpoint + winheight) >= docHeight) { + document.getElementById("myURL12").style.color = "red"; + } +}; \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/range/range.css b/bellatrix.web.tests/src/main/resources/testpages/range/range.css new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/range/range.html b/bellatrix.web.tests/src/main/resources/testpages/range/range.html new file mode 100644 index 00000000..f74c12b6 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/range/range.html @@ -0,0 +1,77 @@ + + + + Url HTML Control Demo + + + + + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + + + + + + + \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/range/range.js b/bellatrix.web.tests/src/main/resources/testpages/range/range.js new file mode 100644 index 00000000..d6a85479 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/range/range.js @@ -0,0 +1,14 @@ +window.onscroll = function (ev) { + var docHeight = document.body.offsetHeight; + docHeight = docHeight == undefined ? window.document.documentElement.scrollHeight : docHeight; + + var winheight = window.innerHeight; + winheight = winheight == undefined ? document.documentElement.clientHeight : winheight; + + var scrollpoint = window.scrollY; + scrollpoint = scrollpoint == undefined ? window.document.documentElement.scrollTop : scrollpoint; + + if ((scrollpoint + winheight) >= docHeight) { + document.getElementById("myURL12").style.color = "red"; + } +}; \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/reset/reset.css b/bellatrix.web.tests/src/main/resources/testpages/reset/reset.css new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/reset/reset.html b/bellatrix.web.tests/src/main/resources/testpages/reset/reset.html new file mode 100644 index 00000000..4372387e --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/reset/reset.html @@ -0,0 +1,30 @@ + + + + Week HTML Control Demo + + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + + + + \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/reset/reset.js b/bellatrix.web.tests/src/main/resources/testpages/reset/reset.js new file mode 100644 index 00000000..83e56e3b --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/reset/reset.js @@ -0,0 +1,25 @@ +var buttons = document.querySelectorAll('input'); +for (var i = 0; i < buttons.length; i++) { + var self = buttons[i]; + + self.addEventListener('click', function (event) { + if (this.value === 'Start') { + this.value = 'Stop'; + } else { + this.value = 'Start'; + } + }, false); +} + +var buttons1 = document.querySelectorAll('button'); +for (var i = 0; i < buttons1.length; i++) { + var self = buttons1[i]; + + self.addEventListener('click', function (event) { + if (this.innerHTML === 'Start') { + this.innerHTML = 'Stop'; + } else { + this.innerHTML = 'Start'; + } + }, false); +} \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/search/search.css b/bellatrix.web.tests/src/main/resources/testpages/search/search.css new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/search/search.html b/bellatrix.web.tests/src/main/resources/testpages/search/search.html new file mode 100644 index 00000000..4f736af7 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/search/search.html @@ -0,0 +1,65 @@ + + + + Url HTML Control Demo + + + + + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+
+ + +
+ + + + \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/search/search.js b/bellatrix.web.tests/src/main/resources/testpages/search/search.js new file mode 100644 index 00000000..d6a85479 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/search/search.js @@ -0,0 +1,14 @@ +window.onscroll = function (ev) { + var docHeight = document.body.offsetHeight; + docHeight = docHeight == undefined ? window.document.documentElement.scrollHeight : docHeight; + + var winheight = window.innerHeight; + winheight = winheight == undefined ? document.documentElement.clientHeight : winheight; + + var scrollpoint = window.scrollY; + scrollpoint = scrollpoint == undefined ? window.document.documentElement.scrollTop : scrollpoint; + + if ((scrollpoint + winheight) >= docHeight) { + document.getElementById("myURL12").style.color = "red"; + } +}; \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/select/select.css b/bellatrix.web.tests/src/main/resources/testpages/select/select.css new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/select/select.html b/bellatrix.web.tests/src/main/resources/testpages/select/select.html new file mode 100644 index 00000000..3d4d087d --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/select/select.html @@ -0,0 +1,55 @@ + + + + Week HTML Control Demo + + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + + + + \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/select/select.js b/bellatrix.web.tests/src/main/resources/testpages/select/select.js new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/span/span.css b/bellatrix.web.tests/src/main/resources/testpages/span/span.css new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/span/span.html b/bellatrix.web.tests/src/main/resources/testpages/span/span.html new file mode 100644 index 00000000..18760f4d --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/span/span.html @@ -0,0 +1,28 @@ + + + + Week HTML Control Demo + + + + + Bellatrix + +
+
+ + Automate The Planet + +
+
+ + + +
+
+ + + + + + \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/span/span.js b/bellatrix.web.tests/src/main/resources/testpages/span/span.js new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/table/table.css b/bellatrix.web.tests/src/main/resources/testpages/table/table.css new file mode 100644 index 00000000..c80dfa11 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/table/table.css @@ -0,0 +1,23 @@ +span { + padding-right: 20px; + background-repeat: no-repeat; + background-position: 100% 100%; +} + +.tablesorter-headerAsc span { + background-image: url('img/down-arrow.png'); +} + +.tablesorter-headerDesc span { + background-image: url('img/up-arrow.png'); +} + +th span { + font-family: "Helvetica, Arial, sans-serif"; + font-size: 14px; +} + +td { + font-family: "Helvetica, Arial, sans-serif"; + font-size: 14px; +} \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/table/table.html b/bellatrix.web.tests/src/main/resources/testpages/table/table.html new file mode 100644 index 00000000..43e190a8 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/table/table.html @@ -0,0 +1,238 @@ + + + + Table HTML Control Demo + + + +
+

Data Tables

+

Often times when you see a table it contains data which is sortable -- sometimes with actions that can be taken within each row (e.g. edit, delete). And it can be challenging to automate interaction with sets of data in a table depending on how it is constructed.

+ +

Example 1

+

No Class or ID attributes to signify groupings of rows and columns

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Last NameFirst NameEmailDueWeb SiteAction
SmithJohnjsmith@gmail.com$50.00http://www.jsmith.com + edit + delete +
BachFrankfbach@yahoo.com$51.00http://www.frank.com + edit + delete +
DoeJasonjdoe@hotmail.com$100.00http://www.jdoe.com + edit + delete +
ConwayTimtconway@earthlink.net$50.00http://www.timconway.com + edit + delete +
+ +

Example 2

+

Class and ID attributes to signify groupings of rows and columns

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Last NameFirst NameDueWeb SiteAction
SmithJohn$50.00http://www.jsmith.com + edit + delete +
BachFrank$51.00http://www.frank.com + edit + delete +
DoeJason$100.00http://www.jdoe.com + edit + delete +
ConwayTim$50.00http://www.timconway.com + edit + delete +
+
+ +
+

Basic Tables

+

Some tables dont have the HTML elements thead, tbody or tfoot. While designing locators this should be taken into consideration.

+ +

Example 1

+

Simple table with *tr* and *td* elements only

+ + + + + + + + + + + + + + + + + + + + + + + + + +
SmithJohn$50.00http://www.jsmith.com
BachFrank$51.00http://www.frank.com
DoeJason$100.00http://www.jdoe.com
ConwayTim$50.00http://www.timconway.com
+
+
+

Nested Tables

+

Some tables have nested tables in one or more of the table cells. This causes difficulties when trying to iterate over the table cells of a row, since only the direct children of the row have to be located.

+ +

Example 1

+

Single Inline table in table cell

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Last NameFirst NameEmailDueWeb Site
SmithJohn + + + +
Businessjsmith@corp.com
Personaljsmith@gmail.com
+
$50.00http://www.jsmith.com
BachFrank + + + +
Businessfbach@someway.com
Personalfbach@yahoo.com
+
$51.00http://www.frank.com
DoeJason + + + +
Business
Personaljdoe@hotmail.com
+
$100.00http://www.jdoe.com
ConwayTim + + + +
Businesstconway@earthlink.net
Personal
+
$50.00http://www.timconway.com
+
+ + + \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/table/table.js b/bellatrix.web.tests/src/main/resources/testpages/table/table.js new file mode 100644 index 00000000..e194759d --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/table/table.js @@ -0,0 +1,4 @@ +$(function () { + $("#table1").tablesorter(); + $("#table2").tablesorter(); +}); \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/text/text.css b/bellatrix.web.tests/src/main/resources/testpages/text/text.css new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/text/text.html b/bellatrix.web.tests/src/main/resources/testpages/text/text.html new file mode 100644 index 00000000..eab377fe --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/text/text.html @@ -0,0 +1,61 @@ + + + + Url HTML Control Demo + + + + + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/text/text.js b/bellatrix.web.tests/src/main/resources/testpages/text/text.js new file mode 100644 index 00000000..d6a85479 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/text/text.js @@ -0,0 +1,14 @@ +window.onscroll = function (ev) { + var docHeight = document.body.offsetHeight; + docHeight = docHeight == undefined ? window.document.documentElement.scrollHeight : docHeight; + + var winheight = window.innerHeight; + winheight = winheight == undefined ? document.documentElement.clientHeight : winheight; + + var scrollpoint = window.scrollY; + scrollpoint = scrollpoint == undefined ? window.document.documentElement.scrollTop : scrollpoint; + + if ((scrollpoint + winheight) >= docHeight) { + document.getElementById("myURL12").style.color = "red"; + } +}; \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/textarea/textArea.css b/bellatrix.web.tests/src/main/resources/testpages/textarea/textArea.css new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/textarea/textArea.html b/bellatrix.web.tests/src/main/resources/testpages/textarea/textArea.html new file mode 100644 index 00000000..b49f138a --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/textarea/textArea.html @@ -0,0 +1,65 @@ + + + + Url HTML Control Demo + + + + + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + + + + + \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/textarea/textArea.js b/bellatrix.web.tests/src/main/resources/testpages/textarea/textArea.js new file mode 100644 index 00000000..d6a85479 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/textarea/textArea.js @@ -0,0 +1,14 @@ +window.onscroll = function (ev) { + var docHeight = document.body.offsetHeight; + docHeight = docHeight == undefined ? window.document.documentElement.scrollHeight : docHeight; + + var winheight = window.innerHeight; + winheight = winheight == undefined ? document.documentElement.clientHeight : winheight; + + var scrollpoint = window.scrollY; + scrollpoint = scrollpoint == undefined ? window.document.documentElement.scrollTop : scrollpoint; + + if ((scrollpoint + winheight) >= docHeight) { + document.getElementById("myURL12").style.color = "red"; + } +}; \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/time/time.css b/bellatrix.web.tests/src/main/resources/testpages/time/time.css new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/time/time.html b/bellatrix.web.tests/src/main/resources/testpages/time/time.html new file mode 100644 index 00000000..9fc61467 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/time/time.html @@ -0,0 +1,58 @@ + + + + Url HTML Control Demo + + + + + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + + + + \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/time/time.js b/bellatrix.web.tests/src/main/resources/testpages/time/time.js new file mode 100644 index 00000000..d6a85479 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/time/time.js @@ -0,0 +1,14 @@ +window.onscroll = function (ev) { + var docHeight = document.body.offsetHeight; + docHeight = docHeight == undefined ? window.document.documentElement.scrollHeight : docHeight; + + var winheight = window.innerHeight; + winheight = winheight == undefined ? document.documentElement.clientHeight : winheight; + + var scrollpoint = window.scrollY; + scrollpoint = scrollpoint == undefined ? window.document.documentElement.scrollTop : scrollpoint; + + if ((scrollpoint + winheight) >= docHeight) { + document.getElementById("myURL12").style.color = "red"; + } +}; \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/url/url.css b/bellatrix.web.tests/src/main/resources/testpages/url/url.css new file mode 100644 index 00000000..e69de29b diff --git a/bellatrix.web.tests/src/main/resources/testpages/url/url.html b/bellatrix.web.tests/src/main/resources/testpages/url/url.html new file mode 100644 index 00000000..83b17d86 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/url/url.html @@ -0,0 +1,221 @@ + + + + Url HTML Control Demo + + + + + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+
+ + +
+ +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + + + + + \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/url/url.js b/bellatrix.web.tests/src/main/resources/testpages/url/url.js new file mode 100644 index 00000000..d6a85479 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/url/url.js @@ -0,0 +1,14 @@ +window.onscroll = function (ev) { + var docHeight = document.body.offsetHeight; + docHeight = docHeight == undefined ? window.document.documentElement.scrollHeight : docHeight; + + var winheight = window.innerHeight; + winheight = winheight == undefined ? document.documentElement.clientHeight : winheight; + + var scrollpoint = window.scrollY; + scrollpoint = scrollpoint == undefined ? window.document.documentElement.scrollTop : scrollpoint; + + if ((scrollpoint + winheight) >= docHeight) { + document.getElementById("myURL12").style.color = "red"; + } +}; \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/week/week.css b/bellatrix.web.tests/src/main/resources/testpages/week/week.css new file mode 100644 index 00000000..5f282702 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/week/week.css @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/week/week.html b/bellatrix.web.tests/src/main/resources/testpages/week/week.html new file mode 100644 index 00000000..364c8c33 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/week/week.html @@ -0,0 +1,58 @@ + + + + Url HTML Control Demo + + + + + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + + + + \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testpages/week/week.js b/bellatrix.web.tests/src/main/resources/testpages/week/week.js new file mode 100644 index 00000000..5f282702 --- /dev/null +++ b/bellatrix.web.tests/src/main/resources/testpages/week/week.js @@ -0,0 +1 @@ + \ No newline at end of file From 96074fedabda8612b25f0f6a27044f6ac4b375cd Mon Sep 17 00:00:00 2001 From: MiriamKyoseva Date: Wed, 12 Jun 2024 12:20:40 +0300 Subject: [PATCH 22/94] Updated config and added TestPagesSettings in bellatrix.web.tests --- .../configuration/TestPagesSettings.java | 40 +++++++++++++++++++ .../resources/testFrameworkSettings.dev.json | 35 ++++++++++++++++ .../resources/testFrameworkSettings.qa.json | 35 ++++++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 bellatrix.web.tests/src/main/java/common/configuration/TestPagesSettings.java diff --git a/bellatrix.web.tests/src/main/java/common/configuration/TestPagesSettings.java b/bellatrix.web.tests/src/main/java/common/configuration/TestPagesSettings.java new file mode 100644 index 00000000..e425fc5a --- /dev/null +++ b/bellatrix.web.tests/src/main/java/common/configuration/TestPagesSettings.java @@ -0,0 +1,40 @@ +package common.configuration; + +import lombok.Data; + +@Data +public class TestPagesSettings { + private String anchorLocalPage; + private String buttonLocalPage; + private String checkBoxLocalPage; + private String colorLocalPage; + private String dateLocalPage; + private String dateTimeLocalLocalPage; + private String gridLocalPage; + private String divLocalPage; + private String elementLocalPage; + private String emailLocalPage; + private String headingLocalPage; + private String imageLocalPage; + private String labelLocalPage; + private String monthLocalPage; + private String numberLocalPage; + private String optionLocalPage; + private String outputLocalPage; + private String passwordLocalPage; + private String phoneLocalPage; + private String progressLocalPage; + private String radioLocalPage; + private String rangeLocalPage; + private String resetLocalPage; + private String searchLocalPage; + private String selectLocalPage; + private String spanLocalPage; + private String textAreaLocalPage; + private String textFieldLocalPage; + private String timeLocalPage; + private String urlLocalPage; + private String weekLocalPage; + private String tableLocalPage; + private String layoutPricingPage; +} \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testFrameworkSettings.dev.json b/bellatrix.web.tests/src/main/resources/testFrameworkSettings.dev.json index af33dffd..d38a3ed3 100644 --- a/bellatrix.web.tests/src/main/resources/testFrameworkSettings.dev.json +++ b/bellatrix.web.tests/src/main/resources/testFrameworkSettings.dev.json @@ -109,5 +109,40 @@ "urlSettings": { "shopUrl": "http://demos.bellatrix.solutions/cart/", "accountUrl": "http://demos.bellatrix.solutions/account/" + }, + "testPagesSettings": { + "anchorLocalPage": "testpages\\anchor\\anchor.html", + "buttonLocalPage": "testpages\\button\\button.html", + "checkBoxLocalPage": "testpages\\checkbox\\checkBox.html", + "colorLocalPage": "testpages\\color\\color.html", + "dateLocalPage": "testpages\\date\\date.html", + "dateTimeLocalLocalPage": "testpages\\datetimelocal\\dateTimeLocal.html", + "divLocalPage": "testpages\\div\\div.html", + "elementLocalPage": "testpages\\url\\url.html", + "emailLocalPage": "testpages\\email\\email.html", + "headingLocalPage": "testpages\\heading\\heading.html", + "imageLocalPage": "testpages\\image\\image.html", + "labelLocalPage": "testpages\\label\\label.html", + "monthLocalPage": "testpages\\month\\month.html", + "numberLocalPage": "testpages\\number\\number.html", + "optionLocalPage": "testpages\\select\\select.html", + "outputLocalPage": "testpages\\output\\output.html", + "passwordLocalPage": "testpages\\password\\password.html", + "phoneLocalPage": "testpages\\phone\\phone.html", + "progressLocalPage": "testpages\\progress\\progress.html", + "radioLocalPage": "testpages\\radio\\radio.html", + "rangeLocalPage": "testpages\\range\\range.html", + "resetLocalPage": "testpages\\reset\\reset.html", + "searchLocalPage": "testpages\\search\\search.html", + "selectLocalPage": "testpages\\select\\select.html", + "spanLocalPage": "testpages\\span\\span.html", + "textAreaLocalPage": "testpages\\textarea\\textArea.html", + "textFieldLocalPage": "testpages\\text\\text.html", + "timeLocalPage": "testpages\\time\\time.html", + "urlLocalPage": "testpages\\url\\url.html", + "weekLocalPage": "testpages\\week\\week.html", + "tableLocalPage": "testpages\\table\\table.html", + "layoutPricingPage": "testpages\\layout\\pricing.html", + "gridLocalPage": "testpages\\grid\\grid.html" } } \ No newline at end of file diff --git a/bellatrix.web.tests/src/main/resources/testFrameworkSettings.qa.json b/bellatrix.web.tests/src/main/resources/testFrameworkSettings.qa.json index af33dffd..d38a3ed3 100644 --- a/bellatrix.web.tests/src/main/resources/testFrameworkSettings.qa.json +++ b/bellatrix.web.tests/src/main/resources/testFrameworkSettings.qa.json @@ -109,5 +109,40 @@ "urlSettings": { "shopUrl": "http://demos.bellatrix.solutions/cart/", "accountUrl": "http://demos.bellatrix.solutions/account/" + }, + "testPagesSettings": { + "anchorLocalPage": "testpages\\anchor\\anchor.html", + "buttonLocalPage": "testpages\\button\\button.html", + "checkBoxLocalPage": "testpages\\checkbox\\checkBox.html", + "colorLocalPage": "testpages\\color\\color.html", + "dateLocalPage": "testpages\\date\\date.html", + "dateTimeLocalLocalPage": "testpages\\datetimelocal\\dateTimeLocal.html", + "divLocalPage": "testpages\\div\\div.html", + "elementLocalPage": "testpages\\url\\url.html", + "emailLocalPage": "testpages\\email\\email.html", + "headingLocalPage": "testpages\\heading\\heading.html", + "imageLocalPage": "testpages\\image\\image.html", + "labelLocalPage": "testpages\\label\\label.html", + "monthLocalPage": "testpages\\month\\month.html", + "numberLocalPage": "testpages\\number\\number.html", + "optionLocalPage": "testpages\\select\\select.html", + "outputLocalPage": "testpages\\output\\output.html", + "passwordLocalPage": "testpages\\password\\password.html", + "phoneLocalPage": "testpages\\phone\\phone.html", + "progressLocalPage": "testpages\\progress\\progress.html", + "radioLocalPage": "testpages\\radio\\radio.html", + "rangeLocalPage": "testpages\\range\\range.html", + "resetLocalPage": "testpages\\reset\\reset.html", + "searchLocalPage": "testpages\\search\\search.html", + "selectLocalPage": "testpages\\select\\select.html", + "spanLocalPage": "testpages\\span\\span.html", + "textAreaLocalPage": "testpages\\textarea\\textArea.html", + "textFieldLocalPage": "testpages\\text\\text.html", + "timeLocalPage": "testpages\\time\\time.html", + "urlLocalPage": "testpages\\url\\url.html", + "weekLocalPage": "testpages\\week\\week.html", + "tableLocalPage": "testpages\\table\\table.html", + "layoutPricingPage": "testpages\\layout\\pricing.html", + "gridLocalPage": "testpages\\grid\\grid.html" } } \ No newline at end of file From eaffe37d23d1f371168ab40715d933e0e67530f5 Mon Sep 17 00:00:00 2001 From: MiriamKyoseva Date: Wed, 12 Jun 2024 12:20:54 +0300 Subject: [PATCH 23/94] Added tests for Table component inside bellatrix.web.tests --- .../controls/table/DataTableExampleOne.java | 19 ++++ .../table/TableControlTestsChrome.java | 87 +++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 bellatrix.web.tests/src/test/java/controls/table/DataTableExampleOne.java create mode 100644 bellatrix.web.tests/src/test/java/controls/table/TableControlTestsChrome.java diff --git a/bellatrix.web.tests/src/test/java/controls/table/DataTableExampleOne.java b/bellatrix.web.tests/src/test/java/controls/table/DataTableExampleOne.java new file mode 100644 index 00000000..500548bc --- /dev/null +++ b/bellatrix.web.tests/src/test/java/controls/table/DataTableExampleOne.java @@ -0,0 +1,19 @@ +package controls.table; + +import lombok.Getter; +import lombok.Setter; +import solutions.bellatrix.web.components.advanced.TableHeader; + +@Getter @Setter +public class DataTableExampleOne { + @TableHeader(name = "Last Name") + public String lastName; + @TableHeader(name = "First Name") + public String firstName; + @TableHeader(name = "Email") + public String email; + @TableHeader(name = "Due") + public String due; + @TableHeader(name = "Web Site") + public String website; +} diff --git a/bellatrix.web.tests/src/test/java/controls/table/TableControlTestsChrome.java b/bellatrix.web.tests/src/test/java/controls/table/TableControlTestsChrome.java new file mode 100644 index 00000000..1c97c40f --- /dev/null +++ b/bellatrix.web.tests/src/test/java/controls/table/TableControlTestsChrome.java @@ -0,0 +1,87 @@ +package controls.table; + +import common.configuration.TestPagesSettings; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import solutions.bellatrix.core.configuration.ConfigurationService; +import solutions.bellatrix.web.components.advanced.table.Table; +import solutions.bellatrix.web.infrastructure.Browser; +import solutions.bellatrix.web.infrastructure.ExecutionBrowser; +import solutions.bellatrix.web.infrastructure.Lifecycle; +import solutions.bellatrix.web.infrastructure.junit.WebTest; + +@ExecutionBrowser(browser = Browser.CHROME, lifecycle = Lifecycle.REUSE_IF_STARTED) +public class TableControlTestsChrome extends WebTest { + @BeforeEach + public void testInit() { + var url = ConfigurationService.get(TestPagesSettings.class).getTableLocalPage(); + app().navigate().toLocalPage(url); + } + + @Test + public void tableGetItems() { + var table = app().create().byId(Table.class, "table1"); + table.setColumn("Last Name").setColumn("First Name").setColumn("Email").setColumn("Due").setColumn("Web Site").setColumn("Action"); + + var dataTableExampleOnes = table.getItems(DataTableExampleOne.class); + + Assertions.assertEquals("Smith", dataTableExampleOnes.get(0).lastName); + Assertions.assertEquals("John", dataTableExampleOnes.get(0).firstName); + Assertions.assertEquals("http://www.timconway.com", dataTableExampleOnes.get(dataTableExampleOnes.size() - 1).website); + } + + @Test + public void basicTableHasHeader() { + var table = app().create().byId(Table.class, "table1"); + + var headerNames = table.getHeaderNames(); + var tableCell = table.getCell(3, 1); + + Assertions.assertTrue(headerNames.contains("Due")); + Assertions.assertEquals("$51.00", tableCell.getText()); + } + + @Test + public void tableWithHeaderReturnsValue() { + var table = app().create().byId(Table.class, "table1"); + table.setColumn("Last Name").setColumn("First Name").setColumn("Email").setColumn("Due").setColumn("Web Site").setColumn("Action"); + + var tableCell = table.getCell("Email", 1); + + Assertions.assertEquals("fbach@yahoo.com", tableCell.getText()); + } + + @Test + public void simpleTableReturnsAllRowsAndCells() { + var table = app().create().byId(Table.class, "simpleTable"); + var firstRowCellsCount = table.getRow(0).getCells().size(); + var secondRowCellsCount = table.getRow(1).getCells().size(); + + Assertions.assertEquals(firstRowCellsCount, secondRowCellsCount); + Assertions.assertEquals(4, firstRowCellsCount); + } + + @Test + public void nestedTablesReturnsTableCellsCountEqualToTableHeadersCount() { + var table = app().create().byId(Table.class, "nestedTable"); + table.setColumn("Last Name").setColumn("First Name").setColumn("Email").setColumn("Due").setColumn("Web Site"); + + var tableHeadersCount = table.getHeaderNames().size(); + var tableCellsCount = table.getRow(0).getCells().size(); + + Assertions.assertEquals(tableHeadersCount, tableCellsCount); + } + + @Test + public void nestedTablesReturnsTableCellsCountEqualBetweenRows() { + var table = app().create().byId(Table.class, "nestedTable"); + table.setColumn("Last Name").setColumn("First Name").setColumn("Email").setColumn("Due").setColumn("Web Site"); + + var firstRowCellsCount = table.getRow(0).getCells().size(); + var secondRowCellsCount = table.getRow(1).getCells().size(); + + Assertions.assertEquals(firstRowCellsCount, secondRowCellsCount); + + } +} From d946a91cd26accb49350d41c93d5bbbff2f27f95 Mon Sep 17 00:00:00 2001 From: MiriamKyoseva Date: Wed, 12 Jun 2024 13:41:21 +0300 Subject: [PATCH 24/94] Update TypeParser.java --- .../bellatrix/core/utilities/TypeParser.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/TypeParser.java b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/TypeParser.java index 697bcaa6..2b3229aa 100644 --- a/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/TypeParser.java +++ b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/TypeParser.java @@ -50,6 +50,10 @@ public class TypeParser { Map.entry(String.class, STRING_ALLOWED_OPERATIONS) )); + /** + * Checks for enum fields containing the specified value and prioritizes which enum value to return by the field, + * instead of the name of the enum value. + */ @SuppressWarnings("unchecked") @SneakyThrows public static T parseEnumValue(String value, Class enumClass) { @@ -68,19 +72,19 @@ public static T parseEnumValue(String value, Class enumClass) { } // TODO: RENAME ME - public class SpecificInstructions extends HashMap, Function> { - public SpecificInstructions(Map, Function> map) { + public class SpecificInstructions extends HashMap, Function> { + public SpecificInstructions(Map, Function> map) { super(map); } - public Function to(Class clazz) { + public Function to(Class clazz) { return this.get(clazz); } } // TODO: RENAME ME - public class InstructionsCollection extends HashMap, T> { - public InstructionsCollection(Map, T> map) { + public class InstructionsCollection extends HashMap, T> { + public InstructionsCollection(Map, T> map) { super(map); } From f49228a088cc0402412ffda90eae83e708f47f57 Mon Sep 17 00:00:00 2001 From: MiriamKyoseva <133047546+MiriamKyoseva@users.noreply.github.com> Date: Fri, 14 Jun 2024 17:36:46 +0300 Subject: [PATCH 25/94] Changes to Core utilities --- .../bellatrix/core/utilities/HtmlService.java | 40 +-- .../bellatrix/core/utilities/TypeParser.java | 95 ------- .../parsing/ParsingInstructions.java | 31 +++ .../core/utilities/parsing/TypeParser.java | 250 ++++++++++++++++++ 4 files changed, 306 insertions(+), 110 deletions(-) delete mode 100644 bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/TypeParser.java create mode 100644 bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/parsing/ParsingInstructions.java create mode 100644 bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/parsing/TypeParser.java diff --git a/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/HtmlService.java b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/HtmlService.java index 91c25be5..8f8611c4 100644 --- a/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/HtmlService.java +++ b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/HtmlService.java @@ -58,31 +58,41 @@ public static Element findElement(String html, String cssQuery) { } public static String getAbsoluteXPath(Element element) { - StringBuilder xpath = new StringBuilder("/"); + StringBuilder xpath = new StringBuilder(); - for (Element el : element.parents()) { - - if (el.tagName().equals("html") || el.tagName().equals("body")) { + Element currentElement = element; + while (currentElement != null) { + if (currentElement.tagName().equals("html") || currentElement.tagName().equals("body") || currentElement.tagName().startsWith("#")) { // ignore the and , because jsoup added them to the html fragment - continue; + break; } - int index = 1; - for (Element sibling : el.siblingElements()) { - if (sibling.tagName().equals(el.tagName())) { - index++; - } - } + xpath.insert(0, indexElement(currentElement)); - if (index == 1) xpath.insert(0, "/" + el.tagName()); - else xpath.insert(0, "/" + el.tagName() + "[" + index + "]"); + currentElement = currentElement.parent(); } - xpath.append(element.tagName()); - return xpath.toString(); } + private String indexElement(Element element) { + int index = 1; + + Element previousSibling = element.previousElementSibling(); + while (previousSibling != null) { + if (previousSibling.tagName().equals(element.tagName())) { + index++; + } + previousSibling = previousSibling.previousElementSibling(); + } + + if (index == 1) { + return "/" + element.tagName(); + } else { + return "/" + element.tagName() + "[" + index + "]"; + } + } + private static String findElementAbsoluteXpath(String html, String xpath) { var doc = Jsoup.parse(html); var el = doc.selectXpath(xpath); diff --git a/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/TypeParser.java b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/TypeParser.java deleted file mode 100644 index 2b3229aa..00000000 --- a/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/TypeParser.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2024 Automate The Planet Ltd. - * Author: Miriam Kyoseva - * Licensed under the Apache License, Version 2.0 (the "License"); - * You may not use this file except in compliance with the License. - * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package solutions.bellatrix.core.utilities; - -import lombok.SneakyThrows; -import lombok.experimental.UtilityClass; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.HashMap; -import java.util.Map; -import java.util.function.Function; - -/** - * Utility class that contains instructions how to convert from one type to another. - */ -@UtilityClass -@SuppressWarnings("unchecked") -public class TypeParser { - private static final SpecificInstructions STRING_ALLOWED_OPERATIONS = new SpecificInstructions<>((Map, Function>) (Map) Map.ofEntries( - Map.entry(String.class, (Function) (x) -> x), - Map.entry(Integer.class, (Function) Integer::parseInt), - Map.entry(Double.class, (Function) Double::parseDouble), - Map.entry(Float.class, (Function) Float::parseFloat), - Map.entry(Byte.class, (Function) Byte::parseByte), - Map.entry(Long.class, (Function) Long::parseLong), - Map.entry(Short.class, (Function) Short::parseShort), - Map.entry(Boolean.class, (Function) Boolean::parseBoolean), - Map.entry(Character.class, (Function) (x) -> x.charAt(0)), - Map.entry(BigDecimal.class, (Function) BigDecimal::new), - Map.entry(BigInteger.class, (Function) BigInteger::new) - )); - - /** - * Instructions for converting from one type to another.
- * You can specify it statically here, or you could add new instructions dynamically via {@link Map#put(Object, Object)} - */ - public static InstructionsCollection ALLOWED_OPERATIONS = new InstructionsCollection<>(Map.ofEntries( - Map.entry(String.class, STRING_ALLOWED_OPERATIONS) - )); - - /** - * Checks for enum fields containing the specified value and prioritizes which enum value to return by the field, - * instead of the name of the enum value. - */ - @SuppressWarnings("unchecked") - @SneakyThrows - public static T parseEnumValue(String value, Class enumClass) { - var fields = enumClass.getDeclaredFields(); - for (T enumConstant : enumClass.getEnumConstants()) { - for (var field : fields) { - field.setAccessible(true); - Object fieldValue = field.get(enumConstant); - if (fieldValue != null && fieldValue.toString().equals(value)) { - return enumConstant; - } - } - } - - return (T) Enum.valueOf((Class)enumClass, value); - } - - // TODO: RENAME ME - public class SpecificInstructions extends HashMap, Function> { - public SpecificInstructions(Map, Function> map) { - super(map); - } - - public Function to(Class clazz) { - return this.get(clazz); - } - } - - // TODO: RENAME ME - public class InstructionsCollection extends HashMap, T> { - public InstructionsCollection(Map, T> map) { - super(map); - } - - public T from(Class clazz) { - return this.get(clazz); - } - } -} diff --git a/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/parsing/ParsingInstructions.java b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/parsing/ParsingInstructions.java new file mode 100644 index 00000000..7da08d7a --- /dev/null +++ b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/parsing/ParsingInstructions.java @@ -0,0 +1,31 @@ +package solutions.bellatrix.core.utilities.parsing; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +@SuppressWarnings({"unchecked", "rawtypes"}) +// TODO: RENAME ME +public class ParsingInstructions extends HashMap, Function> { + public ParsingInstructions() { + super(); + } + + public ParsingInstructions(Map, Function> map) { + super(map); + } + + public ParsingInstructions add(Class toClass, Function parsingInstructions) { + // TODO: EventHandler<> for changing existing instructions + super.put(toClass, parsingInstructions); + return this; + } + + public Function get(Class clazz) { + return super.get(clazz); + } + + public static ParsingInstructions ofEntries(Entry, Function>... entries) { + return new ParsingInstructions(Map.ofEntries(entries)); + } +} \ No newline at end of file diff --git a/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/parsing/TypeParser.java b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/parsing/TypeParser.java new file mode 100644 index 00000000..7aa8cbaa --- /dev/null +++ b/bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/parsing/TypeParser.java @@ -0,0 +1,250 @@ +/* + * Copyright 2024 Automate The Planet Ltd. + * Author: Miriam Kyoseva + * Licensed under the Apache License, Version 2.0 (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package solutions.bellatrix.core.utilities.parsing; + +import lombok.SneakyThrows; +import lombok.experimental.UtilityClass; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; + +/** + * Utility class that contains instructions how to convert from one type to another. + */ +@UtilityClass +@SuppressWarnings({"unchecked", "rawtypes"}) +public class TypeParser { + /** + * Checks for enum fields containing the specified value and prioritizes which enum value to return by the field, + * instead of the name of the enum value. + */ + @SneakyThrows + public static T parseEnumValue(Object value, Class enumClass) { + var fields = enumClass.getDeclaredFields(); + + for (T enumConstant : enumClass.getEnumConstants()) { + for (var field : fields) { + if (field.getClass() == value.getClass()) { + field.setAccessible(true); + Object fieldValue = field.get(enumConstant); + if (fieldValue != null && fieldValue.equals(value)) { + return enumConstant; + } + } + } + } + if (value.getClass() == String.class) { + return (T) Enum.valueOf((Class)enumClass, (String)value); + } else { + // TODO: EventHandler<> for failing to parse enum. + return null; + } + } + + /** + * Checks if instructions for parsing the value to the given class exist and uses them.
+ * In case instructions aren't provided, you can provide them dynamically in your code through {@link #instruct(Class, Class, Function)} + */ + public static T parse(Object value, Class clazz) { + var originalClass = value.getClass(); + + if (clazz == null) { + throw new IllegalArgumentException("Class cannot be null."); + } + + Function operation = TypeParser.ALLOWED_OPERATIONS.get(originalClass).get(clazz); + + if (operation != null) { + return operation.apply(value); + } else if (clazz.isEnum()) { + Function enumOperation = x -> TypeParser.parseEnumValue(x, clazz); + TypeParser.ALLOWED_OPERATIONS.get(String.class).add(clazz, enumOperation); + return enumOperation.apply(value); + } else { + throw new IllegalArgumentException("Unsupported class type: " + clazz.getName() + + "\nYou can add a custom type parser in " + TypeParser.class.getName()); + } + } + + public static void instruct(Class fromClass, Class toClass, Function instructions) { + if (ALLOWED_OPERATIONS.containsKey(fromClass)) { + ALLOWED_OPERATIONS.get(fromClass).add(toClass, instructions); + } else { + Objects.requireNonNull(ALLOWED_OPERATIONS.put(fromClass, new ParsingInstructions<>())).add(toClass, instructions); + } + } + + public static void instruct(Class fromClass, Map.Entry, Function>... entries) { + var map = ParsingInstructions.ofEntries(entries); + + if (ALLOWED_OPERATIONS.containsKey(fromClass)) { + ALLOWED_OPERATIONS.get(fromClass).putAll(map); + } else { + Objects.requireNonNull(ALLOWED_OPERATIONS.put(fromClass, new ParsingInstructions<>())).putAll(map); + } + } + + private static final ParsingInstructions STRING_ALLOWED_OPERATIONS = ParsingInstructions.ofEntries( + Map.entry(String.class, (Function) (x) -> x), + Map.entry(Integer.class, (Function) Integer::parseInt), + Map.entry(Double.class, (Function) Double::parseDouble), + Map.entry(Float.class, (Function) Float::parseFloat), + Map.entry(Byte.class, (Function) Byte::parseByte), + Map.entry(Long.class, (Function) Long::parseLong), + Map.entry(Short.class, (Function) Short::parseShort), + Map.entry(Boolean.class, (Function) Boolean::parseBoolean), + Map.entry(Character.class, (Function) (x) -> x.charAt(0)), + Map.entry(BigDecimal.class, (Function) BigDecimal::new), + Map.entry(BigInteger.class, (Function) BigInteger::new) + // TODO: to DateTime + // TODO: to Date + ); + + private static final ParsingInstructions INTEGER_ALLOWED_OPERATIONS = ParsingInstructions.ofEntries( + Map.entry(Integer.class, (Function)(x) -> x), + Map.entry(String.class, (Function)String::valueOf), + Map.entry(Double.class, (Function)Integer::doubleValue), + Map.entry(Float.class, (Function)Integer::floatValue), + Map.entry(Byte.class, (Function)Integer::byteValue), + Map.entry(Long.class, (Function)Integer::longValue), + Map.entry(Short.class, (Function)Integer::shortValue), + Map.entry(Character.class, (Function)(x) -> String.valueOf(x).charAt(0)), + Map.entry(BigDecimal.class, (Function)BigDecimal::valueOf), + Map.entry(BigInteger.class, (Function)BigInteger::valueOf) + ); + + private static final ParsingInstructions DOUBLE_ALLOWED_OPERATIONS = ParsingInstructions.ofEntries( + Map.entry(Double.class, (Function)(x) -> x), + Map.entry(String.class, (Function)String::valueOf), + Map.entry(Integer.class, (Function)Double::intValue), + Map.entry(Float.class, (Function)Double::floatValue), + Map.entry(Byte.class, (Function)Double::byteValue), + Map.entry(Long.class, (Function)Double::longValue), + Map.entry(Short.class, (Function)Double::shortValue), + Map.entry(Character.class, (Function)(x) -> String.valueOf(x).charAt(0)), + Map.entry(BigDecimal.class, (Function)BigDecimal::valueOf), + Map.entry(BigInteger.class, (Function)(x) -> BigInteger.valueOf(x.intValue())) + ); + + private static final ParsingInstructions FLOAT_ALLOWED_OPERATIONS = ParsingInstructions.ofEntries( + Map.entry(Float.class, (Function)(x) -> x), + Map.entry(String.class, (Function)String::valueOf), + Map.entry(Integer.class, (Function)Float::intValue), + Map.entry(Double.class, (Function)Float::doubleValue), + Map.entry(Byte.class, (Function)Float::byteValue), + Map.entry(Long.class, (Function)Float::longValue), + Map.entry(Short.class, (Function)Float::shortValue), + Map.entry(Character.class, (Function)(x) -> String.valueOf(x).charAt(0)), + Map.entry(BigDecimal.class, (Function)BigDecimal::valueOf), + Map.entry(BigInteger.class, (Function)(x) -> BigInteger.valueOf(x.intValue())) + ); + + private static final ParsingInstructions BYTE_ALLOWED_OPERATIONS = ParsingInstructions.ofEntries( + Map.entry(Byte.class, (Function)(x) -> x), + Map.entry(String.class, (Function)String::valueOf), + Map.entry(Integer.class, (Function)Byte::intValue), + Map.entry(Double.class, (Function)Byte::doubleValue), + Map.entry(Float.class, (Function)Byte::floatValue), + Map.entry(Long.class, (Function)Byte::longValue), + Map.entry(Short.class, (Function)Byte::shortValue), + Map.entry(Character.class, (Function)(x) -> String.valueOf(x).charAt(0)), + Map.entry(BigDecimal.class, (Function)BigDecimal::valueOf), + Map.entry(BigInteger.class, (Function)(x) -> BigInteger.valueOf(x.intValue())) + ); + + private static final ParsingInstructions LONG_ALLOWED_OPERATIONS = ParsingInstructions.ofEntries( + Map.entry(Long.class, (Function)(x) -> x), + Map.entry(String.class, (Function)String::valueOf), + Map.entry(Integer.class, (Function)Long::intValue), + Map.entry(Double.class, (Function)Long::doubleValue), + Map.entry(Float.class, (Function)Long::floatValue), + Map.entry(Byte.class, (Function)Long::byteValue), + Map.entry(Short.class, (Function)Long::shortValue), + Map.entry(Character.class, (Function)(x) -> String.valueOf(x).charAt(0)), + Map.entry(BigDecimal.class, (Function)BigDecimal::valueOf), + Map.entry(BigInteger.class, (Function)(x) -> BigInteger.valueOf(x.intValue())) + ); + + private static final ParsingInstructions SHORT_ALLOWED_OPERATIONS = ParsingInstructions.ofEntries( + Map.entry(Short.class, (Function)(x) -> x), + Map.entry(String.class, (Function)String::valueOf), + Map.entry(Integer.class, (Function)Short::intValue), + Map.entry(Double.class, (Function)Short::doubleValue), + Map.entry(Float.class, (Function)Short::floatValue), + Map.entry(Byte.class, (Function)Short::byteValue), + Map.entry(Long.class, (Function)Short::longValue), + Map.entry(Character.class, (Function)(x) -> String.valueOf(x).charAt(0)), + Map.entry(BigDecimal.class, (Function)BigDecimal::valueOf), + Map.entry(BigInteger.class, (Function)(x) -> BigInteger.valueOf(x.intValue())) + ); + + private static final ParsingInstructions CHARACTER_ALLOWED_OPERATIONS = ParsingInstructions.ofEntries( + Map.entry(Character.class, (Function)(x) -> x), + Map.entry(String.class, (Function)String::valueOf), + Map.entry(Integer.class, (Function)Integer::valueOf), + Map.entry(Double.class, (Function)Double::valueOf), + Map.entry(Float.class, (Function)Float::valueOf), + Map.entry(Byte.class, (Function)(x) -> Byte.valueOf(String.valueOf(x))), + Map.entry(Long.class, (Function)Long::valueOf), + Map.entry(Short.class, (Function)(x) -> Short.valueOf(String.valueOf(x))), + Map.entry(BigDecimal.class, (Function)BigDecimal::valueOf), + Map.entry(BigInteger.class, (Function)(x) -> new BigInteger(String.valueOf(x))) + ); + + private static final ParsingInstructions BIG_DECIMAL_ALLOWED_OPERATIONS = ParsingInstructions.ofEntries( + Map.entry(BigDecimal.class, (Function)(x) -> x), + Map.entry(String.class, (Function)String::valueOf), + Map.entry(Integer.class, (Function)BigDecimal::intValue), + Map.entry(Double.class, (Function)BigDecimal::doubleValue), + Map.entry(Float.class, (Function)BigDecimal::floatValue), + Map.entry(Byte.class, (Function)BigDecimal::byteValue), + Map.entry(Long.class, (Function)BigDecimal::longValue), + Map.entry(Short.class, (Function)BigDecimal::shortValue), + Map.entry(Character.class, (Function)(x) -> String.valueOf(x).charAt(0)), + Map.entry(BigInteger.class, (Function)(x) -> new BigInteger(String.valueOf(x))) + ); + + private static final ParsingInstructions BIG_INTEGER_ALLOWED_OPERATIONS = ParsingInstructions.ofEntries( + Map.entry(BigInteger.class, (Function)(x) -> x), + Map.entry(String.class, (Function)String::valueOf), + Map.entry(Integer.class, (Function)BigInteger::intValue), + Map.entry(Double.class, (Function)BigInteger::doubleValue), + Map.entry(Float.class, (Function)BigInteger::floatValue), + Map.entry(Byte.class, (Function)BigInteger::byteValue), + Map.entry(Long.class, (Function)BigInteger::longValue), + Map.entry(Short.class, (Function)BigInteger::shortValue), + Map.entry(Character.class, (Function)(x) -> String.valueOf(x).charAt(0)), + Map.entry(BigDecimal.class, (Function)(x) -> new BigDecimal(String.valueOf(x))) + ); + + /** + * Instructions for converting from one type to another.
+ * You can specify it statically here, or you could add new instructions dynamically via {@link #instruct(Class, Class, Function)} + */ + private static Map ALLOWED_OPERATIONS = Map.ofEntries( + Map.entry(String.class, STRING_ALLOWED_OPERATIONS), + Map.entry(Integer.class, INTEGER_ALLOWED_OPERATIONS), + Map.entry(Double.class, DOUBLE_ALLOWED_OPERATIONS), + Map.entry(Float.class, FLOAT_ALLOWED_OPERATIONS), + Map.entry(Byte.class, BYTE_ALLOWED_OPERATIONS), + Map.entry(Long.class, LONG_ALLOWED_OPERATIONS), + Map.entry(Short.class, SHORT_ALLOWED_OPERATIONS), + Map.entry(Character.class, CHARACTER_ALLOWED_OPERATIONS), + Map.entry(BigDecimal.class, BIG_DECIMAL_ALLOWED_OPERATIONS), + Map.entry(BigInteger.class, BIG_INTEGER_ALLOWED_OPERATIONS) + ); +} From 20e55dc57edbad420fa27640b4959411be671fd7 Mon Sep 17 00:00:00 2001 From: MiriamKyoseva <133047546+MiriamKyoseva@users.noreply.github.com> Date: Fri, 14 Jun 2024 17:40:17 +0300 Subject: [PATCH 26/94] Table fixes --- .../web/components/advanced/table/Table.java | 36 ++++--------------- .../components/advanced/table/TableCell.java | 7 ++-- .../components/advanced/table/TableRow.java | 3 +- 3 files changed, 10 insertions(+), 36 deletions(-) diff --git a/bellatrix.web/src/main/java/solutions/bellatrix/web/components/advanced/table/Table.java b/bellatrix.web/src/main/java/solutions/bellatrix/web/components/advanced/table/Table.java index 113d77af..13ab4562 100644 --- a/bellatrix.web/src/main/java/solutions/bellatrix/web/components/advanced/table/Table.java +++ b/bellatrix.web/src/main/java/solutions/bellatrix/web/components/advanced/table/Table.java @@ -16,22 +16,19 @@ import lombok.Getter; import lombok.Setter; import solutions.bellatrix.core.assertions.EntitiesAsserter; -import solutions.bellatrix.core.utilities.TypeParser; import solutions.bellatrix.core.utilities.HtmlService; +import solutions.bellatrix.core.utilities.parsing.TypeParser; import solutions.bellatrix.core.utilities.InstanceFactory; import solutions.bellatrix.web.components.Label; import solutions.bellatrix.web.components.WebComponent; import solutions.bellatrix.web.components.advanced.*; -import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.Consumer; -import java.util.function.Function; import java.util.function.Predicate; public class Table extends WebComponent { @@ -74,10 +71,12 @@ public int getRowsCount() { @Getter @Setter private List columnHeaderNames; + // TODO: reuse TableService public List