diff --git a/CHANGELOG.md b/CHANGELOG.md index 50d57f2..c1eb3cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,20 @@ +## [4.10.0](https://github.com/extent-framework/extentreports-java/compare/v4.0.9...v4.1.0) +#### Improvements +* [#18] Steps count in dashboard displays 0 even though there are logged steps +* [#94] Cleanup tag view naming +* [#103] AppendExisting functionality similar to version 3 API, via `JsonFormatter` and `ExtentReports::createDomainFromJsonArchive`: +```java +JsonFormatter json = new JsonFormatter("target/test.json"); +extent.attachReporter(json); +extent.createDomainFromJsonArchive("target/test.json"); +``` +* [#107] ExtentSparkReporter's default view is SPA, similar to V3HtmlReporter. This can be changed by instantiating as `new ExtentSparkReporter("dir", ViewStyle.DEFAULT);` +* [#108] All resources migrated to jsDelivr + +#### Fixes +* [#57] ExtentKlovReporter: Screenshot cannot be saved in base64 format +* [#101] Fixes Freemarker templating error + ## [4.0.9](https://github.com/extent-framework/extentreports-java/compare/v4.0.8...v4.0.9) #### Improvements * [#35] HtmlReporter, BDD: description to appear as tooltip instead of newline diff --git a/Contributing.md b/Contributing.md new file mode 100644 index 0000000..32c2428 --- /dev/null +++ b/Contributing.md @@ -0,0 +1,49 @@ +# Reporting a Bug + +The way you report a bug is the most critical part for a quick resolution. Bugs which lack clear description and steps to reproduce are often not fixed. If you find a bug please make sure that you log the bug based on the template below. Make sure that you are as descriptive as possible. + +## Bug Template + +### Title: Line of text which summarizes what the bug is about. (Max 70 characters) + +- Be short and precise +- Use simple language and grammar +- Summarize what the issue is and nothing else + +### Description: Describe the issue in a few lines using simple words + +While describing a bug consider that you are describing it to someone who knows nothing about your problem. Be as elaborate as possible but avoid being verbose. Being verbose here would mean. +- Providing unnecessary details without which the bug can still be described. + +In most of the cases, try to understand the bug in such a way that you can separate program can be written just to reproduce the issue. If you are not able to understand the bug at this moment, just try to recreate the problem with simplest possible code. + +### Things to include in the Description +- What went wrong? for e.g. Adding a long description to a test results in truncation of the text. +- When it went wrong? for e.g. If you add a text description which is greater than 255 characters, the description text gets truncated + +Things to NOT include in the Description +- You application specific details. For example, do not give elaborate background on what your application does. +- Talking about functions/code which is very specific to your project. We would not know about that. + +### Steps to Reproduce: +- Detailed and precise steps to reproduce the bugs. +- Make sure that preconditions are specified. For e.g. include a particular library or tool which is necessary to reproduce the scenario. +- If possible you can attach images with annotations explaining where the problem is. +- If possible create a piece of code which can reproduce the issue without having any of your application/framework code. + +### Expected Results +In the end make sure that you clearly explain what were you expecting. Being very clear here is the key. + + +# What happens after you have logged the bug? + +We look at bugs periodically. As this is an open source project, we invest time based on the availability. You can expect a reply within 2 - 3 days. If you donot get a reply, please add any of the contributors in the list. + +You can also raise a PR if you know the fix. PR's are always welcome. Please see the code contribution guidelines below. + + + + + + + diff --git a/config/spark-config.xml b/config/spark-config.xml index 0d40510..5da2252 100644 --- a/config/spark-config.xml +++ b/config/spark-config.xml @@ -14,6 +14,9 @@ https + + false + Extent Framework diff --git a/config/v3html-config.xml b/config/v3html-config.xml index 0d40510..5da2252 100644 --- a/config/v3html-config.xml +++ b/config/v3html-config.xml @@ -14,6 +14,9 @@ https + + false + Extent Framework diff --git a/pom-nexus.xml b/pom-nexus.xml index 04f82ab..7c091b2 100644 --- a/pom-nexus.xml +++ b/pom-nexus.xml @@ -1,10 +1,11 @@ - 4.0.0 com.aventstack extentreports - 4.0.9 + 4.1.2-SNAPSHOT extentreports www.extentreports.com @@ -18,8 +19,8 @@ - The BSD 3-Clause License - http://opensource.org/licenses/BSD-3-Clause + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt @@ -36,7 +37,7 @@ UTF-8 - 3.3.0 + 3.12.0 4.5.2 @@ -44,17 +45,7 @@ org.freemarker freemarker - 2.3.23 - - - org.mongodb - mongodb-driver - ${mongodb.version} - - - org.mongodb - bson - ${mongodb.version} + 2.3.29 org.apache.httpcomponents @@ -69,7 +60,17 @@ com.google.code.gson gson - 2.8.5 + 2.8.6 + + + org.mongodb + mongodb-driver + ${mongodb.version} + + + org.mongodb + bson + ${mongodb.version} org.testng @@ -159,7 +160,7 @@ - 7A7DAF8A + 41414BBD anshooarora diff --git a/pom.xml b/pom.xml index fb167f9..ed96e71 100644 --- a/pom.xml +++ b/pom.xml @@ -1,10 +1,11 @@ - 4.0.0 com.aventstack extentreports - 4.0.9 + 4.1.2-SNAPSHOT extentreports www.extentreports.com @@ -18,8 +19,8 @@ - The BSD 3-Clause License - http://opensource.org/licenses/BSD-3-Clause + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt @@ -36,7 +37,7 @@ UTF-8 - 3.3.0 + 3.12.0 4.5.2 @@ -44,17 +45,7 @@ org.freemarker freemarker - 2.3.23 - - - org.mongodb - mongodb-driver - ${mongodb.version} - - - org.mongodb - bson - ${mongodb.version} + 2.3.29 org.apache.httpcomponents @@ -69,12 +60,22 @@ com.google.code.gson gson - 2.8.5 + 2.8.6 + + + org.mongodb + mongodb-driver + ${mongodb.version} + + + org.mongodb + bson + ${mongodb.version} org.testng testng - 6.9.10 + 6.14.3 test diff --git a/src/main/java/com/aventstack/extentreports/AnalysisStrategy.java b/src/main/java/com/aventstack/extentreports/AnalysisStrategy.java index aff7853..fdfca02 100644 --- a/src/main/java/com/aventstack/extentreports/AnalysisStrategy.java +++ b/src/main/java/com/aventstack/extentreports/AnalysisStrategy.java @@ -5,15 +5,12 @@ *

* Available strategies are: *

    - *
  • BDD: Strategy for BDD-style (Gherkin) tests
  • - *
  • CLASS: Used for 2 levels: Class, Test
  • - *
  • SUITE: Used for 3 levels: Suite, Class, Test
  • - *
  • TEST: Used for 1 level only: Test
  • + *
  • BDD: Strategy for BDD-style (Gherkin) tests
  • + *
  • CLASS: Used for 2 levels: Class, Test
  • + *
  • SUITE: Used for 3 levels: Suite, Class, Test
  • + *
  • TEST: Used for 1 level only: Test
  • *
*/ public enum AnalysisStrategy { - BDD, - CLASS, - SUITE, - TEST -} + BDD, CLASS, SUITE, TEST +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/ExceptionTestContextImpl.java b/src/main/java/com/aventstack/extentreports/ExceptionTestContextImpl.java deleted file mode 100644 index 502ca35..0000000 --- a/src/main/java/com/aventstack/extentreports/ExceptionTestContextImpl.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.aventstack.extentreports; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -import com.aventstack.extentreports.model.ExceptionInfo; -import com.aventstack.extentreports.model.ExceptionTestContext; -import com.aventstack.extentreports.model.Test; - -/** - * Provides and tracks the collection of tests segregated by the type of {@link Exception} - * - */ -public class ExceptionTestContextImpl { - private List exTestContextList; - - public ExceptionTestContextImpl() { - exTestContextList = new ArrayList<>(); - } - - public void setExceptionContext(ExceptionInfo ei, Test test) { - Optional exOptionalTestContext = exTestContextList - .stream() - .filter(x -> x.getExceptionInfo().getExceptionName().equals(ei.getExceptionName())) - .findFirst(); - - if (exOptionalTestContext.isPresent()) { - List testList = exOptionalTestContext.get().getTestList(); - - boolean b = testList.stream() - .anyMatch(t -> t.getID() == test.getID()); - - if (!b) { - exOptionalTestContext.get().setTest(test); - } - } - else { - ExceptionTestContext exTestContext = new ExceptionTestContext(ei); - exTestContext.setTest(test); - exTestContextList.add(exTestContext); - } - } - - public List getExceptionTestContextList() { - return exTestContextList; - } -} diff --git a/src/main/java/com/aventstack/extentreports/ExtentObservable.java b/src/main/java/com/aventstack/extentreports/ExtentObservable.java deleted file mode 100644 index 266dbb5..0000000 --- a/src/main/java/com/aventstack/extentreports/ExtentObservable.java +++ /dev/null @@ -1,611 +0,0 @@ -package com.aventstack.extentreports; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.EnumMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import com.aventstack.extentreports.model.Author; -import com.aventstack.extentreports.model.Category; -import com.aventstack.extentreports.model.Device; -import com.aventstack.extentreports.model.Log; -import com.aventstack.extentreports.model.ScreenCapture; -import com.aventstack.extentreports.model.Screencast; -import com.aventstack.extentreports.model.SystemAttribute; -import com.aventstack.extentreports.model.Test; -import com.aventstack.extentreports.reporter.BasicFileReporter; - -abstract class ExtentObservable - implements ReportService { - - /** - * The current AnalysisStrategy for the run session. This decides the technique used - * to count the test status at differing levels. For example, for a BDD style report, - * the levels to be calculated are Feature, Scenario and Step (3 levels). For a generic, - * non-BDD style report, levels can be dynamic. For a non-BDD style report, levels typically - * consist of: - * - *

- * 1 level: Test
- * Test
- * - Event - * - *

- * 2 levels: Test & node
- * Test
- Node
-- Event - * - *

- * 2 levels: Test, the leaf-node
- * Test
- Node
-- Leaf Node
--- Event - * - */ - private AnalysisStrategy strategy = AnalysisStrategy.TEST; - - /** - * Use this setting when building post-execution reports, such as from TestNG IReporter. - * This setting allows setting test with your own variables and prevent update by Extent. - * As of today, with this enabled, Extent does not use time-stamps for tests at the time - * they were created - */ - private boolean usesManualConfiguration = false; - - /** - * The status of the entire report or build - */ - private Status reportStatus = Status.PASS; - - /** - * Time the report or build was started - */ - private Date reportStartDate = Calendar.getInstance().getTime(); - - /** - * Time the report or build ended. This value is updated everytime flush - * is called - */ - private Date reportEndDate; - - /** - * A collection of tests arranged by category - */ - private TestAttributeTestContextProvider categoryContext = new TestAttributeTestContextProvider<>(); - - /** - * A collection of tests arranged by author - */ - private TestAttributeTestContextProvider authorContext = new TestAttributeTestContextProvider<>(); - - /** - * A collection of tests arranged by author - */ - private TestAttributeTestContextProvider deviceContext = new TestAttributeTestContextProvider<>(); - - - /** - * A collection of tests arranged by exception - */ - private ExceptionTestContextImpl exceptionContextBuilder = new ExceptionTestContextImpl(); - - /** - * A context of all system or environment variables - */ - private SystemAttributeContext systemAttributeContext = new SystemAttributeContext(); - - /** - * A list of all {@link ExtentReporter} reporters started by the attachReporter - * method - */ - private List reporterList = new ArrayList<>(); - - /** - * Any logs added by to the test runner can be added to Extent - * - *

- * TestNG Example: - * - *

- * Setting logs with TestNG: - * - *

Reporter.log("hello world")
- * - *

- * Informing Extent of any logs added: - *

-	 * for (String s : Reporter.getOutput()) {
-     *       extent.setTestRunnerOutput(s);
-     * }
-     * 
- */ - private List testRunnerLogs = new ArrayList<>(); - - /** - * A list of all tests created - */ - private List testList = new ArrayList<>(); - - /** - * Instance of {@link ReportStatusStats} - */ - private ReportStatusStats stats = new ReportStatusStats(strategy); - - /** - * A unique list of status tests are marked with - * - *

- * Consider a report having 10 tests: - * - *

    - *
  1. Test1: PASS
  2. - *
  3. Test2: PASS
  4. - *
  5. Test3: PASS
  6. - *
  7. Test4: SKIP
  8. - *
  9. Test5: SKIP
  10. - *
  11. Test6: FAIL
  12. - *
  13. Test7: PASS
  14. - *
  15. Test8: PASS
  16. - *
  17. Test9: FAIL
  18. - *
  19. Test10: PASS
  20. - *
- * - *

- * Distinct list of contained status: - * - *

    - *
  1. PASS
  2. - *
  3. SKIP
  4. - *
  5. FAIL
  6. - *
- */ - private List statusList = new ArrayList<>(); - - /** - * Contains status as keys, which are translated over to statusList - */ - private Map statusMap = new EnumMap<>(Status.class); - - protected ExtentObservable() { } - - /** - * Subscribe the reporter to receive updates when making calls to the API - * - * @param reporter {@link ExtentReporter} reporter - */ - protected void register(ExtentReporter reporter) { - reporterList.add(reporter); - reporter.start(); - } - - /** - * Unsubscribe the reporter. Calling unsubscribe will call the stop method - * and also remove the reporter from the list of started reporters - * - * @param reporter {@link ExtentReporter} reporter to unsubscribe - */ - protected void deregister(ExtentReporter reporter) { - reporter.stop(); - reporterList.remove(reporter); - } - - /** - * Retrieve a list of all started reporters - * - * @return a list of {@link ExtentReporter} objects - */ - protected List getReporterCollection() { - return reporterList; - } - - /** - * Saves the started test and notifies all started reporters - * - * @param test a {@link Test} object - */ - protected synchronized void saveTest(Test test) { - testList.add(test); - reporterList.forEach(x -> x.onTestStarted(test)); - } - - /** - * Removes the test and notifies all started reporters - * - * @param test a {@link Test} object - */ - protected synchronized void removeTest(Test test) { - removeTestTestList(test); - removeTestTestAttributeContext(test); - reporterList.forEach(x -> x.onTestRemoved(test)); - } - - /** - * Removes a test from test list - * - * @param test a {@link Test} object - */ - private void removeTestTestList(Test test) { - TestRemover.remove(testList, test); - refreshReportEntities(); - } - - /** - * Removes test from test list of each context - * - * @param test a {@link Test} object - */ - private void removeTestTestAttributeContext(Test test) { - if (test.hasCategory()) { - categoryContext.removeTest(test); - } - if (test.hasAuthor()) { - authorContext.removeTest(test); - } - if (test.hasDevice()) { - deviceContext.removeTest(test); - } - } - - /** - * Refreshes report entities such as {@link ReportStatusStats} and list of distinct {@link Status} - */ - private void refreshReportEntities() { - refreshReportStats(); - refreshStatusList(); - } - - /** - * Refresh and notify all reports of {@link ReportStatusStats} - */ - private void refreshReportStats() { - stats.refresh(testList); - } - - /** - * Refresh and notify all reports of distinct status assigned to tests - */ - private void refreshStatusList() { - statusMap.clear(); - statusList.clear(); - refreshStatusList(testList); - statusMap.forEach((k,v) -> statusList.add(k)); - } - - /** - * Refreshes distinct status list - * - * @param list a list of started {@link Test} - */ - private void refreshStatusList(List list) { - if (list == null || list.isEmpty()) - return; - - list.stream() - .map(Test::getStatus) - .distinct() - .collect(Collectors.toList()) - .forEach(x -> statusMap.put(x, false)); - - list.forEach(x -> refreshStatusList(x.getNodeContext().getAll())); - } - - /** - * Notify reporters of the added node - * - * @param node a {@link Test} node - */ - synchronized void addNode(Test node) { - reporterList.forEach(x -> x.onNodeStarted(node)); - } - - /** - * Notifies reporters with information of added {@link Log} - * - * @param test {@link Test} to which the event is added - * @param log {@link Log} - */ - synchronized void addLog(Test test, Log log) { - collectRunInfo(); - reporterList.forEach(x -> x.onLogAdded(test, log)); - } - - /** - * Notifies reporters with information of added {@link Category} - * - * @param test {@link Test} to which the Category is added - * @param category {@link Category} - */ - synchronized void assignCategory(Test test, Category category) { - reporterList.forEach(x -> x.onCategoryAssigned(test, category)); - } - - /** - * Notifies reporters with information of added {@link Author} - * - * @param test {@link Test} to which the Author is added - * @param author {@link Author} - */ - synchronized void assignAuthor(Test test, Author author) { - reporterList.forEach(x -> x.onAuthorAssigned(test, author)); - } - - /** - * Notifies reporters with information of added {@link Author} - * - * @param test {@link Test} to which the Device is added - * @param device {@link Device} - */ - synchronized void assignDevice(Test test, Device device) { - reporterList.forEach(x -> x.onDeviceAssigned(test, device)); - } - - /** - * Notifies reporters with information of added {@link ScreenCapture} - * - * @param test {@link Test} to which the ScreenCapture is added - * @param screenCapture {@link ScreenCapture} - * - * @throws IOException thrown if the {@link ScreenCapture} is not found - */ - synchronized void addScreenCapture(Test test, ScreenCapture screenCapture) throws IOException { - for (ExtentReporter r : reporterList) { - r.onScreenCaptureAdded(test, screenCapture); - } - } - - /** - * Notifies reporters with information of added {@link ScreenCapture} - * - * @param test {@link Log} to which the ScreenCapture is added - * @param screenCapture {@link ScreenCapture} - * - * @throws IOException thrown if the {@link ScreenCapture} is not found - */ - synchronized void addScreenCapture(Log log, ScreenCapture screenCapture) throws IOException { - for (ExtentReporter r : reporterList) { - r.onScreenCaptureAdded(log, screenCapture); - } - } - - /** - * Notifies reporters with information of added {@link Screencast} - * - * @param test {@link Test} to which the ScreenCast is added - * @param sc {@link Screencast} - * - * @throws IOException thrown if the {@link Screencast} is not found - */ - synchronized void addScreencast(Test test, Screencast screencast) throws IOException { - for (ExtentReporter r : reporterList) { - r.onScreencastAdded(test, screencast); - } - } - - /** - * Returns the context of author with the list of tests for each - * - * @return a {@link TestAttributeTestContextProvider} object - */ - protected TestAttributeTestContextProvider getAuthorContextInfo() { - return authorContext; - } - - /** - * Updates the status of the report or build - * - * @param status a {@link Status} - */ - private void updateReportStatus(Status status) { - int statusIndex = Status.getStatusHierarchy().indexOf(status); - int reportStatusIndex = Status.getStatusHierarchy().indexOf(reportStatus); - - reportStatus = statusIndex < reportStatusIndex - ? status - : reportStatus; - } - - /** - * Ends the test - * - * @param test a {@link Test} object - */ - private void endTest(Test test) { - test.end(); - updateReportStatus(test.getStatus()); - } - - /** - * Collects and updates all run information and notifies all reporters. Depending upon the - * type of reporter, additional events can occur such as: - * - *
    - *
  • A file written to disk (eg. case of {@link BasicFileReporter}
  • - *
  • A database being updated (eg. case of KlovReporter)
  • - *
- */ - protected synchronized void flush() { - collectRunInfo(); - notifyReporters(); - } - - /** - * Collects run information from all tests for assigned {@link Category}, {@link Author}, - * Exception, Nodes. This also ends and updates all internal test information and - * refreshes {@link ReportStatusStats} and the distinct list of {@link Status} - */ - private synchronized void collectRunInfo() { - if (testList == null || testList.isEmpty()) - return; - - reportEndDate = Calendar.getInstance().getTime(); - - refreshReportEntities(); - - for (Test test : testList) { - endTest(test); - test.setUseManualConfiguration(getAllowManualConfig()); - if (test.hasCategory()) { - test.getCategoryContext().getAll() - .forEach(x -> categoryContext.setAttributeContext((Category)x, test)); - } - if (test.hasAuthor()) { - test.getAuthorContext().getAll() - .forEach(x -> authorContext.setAttributeContext((Author)x, test)); - } - if (test.hasDevice()) { - test.getDeviceContext().getAll() - .forEach(x -> deviceContext.setAttributeContext((Device)x, test)); - } - if (test.hasException()) { - test.getExceptionInfoList() - .forEach(x -> exceptionContextBuilder.setExceptionContext(x, test)); - } - if (test.hasChildren()) { - for (Test node : test.getNodeContext().getAll()) { - copyNodeAttributeAndRunTimeInfoToAttributeContexts(node); - node.setUseManualConfiguration(getAllowManualConfig()); - } - } - } - - updateReportStartTimeForManualConfigurationSetting(); - } - - /** - * In case where manual configuration is used, calculate the correct timestamps based upon - * the timestamps assigned to tests - */ - private void updateReportStartTimeForManualConfigurationSetting() { - if (getAllowManualConfig() && !testList.isEmpty()) { - Date minDate = testList.stream() - .map(t -> t.getStartTime()) - .min(Date::compareTo) - .get(); - Date maxDate = testList.stream() - .map(t -> t.getEndTime()) - .max(Date::compareTo) - .get(); - reportStartDate = reportStartDate.getTime() > minDate.getTime() ? minDate : reportStartDate; - reportEndDate = reportEndDate.getTime() < maxDate.getTime() ? maxDate : reportEndDate; - } - } - - /** - * Traverse all nodes and refresh {@link Category}, {@link Author}, Exception and Node context - * information - * - * @param node a {@link Test} node - */ - private void copyNodeAttributeAndRunTimeInfoToAttributeContexts(Test node) { - if (node.hasCategory()) { - node.getCategoryContext().getAll() - .forEach(x -> categoryContext.setAttributeContext((Category)x, node)); - } - if (node.hasAuthor()) { - node.getAuthorContext().getAll() - .forEach(x -> authorContext.setAttributeContext((Author)x, node)); - } - if (node.hasDevice()) { - node.getDeviceContext().getAll() - .forEach(x -> deviceContext.setAttributeContext((Device)x, node)); - } - if (node.hasException()) { - node.getExceptionInfoList() - .forEach(x -> exceptionContextBuilder.setExceptionContext(x, node)); - } - if (node.hasChildren()) { - node.getNodeContext().getAll() - .forEach(this::copyNodeAttributeAndRunTimeInfoToAttributeContexts); - } - } - - /** - * Notify all reporters with complete run information - */ - private synchronized void notifyReporters() { - if (!testList.isEmpty() && testList.get(0).isBehaviorDrivenType()) { - strategy = AnalysisStrategy.BDD; - } - ReportAggregates reportAggregates = new ReportAggregatesBuilder() - .setAuthorContext(authorContext) - .setCategoryContext(categoryContext) - .setDeviceContext(deviceContext) - .setExceptionContext(exceptionContextBuilder) - .setReportStatusStats(stats) - .setStatusList(statusList) - .setSystemAttributeContext(systemAttributeContext) - .setTestList(testList) - .setTestRunnerLogs(testRunnerLogs) - .setStartTime(reportStartDate) - .setEndTime(reportEndDate) - .build(); - reporterList.forEach(x -> x.setAnalysisStrategy(strategy)); - reporterList.forEach(x -> x.flush(reportAggregates)); - } - - /** - * Ends logging, stops and clears the list of reporters - */ - protected void end() { - flush(); - reporterList.forEach(ExtentReporter::stop); - reporterList.clear(); - } - - /** - * Add a system attribute - * - * @param sa a {@link SystemAttribute} object - */ - protected void setSystemInfo(SystemAttribute sa) { - systemAttributeContext.setSystemAttribute(sa); - } - - /** - * Add a test runner log - * - * @param log a log event - */ - protected void setTestRunnerLogs(String log) { - testRunnerLogs.add(log); - } - - /** - * Updates the {@link AnalysisStrategy} - * - * @param strategy a {@link AnalysisStrategy} object - */ - protected void setAnalysisStrategy(AnalysisStrategy strategy) { - this.strategy = strategy; - stats = new ReportStatusStats(strategy); - } - - /** - * Setting to allow user driven configuration for test time-stamps - * - * @param useManualConfig setting for manual configuration - */ - protected void setAllowManualConfig(boolean useManualConfig) { - this.usesManualConfiguration = useManualConfig; - } - - /** - * Returns the current value of using manual configuration for test time-stamps - * - * @return setting for manual configuration - */ - protected boolean getAllowManualConfig() { - return usesManualConfiguration; - } - - /** - * Return the {@link ReportStatusStats} object - * - * @return a {@link ReportStatusStats} object - */ - protected ReportStatusStats getStats() { - return stats; - } - -} diff --git a/src/main/java/com/aventstack/extentreports/ExtentReporter.java b/src/main/java/com/aventstack/extentreports/ExtentReporter.java deleted file mode 100644 index ac5961c..0000000 --- a/src/main/java/com/aventstack/extentreports/ExtentReporter.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.aventstack.extentreports; - -/** - * Primary interface implemented by each reporter. This interface implements {@link TestListener} and - * {@link ReportAggregatesListener} interface to provide additional functionality to each reporter. - */ -public interface ExtentReporter - extends TestListener, AnalysisStrategyService { - - /** - * Starts passing run information to the reporter - */ - void start(); - - /** - * Stops the reporter. Ensures no information is passed to the reporter. - */ - void stop(); - - /** - * Write to or update the target source (file, database) - * - * @param reportAggregates a {@link ReportAggregates} object - */ - void flush(ReportAggregates reportAggregates); - - /** - * Get the reporter name - * - * @return reporter name - */ - String getReporterName(); -} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/ExtentReports.java b/src/main/java/com/aventstack/extentreports/ExtentReports.java index 18e437c..e5f7a77 100644 --- a/src/main/java/com/aventstack/extentreports/ExtentReports.java +++ b/src/main/java/com/aventstack/extentreports/ExtentReports.java @@ -1,22 +1,31 @@ package com.aventstack.extentreports; +import java.io.File; +import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.Arrays; import java.util.List; +import com.aventstack.extentreports.convert.TestModelReportBuilder; import com.aventstack.extentreports.gherkin.GherkinDialectProvider; import com.aventstack.extentreports.gherkin.model.IGherkinFormatterModel; +import com.aventstack.extentreports.model.Media; +import com.aventstack.extentreports.model.ScreenCapture; import com.aventstack.extentreports.model.SystemAttribute; +import com.aventstack.extentreports.reporter.ExtentKlovReporter; +import com.aventstack.extentreports.reporter.ExtentReporter; /** *

- * The ExtentReports report client for starting reporters and building reports. For most applications, - * you should have one ExtentReports instance for the entire JVM. + * The ExtentReports report client for starting reporters and building reports. + * For most applications, you should have one ExtentReports instance for the + * entire JVM. *

* *

- * ExtentReports itself does not build any reports, but allows reporters to access information, which in - * turn build the said reports. An example of building an HTML report and adding information to ExtentX: + * ExtentReports itself does not build any reports, but allows reporters to + * access information, which in turn build the said reports. An example of + * building an HTML report and adding information to ExtentX: *

* *
@@ -32,13 +41,14 @@
  * 
* *

- * A few notes: + * A few notes: *

* *
    - *
  • It is mandatory to call the flush method to ensure information is written to the started - * reporters.
  • - *
  • You can create standard and BDD-style tests using the createTest method
  • + *
  • It is mandatory to call the flush method to ensure + * information is written to the started reporters.
  • + *
  • You can create standard and BDD-style tests using the + * createTest method
  • *
* * @see ExtentTest @@ -46,358 +56,433 @@ * @see IGherkinFormatterModel * @see Status */ -public class ExtentReports - extends ExtentObservable { - - /** - * Attach a {@link ExtentReporter} reporter, allowing it to access all started tests, nodes and logs - * - *

- * Available reporter types are: - *

- * - *
    - *
  • ExtentHtmlReporter provided by artifactId "extent-html-formatter"
  • - *
  • ExtentEmailReporter (pro-only) provided by artifactId "extent-email-formatter"
  • - *
  • KlovReporter provided by artifactId "extent-klov-reporter"
  • - *
  • ConsoleLogger
  • - *
- * - * @param reporter {@link ExtentReporter} reporter - */ - public void attachReporter(ExtentReporter... reporter) { - Arrays.stream(reporter).forEach(this::register); - } - - /** - * Returns a list of started reporters - * - * @return A list of {@link ExtentReporter} - */ - public List getStartedReporters() { - return getReporterCollection(); - } +public class ExtentReports extends ReportObservable { - /** - * Creates a BDD-style test with description representing one of the {@link IGherkinFormatterModel} - * classes such as: - * - *
    - *
  • {@link com.aventstack.extentreports.gherkin.model.Feature}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Background}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Scenario}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Given}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.When}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Then}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.And}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.But}
  • - *
- * - *

- * Example: - *

- * - *
-     * extent.createTest(Feature.class, "feature", "description");
-     * extent.createTest(Scenario.class, "scenario", "description");
-     * extent.createTest(Given.class, "given", "description");
-     * 
- * - * @param type A {@link IGherkinFormatterModel} type - * @param testName Name of test - * @param description A short description of the test - * - * @return {@link ExtentTest} object - */ - public synchronized ExtentTest createTest(Class type, String testName, String description) { - ExtentTest t = new ExtentTest(this, type, testName, description); - applyCommonTestSettings(t); - - saveTest(t.getModel()); - - return t; - } - - /** - * Creates a BDD-style test representing one of the {@link IGherkinFormatterModel} classes such as: - * - *
    - *
  • {@link com.aventstack.extentreports.gherkin.model.Feature}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Background}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Scenario}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Given}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.When}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Then}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.And}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.But}
  • - *
- * - *

- * Example: - *

- * - *
-     * extent.createTest(Feature.class, "feature");
-     * extent.createTest(Scenario.class, "scenario");
-     * extent.createTest(Given.class, "given");
-     * 
- * - * @param type A {@link IGherkinFormatterModel} type - * @param testName Name of test - * - * @return {@link ExtentTest} object - */ - public synchronized ExtentTest createTest(Class type, String testName) { - return createTest(type, testName, null); - } - - /** - * Creates a BDD-style test with description using name of the Gherkin model such as: - * - *
    - *
  • {@link com.aventstack.extentreports.gherkin.model.Feature}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Background}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Scenario}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Given}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.When}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Then}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.And}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.But}
  • - *
- * - *

- * Example: - *

- * - *
-     * extent.createTest(new GherkinKeyword("Feature"), "feature", "description");
-     * extent.createTest(new GherkinKeyword("Scenario"), "scenario", "description");
-     * extent.createTest(new GherkinKeyword("Given"), "given", "description");
-     * 
- * - * @param gherkinKeyword Name of the {@link GherkinKeyword} - * @param testName Name of test - * @param description A short description of the test - * - * @return {@link ExtentTest} object - */ - public synchronized ExtentTest createTest(GherkinKeyword gherkinKeyword, String testName, String description) { - Class clazz = gherkinKeyword.getKeyword().getClass(); - return createTest(clazz, testName, description); - } - - /** - * Creates a BDD-style test using name of the Gherkin model such as: - * - *
    - *
  • {@link com.aventstack.extentreports.gherkin.model.Feature}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Background}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Scenario}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Given}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.When}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Then}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.And}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.But}
  • - *
- * - *

- * Example: - *

- * - *
-     * extent.createTest(new GherkinKeyword("Feature"), "feature");
-     * extent.createTest(new GherkinKeyword("Scenario"), "scenario");
-     * extent.createTest(new GherkinKeyword("Given"), "given");
-     * 
- * - * @param gherkinKeyword Name of the {@link GherkinKeyword} - * @param testName Name of test - * - * @return {@link ExtentTest} object - */ - public synchronized ExtentTest createTest(GherkinKeyword gherkinKeyword, String testName) { - return createTest(gherkinKeyword, testName, null); - } - - /** - * Creates a test with description - * - * @param testName Name of test - * @param description A short test description - * - * @return {@link ExtentTest} object - */ - public synchronized ExtentTest createTest(String testName, String description) { - ExtentTest t = new ExtentTest(this, testName, description); - applyCommonTestSettings(t); - - saveTest(t.getModel()); - - return t; - } + private static final String[] IMAGE_PATH_RESOLVER_DIR = new String[] { "target/", "test-output/" }; + + /** + * Attach a {@link ExtentReporter} reporter, allowing it to access all started + * tests, nodes and logs + * + *

+ * Available reporter types are: + *

+ * + *
    + *
  • ExtentHtmlReporter provided by artifactId "extent-html-formatter"
  • + *
  • ExtentEmailReporter (pro-only) provided by artifactId + * "extent-email-formatter"
  • + *
  • KlovReporter provided by artifactId "extent-klov-reporter"
  • + *
  • ConsoleLogger
  • + *
+ * + * @param reporter {@link ExtentReporter} reporter + */ + public void attachReporter(ExtentReporter... reporter) { + Arrays.stream(reporter).forEach(this::register); + } + + /** + * Returns a list of started reporters + * + * @return A list of {@link ExtentReporter} + */ + public List getStartedReporters() { + return getReporterCollection(); + } + + /** + * Creates a BDD-style test with description representing one of the + * {@link IGherkinFormatterModel} classes such as: + * + *
    + *
  • {@link com.aventstack.extentreports.gherkin.model.Feature}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Background}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Scenario}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Given}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.When}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Then}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.And}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.But}
  • + *
+ * + *

+ * Example: + *

+ * + *
+	 * extent.createTest(Feature.class, "feature", "description");
+	 * extent.createTest(Scenario.class, "scenario", "description");
+	 * extent.createTest(Given.class, "given", "description");
+	 * 
+ * + * @param type A {@link IGherkinFormatterModel} type + * @param testName Name of test + * @param description A short description of the test + * + * @return {@link ExtentTest} object + */ + public ExtentTest createTest(Class type, String testName, + String description) { + ExtentTest t = new ExtentTest(this, type, testName, description); + applyCommonTestSettings(t); + saveTest(t.getModel()); + return t; + } + + /** + * Creates a BDD-style test representing one of the + * {@link IGherkinFormatterModel} classes such as: + * + *
    + *
  • {@link com.aventstack.extentreports.gherkin.model.Feature}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Background}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Scenario}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Given}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.When}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Then}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.And}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.But}
  • + *
+ * + *

+ * Example: + *

+ * + *
+	 * extent.createTest(Feature.class, "feature");
+	 * extent.createTest(Scenario.class, "scenario");
+	 * extent.createTest(Given.class, "given");
+	 * 
+ * + * @param type A {@link IGherkinFormatterModel} type + * @param testName Name of test + * + * @return {@link ExtentTest} object + */ + public ExtentTest createTest(Class type, String testName) { + return createTest(type, testName, null); + } + + /** + * Creates a BDD-style test with description using name of the Gherkin model + * such as: + * + *
    + *
  • {@link com.aventstack.extentreports.gherkin.model.Feature}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Background}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Scenario}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Given}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.When}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Then}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.And}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.But}
  • + *
+ * + *

+ * Example: + *

+ * + *
+	 * extent.createTest(new GherkinKeyword("Feature"), "feature", "description");
+	 * extent.createTest(new GherkinKeyword("Scenario"), "scenario", "description");
+	 * extent.createTest(new GherkinKeyword("Given"), "given", "description");
+	 * 
+ * + * @param gherkinKeyword Name of the {@link GherkinKeyword} + * @param testName Name of test + * @param description A short description of the test + * + * @return {@link ExtentTest} object + */ + public ExtentTest createTest(GherkinKeyword gherkinKeyword, String testName, String description) { + Class clazz = gherkinKeyword.getKeyword().getClass(); + return createTest(clazz, testName, description); + } + + /** + * Creates a BDD-style test using name of the Gherkin model such as: + * + *
    + *
  • {@link com.aventstack.extentreports.gherkin.model.Feature}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Background}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Scenario}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Given}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.When}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Then}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.And}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.But}
  • + *
+ * + *

+ * Example: + *

+ * + *
+	 * extent.createTest(new GherkinKeyword("Feature"), "feature");
+	 * extent.createTest(new GherkinKeyword("Scenario"), "scenario");
+	 * extent.createTest(new GherkinKeyword("Given"), "given");
+	 * 
+ * + * @param gherkinKeyword Name of the {@link GherkinKeyword} + * @param testName Name of test + * + * @return {@link ExtentTest} object + */ + public ExtentTest createTest(GherkinKeyword gherkinKeyword, String testName) { + return createTest(gherkinKeyword, testName, null); + } + + /** + * Creates a test with description + * + * @param testName Name of test + * @param description A short test description + * + * @return {@link ExtentTest} object + */ + public ExtentTest createTest(String testName, String description) { + ExtentTest t = new ExtentTest(this, testName, description); + applyCommonTestSettings(t); + + saveTest(t.getModel()); + + return t; + } - /** - * Creates a test - * - * @param testName Name of test - * - * @return {@link ExtentTest} object - */ - public synchronized ExtentTest createTest(String testName) { - return createTest(testName, null); - } - - private synchronized void applyCommonTestSettings(ExtentTest extentTest) { - extentTest.setUseManualConfiguration(getAllowManualConfig()); - } - - /** - * Removes a test - * - * @param test {@link ExtentTest} object - */ - public synchronized void removeTest(ExtentTest test) { - super.removeTest(test.getModel()); - } - - /** - * Writes test information from the started reporters to their output view - * - *
    - *
  • extent-html-formatter: flush output to HTML file
  • - *
  • extent-klov-reporter: updates MongoDB collections
  • - *
  • extent-email-formatter (pro-only): creates or appends to an HTML file
  • - *
  • ConsoleLogger: no action taken
  • - *
- */ - @Override - public synchronized void flush() { - super.flush(); - } + /** + * Creates a test + * + * @param testName Name of test + * + * @return {@link ExtentTest} object + */ + public ExtentTest createTest(String testName) { + return createTest(testName, null); + } + + private void applyCommonTestSettings(ExtentTest extentTest) { + extentTest.setUseManualConfiguration(getAllowManualConfig()); + } - /** - * Adds any applicable system information to all started reporters - * - *

- * Example: - *

- * - *
-     * extent.setSystemInfo("HostName", "AventStack-PC");
-     * 
- * - * @param k Name of system variable - * @param v Value of system variable - */ - public void setSystemInfo(String k, String v) { - SystemAttribute sa = new SystemAttribute(k, v); - super.setSystemInfo(sa); - } - - /** - * Adds logs from test framework tools to the test-runner logs view (if available in the reporter) - * - *

- * TestNG usage example: - *

- * - *
-     * extent.setTestRunnerOutput(Reporter.getOutput());
-     * 
- * - * @param log Log string from the test runner frameworks such as TestNG or JUnit - */ - public void setTestRunnerOutput(List log) { - log.forEach(this::setTestRunnerLogs); - } - - /** - * Adds logs from test framework tools to the test-runner logs view (if available in the reporter) - * - *

- * TestNG usage example: - *

- * - *
-     * for (String s : Reporter.getOutput()) {
-     *   extent.setTestRunnerOutput(s);
-     * }
-     * 
- * - * @param log Log string from the test runner frameworks such as TestNG or JUnit - */ - public void setTestRunnerOutput(String log) { - setTestRunnerLogs(log); - } - - /** - * Use this setting when building post-execution reports, such as from TestNG IReporter. - * This setting allows setting test with your own time-stamps. With this enabled, Extent - * does not use time-stamps for tests at the time they were created. - * - *

- * If this setting is enabled and time-stamps are not specified explicitly, the time-stamps - * of test creation are used. - * - * @param useManualConfig Set to true if building reports at the end of execution with manual configuration - */ - public void setReportUsesManualConfiguration(boolean useManualConfig) { - setAllowManualConfig(useManualConfig); - } + /** + * Removes a test + * + * @param test {@link ExtentTest} object + */ + public void removeTest(ExtentTest test) { + super.removeTest(test.getModel()); + } + + /** + * Writes test information from the started reporters to their output view + * + *

    + *
  • extent-html-formatter: flush output to HTML file
  • + *
  • extent-klov-reporter: updates MongoDB collections
  • + *
  • extent-email-formatter (pro-only): creates or appends to an HTML + * file
  • + *
  • ConsoleLogger: no action taken
  • + *
+ */ + @Override + public void flush() { + super.flush(); + } /** - * Type of AnalysisStrategy for the reporter. Not all reporters support this setting. - * - *

- * There are 2 types of strategies available: - * - *

    - *
  • TEST: Shows analysis at the test and step level
  • - *
  • SUITE: Shows analysis at the suite, test and step level
  • - *
- * - * @param strategy {@link AnalysisStrategy} determines the type of analysis (dashboard) - * created for the reporter. Not all reporters will support this setting. - */ - @Override - public void setAnalysisStrategy(AnalysisStrategy strategy) { - super.setAnalysisStrategy(strategy); - } - - /** - * Provides common report configurations - * - * @return an instance of {@link ReportConfigurator} - */ - public ReportConfigurator config() { - return ReportConfigurator.getInstance(); - } - - /** - * Allows setting the target language for Gherkin keywords. - * - *

- * Default setting is "en" - * - * @param language A valid dialect from - * gherkin-languages.json - * - * @throws UnsupportedEncodingException Thrown if the language is one of the supported language from - * gherkin-languages.json - */ - public void setGherkinDialect(String language) throws UnsupportedEncodingException { - GherkinDialectProvider.setLanguage(language); - } - - /** - * Returns an instance of {@link ReportStatusStats} with counts of tests executed - * by their status (pass, fail, skip etc) - * - * @return an instance of {@link ReportStatusStats} - */ - @Override - public ReportStatusStats getStats() { - return super.getStats(); - } - -} + * Adds any applicable system information to all started reporters + * + *

+ * Example: + *

+ * + *
+	 * extent.setSystemInfo("HostName", "AventStack-PC");
+	 * 
+ * + * @param k Name of system variable + * @param v Value of system variable + */ + public void setSystemInfo(String k, String v) { + SystemAttribute sa = new SystemAttribute(k, v); + super.setSystemInfo(sa); + } + + /** + * Adds logs from test framework tools to the test-runner logs view (if + * available in the reporter) + * + *

+ * TestNG usage example: + *

+ * + *
+	 * extent.setTestRunnerOutput(Reporter.getOutput());
+	 * 
+ * + * @param log Log string from the test runner frameworks such as TestNG or JUnit + */ + public void setTestRunnerOutput(List log) { + log.forEach(this::setTestRunnerLogs); + } + + /** + * Adds logs from test framework tools to the test-runner logs view (if + * available in the reporter) + * + *

+ * TestNG usage example: + *

+ * + *
+	 * for (String s : Reporter.getOutput()) {
+	 * 	extent.setTestRunnerOutput(s);
+	 * }
+	 * 
+ * + * @param log Log string from the test runner frameworks such as TestNG or JUnit + */ + public void setTestRunnerOutput(String log) { + setTestRunnerLogs(log); + } + + /** + * Tries to resolve a {@link ScreenCapture} location if the supplied path is not found using + * default locations. This can resolve cases where the default path was supplied to be relative + * for a FileReporter. If the absolute path is not determined, the supplied will be used. + * below paths are used to locate the image: + * + *
    + *
  • target/
  • + *
  • test-output//
  • + *
+ * + * @return {@link ExtentKlovReporter} + */ + public ExtentReports tryResolveMediaPath() { + setMediaPathResolveDir(IMAGE_PATH_RESOLVER_DIR); + return this; + } + + /** + * Tries to resolve a {@link ScreenCapture} location if the supplied path is not found using + * supplied locations. This can resolve cases where the default path was supplied to be relative + * for a FileReporter. If the absolute path is not determined, the supplied will be used. + * + * @param paths Dirs used to create absolute path of the {@link Media} object + * + * @return {@link ExtentKlovReporter} + */ + public ExtentReports tryResolveMediaPath(String[] paths) { + setMediaPathResolveDir(paths); + return this; + } + + /** + * Creates the internal models by consuming a JSON archive from a previous run + * session. This provides the same functionality as available in earlier versions + * via appendExisting, with the exception of being accessible by + * all reporters instead of just one. + * + * @param jsonFile The JSON archive file + * @throws IOException Exception thrown if the jsonFile is not found + */ + public void createDomainFromJsonArchive(File jsonFile) throws IOException { + TestModelReportBuilder modelBuilder = new TestModelReportBuilder(); + modelBuilder.createDomainFromJsonArchive(this, jsonFile); + } + + /** + * Creates the internal models by consuming a JSON archive from a previous run + * session. This provides the same functionality as available in earlier versions + * via appendExisting, with the exception of being accessible by + * all reporters instead of just one. + * + * @param jsonFilePath The JSON archive file + * @throws IOException Exception thrown if the jsonFilePath is not found + */ + public void createDomainFromJsonArchive(String jsonFilePath) throws IOException { + createDomainFromJsonArchive(new File(jsonFilePath)); + } + + /** + * Use this setting when building post-execution reports, such as from TestNG + * IReporter. This setting allows setting test with your own time-stamps. With + * this enabled, Extent does not use time-stamps for tests at the time they were + * created. + * + *

+ * If this setting is enabled and time-stamps are not specified explicitly, the + * time-stamps of test creation are used. + * + * @param useManualConfig Set to true if building reports at the end of + * execution with manual configuration + */ + public void setReportUsesManualConfiguration(boolean useManualConfig) { + setAllowManualConfig(useManualConfig); + } + + public Boolean getReportUsesManualConfiguration() { + return getAllowManualConfig(); + } + + /** + * Type of AnalysisStrategy for the reporter. Not all reporters support this + * setting. + * + *

+ * There are 2 types of strategies available: + * + *

    + *
  • TEST: Shows analysis at the test and step level
  • + *
  • SUITE: Shows analysis at the suite, test and step level
  • + *
+ * + * @param strategy {@link AnalysisStrategy} determines the type of analysis + * (dashboard) created for the reporter. Not all reporters will + * support this setting. + */ + @Override + public void setAnalysisStrategy(AnalysisStrategy strategy) { + super.setAnalysisStrategy(strategy); + } + + /** + * Provides common report configurations + * + * @return an instance of {@link ReportConfigurator} + */ + public ReportConfigurator config() { + return ReportConfigurator.getInstance(); + } + + /** + * Allows setting the target language for Gherkin keywords. + * + *

+ * Default setting is "en" + * + * @param language A valid dialect from gherkin-languages.json + * + * @throws UnsupportedEncodingException Thrown if the language is one of the + * supported language from gherkin-languages.json + */ + public void setGherkinDialect(String language) throws UnsupportedEncodingException { + GherkinDialectProvider.setLanguage(language); + } + + /** + * Returns an instance of {@link ReportStatusStats} with counts of tests + * executed by their status (pass, fail, skip etc) + * + * @return an instance of {@link ReportStatusStats} + */ + @Override + public ReportStatusStats getStats() { + return super.getStats(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/ExtentTest.java b/src/main/java/com/aventstack/extentreports/ExtentTest.java index a36e634..d346436 100644 --- a/src/main/java/com/aventstack/extentreports/ExtentTest.java +++ b/src/main/java/com/aventstack/extentreports/ExtentTest.java @@ -10,17 +10,16 @@ import com.aventstack.extentreports.model.Category; import com.aventstack.extentreports.model.Device; import com.aventstack.extentreports.model.ExceptionInfo; -import com.aventstack.extentreports.model.IAddsMedia; import com.aventstack.extentreports.model.Log; import com.aventstack.extentreports.model.Media; -import com.aventstack.extentreports.model.MediaType; import com.aventstack.extentreports.model.ScreenCapture; -import com.aventstack.extentreports.model.Screencast; import com.aventstack.extentreports.model.Test; +import com.aventstack.extentreports.utils.ExceptionUtil; import com.aventstack.extentreports.utils.StringUtil; /** - * Defines a test. You can add logs, snapshots, assign author and categories to a test and its children. + * Defines a test. You can add logs, snapshots, assign author and categories to + * a test and its children. * *

* The below log types will all be logged with Status.PASS: @@ -37,1182 +36,1189 @@ *

* *
    - *
  • Tests started with the createTest method are parent-level, always level 0
  • - *
  • Tests started with the createNode method are children, always level 1 and greater
  • + *
  • Tests started with the createTest method are parent-level, + * always level 0
  • + *
  • Tests started with the createNode method are children, + * always level 1 and greater
  • *
*/ -public class ExtentTest - implements IAddsMedia, RunResult, Serializable { - - private static final long serialVersionUID = 9199820968410788862L; - - /** - * An instance of {@link ExtentReports} to which this {@link ExtentTest} belongs - */ - private transient ExtentReports extent; - - /** - * Internal model - */ - private Test test; - - /** - * Creates a BDD style parent test representing one of the {@link IGherkinFormatterModel} - * classes. This method would ideally be used for creating the parent, ie {@link Feature). - * - *
    - *
  • {@link com.aventstack.extentreports.gherkin.model.Feature}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Background}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Scenario}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Given}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.When}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Then}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.And}
  • - *
- * - *

- * Example: - *

- * - *
-     * extent.createTest(Feature.class, "Feature Name", "Description");
-     * 
- * - * @param extent An {@link ExtentReports} object - * @param type A {@link IGherkinFormatterModel} type - * @param testName Test name - * @param description Test description - */ - ExtentTest(ExtentReports extent, Class type, String testName, String description) { - if (testName == null || testName.isEmpty()) - throw new IllegalArgumentException("testName cannot be null or empty"); - - this.extent = extent; - - test = new Test(); - test.setName(testName.trim()); - test.setDescription(description == null ? "" : description.trim()); - - if (type != null) { - test.setBehaviorDrivenType(type); - } - } - - /** - * Create a test with description - * - * @param extent An {@link ExtentReports} object - * @param testName Test name - * @param description Test description - */ - ExtentTest(ExtentReports extent, String testName, String description) { - this(extent, null, testName, description); - } - - /** - * Creates a BDD-style node with description representing one of the {@link IGherkinFormatterModel} - * classes: - * - *
    - *
  • {@link com.aventstack.extentreports.gherkin.model.Feature}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Background}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Scenario}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Given}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.When}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Then}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.And}
  • - *
- * - *

- * Example: - *

- * - *
-     * test.createNode(Scenario.class, "bddNode", "description");
-     * 
- * - * @param type A {@link IGherkinFormatterModel} type - * @param name Name of node - * @param description A short description - * - * @return {@link ExtentTest} object - */ - public synchronized ExtentTest createNode(Class type, String name, String description) { - if (name == null || name.isEmpty()) - throw new IllegalArgumentException("nodeName cannot be null or empty"); - - ExtentTest t; - if (type == null) { - t = new ExtentTest(extent, name, description); - } else { - t = new ExtentTest(extent, type, name, description); - } - - applyCommonNodeSettings(t); - addNodeToReport(t); - return t; - } - - /** - * Creates a node with description - * - * @param name Name of node - * @param description A short description - * - * @return {@link ExtentTest} object - */ - public synchronized ExtentTest createNode(String name, String description) { - if (name == null || name.isEmpty()) - throw new IllegalArgumentException("nodeName cannot be null or empty"); - - ExtentTest t = new ExtentTest(extent, name, description); - applyCommonNodeSettings(t); - addNodeToReport(t); - return t; - } - - /** - * Creates a BDD-style node representing one of the {@link IGherkinFormatterModel} classes such as: - * - *
    - *
  • {@link com.aventstack.extentreports.gherkin.model.Feature}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Background}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Scenario}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Given}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.When}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Then}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.And}
  • - *
- * - *

- * Example: - *

- * - *
-     * test.createNode(Scenario.class, "bddNode");
-     * 
- * - * @param type A {@link IGherkinFormatterModel} type - * @param name Name of node - * - * @return {@link ExtentTest} object - */ - public synchronized ExtentTest createNode(Class type, String name) { - return createNode(type, name, null); - } - - /** - * Creates a BDD-style node with description using name of the Gherkin model such as: - * - *
    - *
  • {@link com.aventstack.extentreports.gherkin.model.Feature}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Background}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Scenario}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Given}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.When}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Then}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.And}
  • - *
- * - *

- * Example: - *

- * - *
-     * test.createNode(new GherkinKeyword("Scenario"), "bddTest", "description");
-     * 
- * - * @param gherkinKeyword Name of the {@link GherkinKeyword} - * @param name Name of node - * @param description A short description - * - * @return {@link ExtentTest} - */ - public synchronized ExtentTest createNode(GherkinKeyword gherkinKeyword, String name, String description) { - Class clazz = gherkinKeyword.getKeyword().getClass(); - return createNode(clazz, name, description); - } - - /** - * Creates a BDD-style node using name of the Gherkin model such as: - * - *
    - *
  • {@link com.aventstack.extentreports.gherkin.model.Feature}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Background}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Scenario}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Given}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.When}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Then}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.And}
  • - *
- * - *

- * Example: - *

- * - *
-     * test.createNode(new GherkinKeyword("Scenario"), "bddTest");
-     * 
- * - * @param gherkinKeyword Name of the {@link GherkinKeyword} - * @param name Name of node - * - * @return {@link ExtentTest} object - */ - public synchronized ExtentTest createNode(GherkinKeyword gherkinKeyword, String name) { - return createNode(gherkinKeyword, name, null); - } - - /** - * Creates a node - * - * @param name Name of node - * - * @return {@link ExtentTest} object - */ - public synchronized ExtentTest createNode(String name) { - return createNode(name, null); - } - - private void applyCommonNodeSettings(ExtentTest extentTest) { - extentTest.getModel().setLevel(test.getLevel() + 1); - extentTest.getModel().setParent(getModel()); - test.getNodeContext().add(extentTest.getModel()); - } - - private void addNodeToReport(ExtentTest extentNode) { - extent.addNode(extentNode.getModel()); - } - - /** - * Logs an event with {@link Status}, details and a media object: {@link Screencast} or - * {@link ScreenCapture} - * - *

- * Example: - *

- * - *
-     * test.log(Status.FAIL, "details", MediaEntityBuilder.createScreenCaptureFromPath("screen.png").build());
-     * 
- * - * @param status {@link Status} - * @param details Details - * @param provider A {@link MediaEntityModelProvider} object - * - * @return An {@link ExtentTest} object - */ - public synchronized ExtentTest log(Status status, String details, MediaEntityModelProvider provider) { - Log evt = createLog(status, details); - addMedia(evt, provider); - return addLog(evt); - } - - private synchronized void addMedia(Log evt, MediaEntityModelProvider provider) { - if (provider != null) { - Class clazz = provider.getMedia().getClass(); - - if (clazz.equals(ScreenCapture.class)) { - ScreenCapture sc = (ScreenCapture) provider.getMedia(); - evt.setScreenCapture(sc); - } else { - evt.setScreencast((Screencast) provider.getMedia()); - } - } - } - - /** - * Logs an event with {@link Status} and details - * - * @param status {@link Status} - * @param details Details - * - * @return An {@link ExtentTest} object - */ - public synchronized ExtentTest log(Status status, String details) { - return log(status, details, null); - } - - /** - * Logs an event with {@link Status} and custom {@link Markup} such as: - * - *
    - *
  • Code block
  • - *
  • Label
  • - *
  • Table
  • - *
- * - * @param status {@link Status} - * @param markup {@link Markup} - * - * @return An {@link ExtentTest} object - */ - public synchronized ExtentTest log(Status status, Markup markup) { - String details = markup.getMarkup(); - return log(status, details); - } - - private synchronized ExtentTest addLog(Log evt) { - test.getLogContext().add(evt); - test.end(); - - extent.addLog(test, evt); - - if (evt.hasScreenCapture()) { - try { - extent.addScreenCapture(evt, evt.getScreenCaptureContext().getLast()); - } catch (IOException e) { - e.printStackTrace(); - } - } - - return this; - } - - private Log createLog(Status status) { - Log evt = new Log(this); - evt.setStatus(status); - evt.setSequence(test.getLogContext().getAll().size() + 1); - return evt; - } - - private Log createLog(Status status, String details) { - Log evt = createLog(status); - evt.setDetails(details == null ? "" : details.trim()); - return evt; - } - - /** - * Logs an event with {@link Status}, an exception and a media object: {@link Screencast} or - * {@link ScreenCapture} - * - *

- * Example: - *

- * - *
-     * Exception exception = new NullPointerException();
-     * test.log(Status.FAIL, exception, MediaEntityBuilder.createScreenCaptureFromPath("screen.png").build());
-     * 
- * - * @param status {@link Status} - * @param t {@link Throwable} - * @param provider A {@link MediaEntityModelProvider} object - * - * @return An {@link ExtentTest} object - */ - public synchronized ExtentTest log(Status status, Throwable t, MediaEntityModelProvider provider) { - ExceptionInfo exInfo = new ExceptionInfo(t); - getModel().setExceptionInfo(exInfo); - Log evt = createLog(status); - evt.setExceptionInfo(exInfo); - addMedia(evt, provider); - return addLog(evt); - } - - /** - * Logs an event with {@link Status} and exception - * - * @param status {@link Status} - * @param t {@link Throwable} - * - * @return An {@link ExtentTest} object - */ - public synchronized ExtentTest log(Status status, Throwable t) { - return log(status, t, null); - } - - /** - * Logs an Status.INFO event with details and a media object: - * {@link Screencast} or {@link ScreenCapture} - * - *

- * Example: - *

- * - *
-     * test.info("details", MediaEntityBuilder.createScreenCaptureFromPath("screen.png").build());
-     * 
- * - * @param details Details - * @param provider A {@link MediaEntityModelProvider} object - * - * @return An {@link ExtentTest} object - */ - public ExtentTest info(String details, MediaEntityModelProvider provider) { - log(Status.INFO, details, provider); - return this; - } - - /** - * Logs an event with Status.INFO with details - * - * @param details Details - * - * @return {@link ExtentTest} object - */ - public ExtentTest info(String details) { - return info(details, null); - } - - /** - * Logs an Status.INFO event with an exception and a media object: - * {@link Screencast} or {@link ScreenCapture} - * - *

- * Example: - *

- * - *
-     * Exception exception = new NullPointerException();
+public class ExtentTest implements IAddsMedia, RunResult, Serializable {
+
+	private static final long serialVersionUID = 9199820968410788862L;
+
+	/**
+	 * An instance of {@link ExtentReports} to which this {@link ExtentTest} belongs
+	 */
+	private transient ExtentReports extent;
+
+	/**
+	 * Internal model
+	 */
+	private Test test;
+
+	/**
+	 * Creates a BDD style parent test representing one of the
+	 * {@link IGherkinFormatterModel} classes. This method would ideally be used for
+	 * creating the parent, ie {@link Feature).
+	 * 
+	 * 
    + *
  • {@link com.aventstack.extentreports.gherkin.model.Feature}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Background}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Scenario}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Given}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.When}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Then}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.And}
  • + *
+ * + *

+ * Example: + *

+ * + *
+	 * extent.createTest(Feature.class, "Feature Name", "Description");
+	 * 
+ * + * @param extent An {@link ExtentReports} object + * @param type A {@link IGherkinFormatterModel} type + * @param name Test name + * @param description Test description + */ + ExtentTest(ExtentReports extent, Class type, String name, String description) { + if (name == null || name.isEmpty()) { + throw new IllegalArgumentException("testName cannot be null or empty"); + } + this.extent = extent; + test = new Test(); + test.setName(name.trim()); + test.setDescription(description == null ? "" : description.trim()); + if (type != null) { + test.setBddType(type); + } + } + + /** + * Create a test with description + * + * @param extent An {@link ExtentReports} object + * @param testName Test name + * @param description Test description + */ + ExtentTest(ExtentReports extent, String testName, String description) { + this(extent, null, testName, description); + } + + /** + * Creates a BDD-style node with description representing one of the + * {@link IGherkinFormatterModel} classes: + * + *
    + *
  • {@link com.aventstack.extentreports.gherkin.model.Feature}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Background}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Scenario}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Given}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.When}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Then}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.And}
  • + *
+ * + *

+ * Example: + *

+ * + *
+	 * test.createNode(Scenario.class, "bddNode", "description");
+	 * 
+ * + * @param type A {@link IGherkinFormatterModel} type + * @param name Name of node + * @param description A short description + * + * @return {@link ExtentTest} object + */ + public ExtentTest createNode(Class type, String name, String description) { + if (name == null || name.isEmpty()) + throw new IllegalArgumentException("nodeName cannot be null or empty"); + + ExtentTest t; + if (type == null) { + t = new ExtentTest(extent, name, description); + } else { + t = new ExtentTest(extent, type, name, description); + } + + applyCommonNodeSettings(t); + addNodeToReport(t); + return t; + } + + /** + * Creates a node with description + * + * @param name Name of node + * @param description A short description + * + * @return {@link ExtentTest} object + */ + public ExtentTest createNode(String name, String description) { + if (name == null || name.isEmpty()) + throw new IllegalArgumentException("nodeName cannot be null or empty"); + + ExtentTest t = new ExtentTest(extent, name, description); + applyCommonNodeSettings(t); + addNodeToReport(t); + return t; + } + + /** + * Creates a BDD-style node representing one of the + * {@link IGherkinFormatterModel} classes such as: + * + *
    + *
  • {@link com.aventstack.extentreports.gherkin.model.Feature}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Background}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Scenario}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Given}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.When}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Then}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.And}
  • + *
+ * + *

+ * Example: + *

+ * + *
+	 * test.createNode(Scenario.class, "bddNode");
+	 * 
+ * + * @param type A {@link IGherkinFormatterModel} type + * @param name Name of node + * + * @return {@link ExtentTest} object + */ + public ExtentTest createNode(Class type, String name) { + return createNode(type, name, null); + } + + /** + * Creates a BDD-style node with description using name of the Gherkin model + * such as: + * + *
    + *
  • {@link com.aventstack.extentreports.gherkin.model.Feature}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Background}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Scenario}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Given}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.When}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Then}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.And}
  • + *
+ * + *

+ * Example: + *

+ * + *
+	 * test.createNode(new GherkinKeyword("Scenario"), "bddTest", "description");
+	 * 
+ * + * @param gherkinKeyword Name of the {@link GherkinKeyword} + * @param name Name of node + * @param description A short description + * + * @return {@link ExtentTest} + */ + public ExtentTest createNode(GherkinKeyword gherkinKeyword, String name, String description) { + Class clazz = gherkinKeyword.getKeyword().getClass(); + return createNode(clazz, name, description); + } + + /** + * Creates a BDD-style node using name of the Gherkin model such as: + * + *
    + *
  • {@link com.aventstack.extentreports.gherkin.model.Feature}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Background}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Scenario}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Given}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.When}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Then}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.And}
  • + *
+ * + *

+ * Example: + *

+ * + *
+	 * test.createNode(new GherkinKeyword("Scenario"), "bddTest");
+	 * 
+ * + * @param gherkinKeyword Name of the {@link GherkinKeyword} + * @param name Name of node + * + * @return {@link ExtentTest} object + */ + public ExtentTest createNode(GherkinKeyword gherkinKeyword, String name) { + return createNode(gherkinKeyword, name, null); + } + + /** + * Creates a node + * + * @param name Name of node + * + * @return {@link ExtentTest} object + */ + public ExtentTest createNode(String name) { + return createNode(name, null); + } + + private void applyCommonNodeSettings(ExtentTest extentTest) { + extentTest.getModel().setLevel(test.getLevel() + 1); + extentTest.getModel().setParent(getModel()); + test.getNodeContext().add(extentTest.getModel()); + } + + private void addNodeToReport(ExtentTest extentNode) { + extent.addNode(extentNode.getModel()); + } + + /** + * Logs an event with {@link Status}, details and a media object: + * {@link ScreenCapture} + * + *

+ * Example: + *

+ * + *
+	 * test.log(Status.FAIL, "details", MediaEntityBuilder.createScreenCaptureFromPath("screen.png").build());
+	 * 
+ * + * @param status {@link Status} + * @param details Details + * @param provider A {@link MediaEntityModelProvider} object + * + * @return An {@link ExtentTest} object + */ + public ExtentTest log(Status status, String details, MediaEntityModelProvider provider) { + Log evt = createLog(status, details); + addMedia(evt, provider); + return addLog(evt); + } + + private void addMedia(Log evt, MediaEntityModelProvider provider) { + if (provider != null) { + Class clazz = provider.getMedia().getClass(); + + if (clazz.equals(ScreenCapture.class)) { + ScreenCapture c = (ScreenCapture) provider.getMedia(); + evt.getScreenCaptureContext().add(c); + } else { + + } + } + } + + /** + * Logs an event with {@link Status} and details + * + * @param status {@link Status} + * @param details Details + * + * @return An {@link ExtentTest} object + */ + public ExtentTest log(Status status, String details) { + return log(status, details, null); + } + + /** + * Logs an event with {@link Status} and custom {@link Markup} such as: + * + *
    + *
  • Code block
  • + *
  • Label
  • + *
  • Table
  • + *
+ * + * @param status {@link Status} + * @param markup {@link Markup} + * + * @return An {@link ExtentTest} object + */ + public ExtentTest log(Status status, Markup markup) { + String details = markup.getMarkup(); + return log(status, details); + } + + private ExtentTest addLog(Log evt) { + getModel().getLogContext().add(evt); + getModel().end(); + extent.addLog(getModel(), evt); + + if (!evt.getScreenCaptureContext().isEmpty()) { + try { + extent.addScreenCapture(evt, evt.getScreenCaptureContext().getLast()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + return this; + } + + private Log createLog(Status status) { + Log evt = new Log(getModel()); + evt.setStatus(status); + evt.setSequence(test.getLogContext().size() + 1); + return evt; + } + + private Log createLog(Status status, String details) { + Log evt = createLog(status); + evt.setDetails(details == null ? "" : details.trim()); + return evt; + } + + /** + * Logs an event with {@link Status}, an exception and a media object: + * {@link ScreenCapture} + * + *

+ * Example: + *

+ * + *
+	 * Exception exception = new NullPointerException();
+	 * test.log(Status.FAIL, exception, MediaEntityBuilder.createScreenCaptureFromPath("screen.png").build());
+	 * 
+ * + * @param status {@link Status} + * @param t {@link Throwable} + * @param provider A {@link MediaEntityModelProvider} object + * + * @return An {@link ExtentTest} object + */ + public ExtentTest log(Status status, Throwable t, MediaEntityModelProvider provider) { + ExceptionInfo exceptionInfo = new ExceptionInfo(); + exceptionInfo.setThrowable(t); + exceptionInfo.setExceptionName(ExceptionUtil.getExceptionHeadline(t)); + exceptionInfo.setStackTrace(ExceptionUtil.getStackTrace(t)); + Log evt = createLog(status); + evt.setExceptionInfo(exceptionInfo); + getModel().getExceptionInfoContext().add(exceptionInfo); + addMedia(evt, provider); + return addLog(evt); + } + + /** + * Logs an event with {@link Status} and exception + * + * @param status {@link Status} + * @param t {@link Throwable} + * + * @return An {@link ExtentTest} object + */ + public ExtentTest log(Status status, Throwable t) { + return log(status, t, null); + } + + /** + * Logs an event with {@link ExceptionInfo} + * + * @param status {@link Status} + * @param exceptionInfo{@link ExceptionInfo} + * + * @return An {@link ExtentTest} object + */ + public ExtentTest log(Status status, ExceptionInfo exceptionInfo) { + Log evt = createLog(status); + evt.setExceptionInfo(exceptionInfo); + getModel().getExceptionInfoContext().add(exceptionInfo); + return addLog(evt); + } + + /** + * Logs an Status.INFO event with details and a media object: + * {@link ScreenCapture} + * + *

+ * Example: + *

+ * + *
+	 * test.info("details", MediaEntityBuilder.createScreenCaptureFromPath("screen.png").build());
+	 * 
+ * + * @param details Details + * @param provider A {@link MediaEntityModelProvider} object + * + * @return An {@link ExtentTest} object + */ + public ExtentTest info(String details, MediaEntityModelProvider provider) { + log(Status.INFO, details, provider); + return this; + } + + /** + * Logs an event with Status.INFO with details + * + * @param details Details + * + * @return {@link ExtentTest} object + */ + public ExtentTest info(String details) { + return info(details, null); + } + + /** + * Logs an Status.INFO event with an exception and a media object: + * {@link ScreenCapture} + * + *

+ * Example: + *

+ * + *
+	 * Exception exception = new NullPointerException();
 	 * test.info(exception, MediaEntityBuilder.createScreenCaptureFromPath("screen.png").build());
-     * 
- * - * @param t {@link Throwable} - * @param provider A {@link MediaEntityModelProvider} object - * - * @return An {@link ExtentTest} object - */ - public ExtentTest info(Throwable t, MediaEntityModelProvider provider) { - log(Status.INFO, t, provider); - return this; - } - - /** - * Logs an event with Status.INFO and exception - * - * @param t {@link Throwable} - * - * @return {@link ExtentTest} object - */ - public ExtentTest info(Throwable t) { - return info(t, null); - } - - /** - * Logs an event with Status.INFO and custom {@link Markup} such as: - * - *
    - *
  • Code block
  • - *
  • Label
  • - *
  • Table
  • - *
- * - * @param m {@link Markup} - * - * @return {@link ExtentTest} object - */ - public ExtentTest info(Markup m) { - log(Status.INFO, m); - return this; - } - - /** - * Logs an Status.PASS event with details and a media object: - * {@link Screencast} or {@link ScreenCapture} - * - *

- * Example: - *

- * - *
-     * test.pass("details", MediaEntityBuilder.createScreenCaptureFromPath("screen.png").build());
-     * 
- * - * @param details Details - * @param provider A {@link MediaEntityModelProvider} object - * - * @return An {@link ExtentTest} object - */ - public ExtentTest pass(String details, MediaEntityModelProvider provider) { - log(Status.PASS, details, provider); - return this; - } - - /** - * Logs an event Status.PASS with details - * - * @param details Details - * - * @return {@link ExtentTest} object - */ - public ExtentTest pass(String details) { - return pass(details, null); - } - - /** - * Logs an Status.PASS event with an exception and a media object: - * {@link Screencast} or {@link ScreenCapture} - * - *

- * Example: - *

- * - *
-     * Exception exception = new NullPointerException();
+	 * 
+ * + * @param t {@link Throwable} + * @param provider A {@link MediaEntityModelProvider} object + * + * @return An {@link ExtentTest} object + */ + public ExtentTest info(Throwable t, MediaEntityModelProvider provider) { + log(Status.INFO, t, provider); + return this; + } + + /** + * Logs an event with Status.INFO and exception + * + * @param t {@link Throwable} + * + * @return {@link ExtentTest} object + */ + public ExtentTest info(Throwable t) { + return info(t, null); + } + + /** + * Logs an event with Status.INFO and custom {@link Markup} such + * as: + * + *
    + *
  • Code block
  • + *
  • Label
  • + *
  • Table
  • + *
+ * + * @param m {@link Markup} + * + * @return {@link ExtentTest} object + */ + public ExtentTest info(Markup m) { + log(Status.INFO, m); + return this; + } + + /** + * Logs an Status.PASS event with details and a media object: + * {@link ScreenCapture} + * + *

+ * Example: + *

+ * + *
+	 * test.pass("details", MediaEntityBuilder.createScreenCaptureFromPath("screen.png").build());
+	 * 
+ * + * @param details Details + * @param provider A {@link MediaEntityModelProvider} object + * + * @return An {@link ExtentTest} object + */ + public ExtentTest pass(String details, MediaEntityModelProvider provider) { + log(Status.PASS, details, provider); + return this; + } + + /** + * Logs an event Status.PASS with details + * + * @param details Details + * + * @return {@link ExtentTest} object + */ + public ExtentTest pass(String details) { + return pass(details, null); + } + + /** + * Logs an Status.PASS event with an exception and a media object: + * {@link ScreenCapture} + * + *

+ * Example: + *

+ * + *
+	 * Exception exception = new NullPointerException();
 	 * test.pass(exception, MediaEntityBuilder.createScreenCaptureFromPath("screen.png").build());
-     * 
- * - * @param t {@link Throwable} - * @param provider A {@link MediaEntityModelProvider} object - * - * @return An {@link ExtentTest} object - */ - public ExtentTest pass(Throwable t, MediaEntityModelProvider provider) { - log(Status.PASS, t, provider); - return this; - } - - /** - * Logs an event with Status.PASS and exception - * - * @param t {@link Throwable} - * - * @return An {@link ExtentTest} object - */ - public ExtentTest pass(Throwable t) { - return pass(t, null); - } - - /** - * Logs an event with Status.PASS and custom {@link Markup} such as: - * - *
    - *
  • Code block
  • - *
  • Label
  • - *
  • Table
  • - *
- * - * @param m {@link Markup} - * - * @return An {@link ExtentTest} object - */ - public ExtentTest pass(Markup m) { - log(Status.PASS, m); - return this; - } - - /** - * Logs an Status.FAIL event with details and a media object: - * {@link Screencast} or {@link ScreenCapture} - * - * @param details Details - * @param provider A {@link MediaEntityModelProvider} object - * - * @return An {@link ExtentTest} object - */ - public ExtentTest fail(String details, MediaEntityModelProvider provider) { - log(Status.FAIL, details, provider); - return this; - } - - /** - * Logs an event Status.FAIL with details - * - * @param details Details - * - * @return {@link ExtentTest} object - */ - public ExtentTest fail(String details) { - return fail(details, null); - } - - /** - * Logs an Status.FAIL event with an exception and a media object: - * {@link Screencast} or {@link ScreenCapture} - * - *

- * Example: - *

- * - *
-     * Exception exception = new NullPointerException();
+	 * 
+ * + * @param t {@link Throwable} + * @param provider A {@link MediaEntityModelProvider} object + * + * @return An {@link ExtentTest} object + */ + public ExtentTest pass(Throwable t, MediaEntityModelProvider provider) { + log(Status.PASS, t, provider); + return this; + } + + /** + * Logs an event with Status.PASS and exception + * + * @param t {@link Throwable} + * + * @return An {@link ExtentTest} object + */ + public ExtentTest pass(Throwable t) { + return pass(t, null); + } + + /** + * Logs an event with Status.PASS and custom {@link Markup} such + * as: + * + *
    + *
  • Code block
  • + *
  • Label
  • + *
  • Table
  • + *
+ * + * @param m {@link Markup} + * + * @return An {@link ExtentTest} object + */ + public ExtentTest pass(Markup m) { + log(Status.PASS, m); + return this; + } + + /** + * Logs an Status.FAIL event with details and a media object: + * {@link ScreenCapture} + * + * @param details Details + * @param provider A {@link MediaEntityModelProvider} object + * + * @return An {@link ExtentTest} object + */ + public ExtentTest fail(String details, MediaEntityModelProvider provider) { + log(Status.FAIL, details, provider); + return this; + } + + /** + * Logs an event Status.FAIL with details + * + * @param details Details + * + * @return {@link ExtentTest} object + */ + public ExtentTest fail(String details) { + return fail(details, null); + } + + /** + * Logs an Status.FAIL event with an exception and a media object: + * {@link ScreenCapture} + * + *

+ * Example: + *

+ * + *
+	 * Exception exception = new NullPointerException();
 	 * test.fail(exception, MediaEntityBuilder.createScreenCaptureFromPath("screen.png").build());
-     * 
- * - * @param t {@link Throwable} - * @param provider A {@link MediaEntityModelProvider} object - * - * @return An {@link ExtentTest} object - */ - public ExtentTest fail(Throwable t, MediaEntityModelProvider provider) { - log(Status.FAIL, t, provider); - return this; - } - - /** - * Logs an event with Status.FAIL and exception - * - * @param t {@link Throwable} - * - * @return {@link ExtentTest} object - */ - public ExtentTest fail(Throwable t) { - return fail(t, null); - } - - /** - * Logs an event with Status.FAIL and custom {@link Markup} such as: - * - *
    - *
  • Code block
  • - *
  • Label
  • - *
  • Table
  • - *
- * - * @param m {@link Markup} - * - * @return {@link ExtentTest} object - */ - public ExtentTest fail(Markup m) { - log(Status.FAIL, m); - return this; - } - - /** - * Logs an Status.DATAL event with an exception and a media object: - * {@link Screencast} or {@link ScreenCapture} - * - * @param details Details - * @param provider A {@link MediaEntityModelProvider} object - * - * @return An {@link ExtentTest} object - */ - public ExtentTest fatal(String details, MediaEntityModelProvider provider) { - log(Status.FATAL, details, provider); - return this; - } - - /** - * Logs an event Status.FATAL with details - * - * @param details Details - * - * @return An {@link ExtentTest} object - */ - public ExtentTest fatal(String details) { - log(Status.FATAL, details); - return this; - } - - /** - * Logs an Status.FATAL event with an exception and a media object: - * {@link Screencast} or {@link ScreenCapture} - * - *

- * Example: - *

- * - *
-     * Exception exception = new NullPointerException();
+	 * 
+ * + * @param t {@link Throwable} + * @param provider A {@link MediaEntityModelProvider} object + * + * @return An {@link ExtentTest} object + */ + public ExtentTest fail(Throwable t, MediaEntityModelProvider provider) { + log(Status.FAIL, t, provider); + return this; + } + + /** + * Logs an event with Status.FAIL and exception + * + * @param t {@link Throwable} + * + * @return {@link ExtentTest} object + */ + public ExtentTest fail(Throwable t) { + return fail(t, null); + } + + /** + * Logs an event with Status.FAIL and custom {@link Markup} such + * as: + * + *
    + *
  • Code block
  • + *
  • Label
  • + *
  • Table
  • + *
+ * + * @param m {@link Markup} + * + * @return {@link ExtentTest} object + */ + public ExtentTest fail(Markup m) { + log(Status.FAIL, m); + return this; + } + + /** + * Logs an Status.DATAL event with an exception and a media object: + * {@link ScreenCapture} + * + * @param details Details + * @param provider A {@link MediaEntityModelProvider} object + * + * @return An {@link ExtentTest} object + */ + public ExtentTest fatal(String details, MediaEntityModelProvider provider) { + log(Status.FATAL, details, provider); + return this; + } + + /** + * Logs an event Status.FATAL with details + * + * @param details Details + * + * @return An {@link ExtentTest} object + */ + public ExtentTest fatal(String details) { + log(Status.FATAL, details); + return this; + } + + /** + * Logs an Status.FATAL event with an exception and a media object: + * {@link ScreenCapture} + * + *

+ * Example: + *

+ * + *
+	 * Exception exception = new NullPointerException();
 	 * test.fatal(exception, MediaEntityBuilder.createScreenCaptureFromPath("screen.png").build());
-     * 
- * - * @param t {@link Throwable} - * @param provider A {@link MediaEntityModelProvider} object - * - * @return An {@link ExtentTest} object - */ - public ExtentTest fatal(Throwable t, MediaEntityModelProvider provider) { - log(Status.FATAL, t, provider); - return this; - } - - /** - * Logs an event with Status.FATAL and exception - * - * @param t {@link Throwable} - * - * @return {@link ExtentTest} object - */ - public ExtentTest fatal(Throwable t) { - log(Status.FATAL, t); - return this; - } - - /** - * Logs an event with Status.FATAL and custom {@link Markup} such as: - * - *
    - *
  • Code block
  • - *
  • Label
  • - *
  • Table
  • - *
- * - * @param m {@link Markup} - * - * @return An {@link ExtentTest} object - */ - public ExtentTest fatal(Markup m) { - log(Status.FATAL, m); - return this; - } - - /** - * Logs an Status.WARNING event with an exception and a media object: - * {@link Screencast} or {@link ScreenCapture} - * - * @param details Details - * @param provider A {@link MediaEntityModelProvider} object - * - * @return An {@link ExtentTest} object - */ - public ExtentTest warning(String details, MediaEntityModelProvider provider) { - log(Status.WARNING, details, provider); - return this; - } - - /** - * Logs an event Status.WARNING with details - * - * @param details Details - * - * @return {@link ExtentTest} object - */ - public ExtentTest warning(String details) { - return warning(details, null); - } - - /** - * Logs an Status.WARNING event with an exception and a media object: - * {@link Screencast} or {@link ScreenCapture} - * - *

- * Example: - *

- * - *
-     * Exception exception = new NullPointerException();
+	 * 
+ * + * @param t {@link Throwable} + * @param provider A {@link MediaEntityModelProvider} object + * + * @return An {@link ExtentTest} object + */ + public ExtentTest fatal(Throwable t, MediaEntityModelProvider provider) { + log(Status.FATAL, t, provider); + return this; + } + + /** + * Logs an event with Status.FATAL and exception + * + * @param t {@link Throwable} + * + * @return {@link ExtentTest} object + */ + public ExtentTest fatal(Throwable t) { + log(Status.FATAL, t); + return this; + } + + /** + * Logs an event with Status.FATAL and custom {@link Markup} such + * as: + * + *
    + *
  • Code block
  • + *
  • Label
  • + *
  • Table
  • + *
+ * + * @param m {@link Markup} + * + * @return An {@link ExtentTest} object + */ + public ExtentTest fatal(Markup m) { + log(Status.FATAL, m); + return this; + } + + /** + * Logs an Status.WARNING event with an exception and a media + * object: {@link ScreenCapture} + * + * @param details Details + * @param provider A {@link MediaEntityModelProvider} object + * + * @return An {@link ExtentTest} object + */ + public ExtentTest warning(String details, MediaEntityModelProvider provider) { + log(Status.WARNING, details, provider); + return this; + } + + /** + * Logs an event Status.WARNING with details + * + * @param details Details + * + * @return {@link ExtentTest} object + */ + public ExtentTest warning(String details) { + return warning(details, null); + } + + /** + * Logs an Status.WARNING event with an exception and a media + * object: {@link ScreenCapture} + * + *

+ * Example: + *

+ * + *
+	 * Exception exception = new NullPointerException();
 	 * test.warning(exception, MediaEntityBuilder.createScreenCaptureFromPath("screen.png").build());
-     * 
- * - * @param t {@link Throwable} - * @param provider A {@link MediaEntityModelProvider} object - * - * @return An {@link ExtentTest} object - */ - public ExtentTest warning(Throwable t, MediaEntityModelProvider provider) { - log(Status.WARNING, t, provider); - return this; - } - - /** - * Logs an event with Status.WARNING and exception - * - * @param t {@link Throwable} - * - * @return {@link ExtentTest} object - */ - public ExtentTest warning(Throwable t) { - return warning(t, null); - } - - /** - * Logs an event with Status.WARNING and custom {@link Markup} such as: - * - *
    - *
  • Code block
  • - *
  • Label
  • - *
  • Table
  • - *
- * - * @param m {@link Markup} - * - * @return An {@link ExtentTest} object - */ - public ExtentTest warning(Markup m) { - log(Status.WARNING, m); - return this; - } - - /** - * Logs an Status.ERROR event with an exception and a media object: - * {@link Screencast} or {@link ScreenCapture} - * - * @param details Details - * @param provider A {@link MediaEntityModelProvider} object - * - * @return An {@link ExtentTest} object - */ - public ExtentTest error(String details, MediaEntityModelProvider provider) { - log(Status.ERROR, details, provider); - return this; - } - - /** - * Logs an event Status.ERROR with details - * - * @param details Details - * - * @return {@link ExtentTest} object - */ - public ExtentTest error(String details) { - return error(details, null); - } - - /** - * Logs an Status.ERROR event with an exception and a media object: - * {@link Screencast} or {@link ScreenCapture} - * - *

- * Example: - *

- * - *
-     * Exception exception = new NullPointerException();
+	 * 
+ * + * @param t {@link Throwable} + * @param provider A {@link MediaEntityModelProvider} object + * + * @return An {@link ExtentTest} object + */ + public ExtentTest warning(Throwable t, MediaEntityModelProvider provider) { + log(Status.WARNING, t, provider); + return this; + } + + /** + * Logs an event with Status.WARNING and exception + * + * @param t {@link Throwable} + * + * @return {@link ExtentTest} object + */ + public ExtentTest warning(Throwable t) { + return warning(t, null); + } + + /** + * Logs an event with Status.WARNING and custom {@link Markup} such + * as: + * + *
    + *
  • Code block
  • + *
  • Label
  • + *
  • Table
  • + *
+ * + * @param m {@link Markup} + * + * @return An {@link ExtentTest} object + */ + public ExtentTest warning(Markup m) { + log(Status.WARNING, m); + return this; + } + + /** + * Logs an Status.ERROR event with an exception and a media object: + * {@link ScreenCapture} + * + * @param details Details + * @param provider A {@link MediaEntityModelProvider} object + * + * @return An {@link ExtentTest} object + */ + public ExtentTest error(String details, MediaEntityModelProvider provider) { + log(Status.ERROR, details, provider); + return this; + } + + /** + * Logs an event Status.ERROR with details + * + * @param details Details + * + * @return {@link ExtentTest} object + */ + public ExtentTest error(String details) { + return error(details, null); + } + + /** + * Logs an Status.ERROR event with an exception and a media object: + * {@link ScreenCapture} + * + *

+ * Example: + *

+ * + *
+	 * Exception exception = new NullPointerException();
 	 * test.error(exception, MediaEntityBuilder.createScreenCaptureFromPath("screen.png").build());
-     * 
- * - * @param t {@link Throwable} - * @param provider A {@link MediaEntityModelProvider} object - * - * @return An {@link ExtentTest} object - */ - public ExtentTest error(Throwable t, MediaEntityModelProvider provider) { - log(Status.ERROR, t, provider); - return this; - } - - /** - * Logs an event with Status.ERROR and exception - * - * @param t {@link Throwable} - * - * @return {@link ExtentTest} object - */ - public ExtentTest error(Throwable t) { - return error(t, null); - } - - /** - * Logs an event with Status.ERROR and custom {@link Markup} such as: - * - *
    - *
  • Code block
  • - *
  • Label
  • - *
  • Table
  • - *
- * - * @param m {@link Markup} - * - * @return {@link ExtentTest} object - */ - public ExtentTest error(Markup m) { - log(Status.ERROR, m); - return this; - } - - /** - * - * @param details Details - * @param provider A {@link MediaEntityModelProvider} object - * - * @return An {@link ExtentTest} object - */ - public ExtentTest skip(String details, MediaEntityModelProvider provider) { - log(Status.SKIP, details, provider); - return this; - } - - /** - * Logs an event Status.SKIP with details - * - * @param details Details - * - * @return {@link ExtentTest} object - */ - public ExtentTest skip(String details) { - return skip(details, null); - } - - /** - * Logs an Status.SKIP event with an exception and a media object: - * {@link Screencast} or {@link ScreenCapture} - * - *

- * Example: - *

- * - *
-     * Exception exception = new NullPointerException();
+	 * 
+ * + * @param t {@link Throwable} + * @param provider A {@link MediaEntityModelProvider} object + * + * @return An {@link ExtentTest} object + */ + public ExtentTest error(Throwable t, MediaEntityModelProvider provider) { + log(Status.ERROR, t, provider); + return this; + } + + /** + * Logs an event with Status.ERROR and exception + * + * @param t {@link Throwable} + * + * @return {@link ExtentTest} object + */ + public ExtentTest error(Throwable t) { + return error(t, null); + } + + /** + * Logs an event with Status.ERROR and custom {@link Markup} such + * as: + * + *
    + *
  • Code block
  • + *
  • Label
  • + *
  • Table
  • + *
+ * + * @param m {@link Markup} + * + * @return {@link ExtentTest} object + */ + public ExtentTest error(Markup m) { + log(Status.ERROR, m); + return this; + } + + /** + * + * @param details Details + * @param provider A {@link MediaEntityModelProvider} object + * + * @return An {@link ExtentTest} object + */ + public ExtentTest skip(String details, MediaEntityModelProvider provider) { + log(Status.SKIP, details, provider); + return this; + } + + /** + * Logs an event Status.SKIP with details + * + * @param details Details + * + * @return {@link ExtentTest} object + */ + public ExtentTest skip(String details) { + return skip(details, null); + } + + /** + * Logs an Status.SKIP event with an exception and a media object: + * {@link ScreenCapture} + * + *

+ * Example: + *

+ * + *
+	 * Exception exception = new NullPointerException();
 	 * test.skip(exception, MediaEntityBuilder.createScreenCaptureFromPath("screen.png").build());
-     * 
- * - * @param t {@link Throwable} - * @param provider A {@link MediaEntityModelProvider} object - * - * @return An {@link ExtentTest} object - */ - public ExtentTest skip(Throwable t, MediaEntityModelProvider provider) { - log(Status.SKIP, t, provider); - return this; - } - - /** - * Logs an event with Status.SKIP and exception - * - * @param t {@link Throwable} - * - * @return {@link ExtentTest} object - */ - public ExtentTest skip(Throwable t) { - return skip(t, null); - } - - /** - * Logs an event with Status.SKIP and custom {@link Markup} such as: - * - *
    - *
  • Code block
  • - *
  • Label
  • - *
  • Table
  • - *
- * - * @param m {@link Markup} - * - * @return {@link ExtentTest} object - */ - public ExtentTest skip(Markup m) { - log(Status.SKIP, m); - return this; - } - - /** - * Logs an Status.DEBUG event with an exception and a media object: - * {@link Screencast} or {@link ScreenCapture} - * - * @param details Details - * @param provider A {@link MediaEntityModelProvider} object - * - * @return An {@link ExtentTest} object - */ - public ExtentTest debug(String details, MediaEntityModelProvider provider) { - log(Status.DEBUG, details, provider); - return this; - } - - /** - * Logs an event Status.DEBUG with details - * - * @param details Details - * - * @return {@link ExtentTest} object - */ - public ExtentTest debug(String details) { - return debug(details, null); - } - - /** - * Logs an Status.DEBUG event with an exception and a media object: - * {@link Screencast} or {@link ScreenCapture} - * - *

- * Example: - *

- * - *
-     * Exception exception = new NullPointerException();
-     * test.debug(exception, MediaEntityBuilder.createScreenCaptureFromPath("screen.png").build());
-     * 
- * - * @param t {@link Throwable} - * @param provider A {@link MediaEntityModelProvider} object - * - * @return An {@link ExtentTest} object - */ - public ExtentTest debug(Throwable t, MediaEntityModelProvider provider) { - log(Status.DEBUG, t, provider); - return this; - } - - /** - * Logs an event with Status.SKIP and exception - * - * @param t {@link Throwable} - * - * @return {@link ExtentTest} object - */ - public ExtentTest debug(Throwable t) { - return debug(t, null); - } - - /** - * Logs an event with Status.DEBUG and custom {@link Markup} such as: - * - *
    - *
  • Code block
  • - *
  • Label
  • - *
  • Table
  • - *
- * - * @param m {@link Markup} - * - * @return {@link ExtentTest} object - */ - public ExtentTest debug(Markup m) { - log(Status.DEBUG, m); - return this; - } - - /** - * Assigns a category or group - * - * @param category Category name - * - * @return {@link ExtentTest} object - */ - public ExtentTest assignCategory(String... category) { - if (category == null) - return this; - - Arrays.stream(category) - .filter(StringUtil::isNotNullOrEmpty) - .forEach(c -> { - Category objCategory = new Category(c.replace(" ", "")); - test.setCategory(objCategory); - extent.assignCategory(test, objCategory); - } - ); - return this; - } - - /** - * Assigns an author - * - * @param author Author name - * - * @return {@link ExtentTest} object - */ - public ExtentTest assignAuthor(String... author) { - Arrays.stream(author) - .filter(StringUtil::isNotNullOrEmpty) - .forEach(x -> { - Author a = new Author(x.replace(" ", "")); - test.setAuthor(a); - extent.assignAuthor(test, a); - } - ); - return this; - } - - /** - * Assign a device - * - * @param device Device name - * - * @return {@link ExtentTest} object - */ - public ExtentTest assignDevice(String... device) { - Arrays.stream(device) - .filter(StringUtil::isNotNullOrEmpty) - .forEach(x -> { - Device d = new Device(x.replace(" ", "")); - test.setDevice(d); - extent.assignDevice(test, d); - } - ); - return this; - } - - @Override - public ExtentTest addScreenCaptureFromPath(String imagePath, String title) throws IOException { - if (imagePath == null || imagePath.isEmpty()) - throw new IllegalArgumentException("imagePath cannot be null or empty"); - - ScreenCapture screenCapture = new ScreenCapture(); - screenCapture.setPath(imagePath); - if (title != null) { - screenCapture.setName(title); - } - screenCapture.setMediaType(MediaType.IMG); - if (test.getObjectId() != null) { - screenCapture.setTestObjectId(test.getObjectId()); - } - extent.addScreenCapture(test, screenCapture); - return addScreenCapture(screenCapture); - } - - private ExtentTest addScreenCapture(ScreenCapture screenCapture) { - test.setScreenCapture(screenCapture); - if (test.getObjectId() != null) { - int sequence = test.getScreenCaptureList().size(); - screenCapture.setTestObjectId(test.getObjectId()); - screenCapture.setSequence(sequence); - } - return this; - } - - @Override - public ExtentTest addScreenCaptureFromPath(String imagePath) throws IOException { - return addScreenCaptureFromPath(imagePath, null); - } - - @Override - public ExtentTest addScreenCaptureFromBase64String(String s, String title) { - ScreenCapture screenCapture = new ScreenCapture(); - screenCapture.setBase64String(s); - screenCapture.setName(title); - screenCapture.setMediaType(MediaType.IMG); - - if (test.getObjectId() != null) - screenCapture.setTestObjectId(test.getObjectId()); - - try { - extent.addScreenCapture(test, screenCapture); - } catch (IOException e) {} - - return addScreenCapture(screenCapture); - } - - @Override - public ExtentTest addScreenCaptureFromBase64String(String s) { - return addScreenCaptureFromBase64String(s, null); - } - - @Override - public ExtentTest addScreencastFromPath(String screencastPath) throws IOException { - Screencast screencast = new Screencast(); - screencast.setPath(screencastPath); - screencast.setMediaType(MediaType.VID); - test.setScreencast(screencast); - if (test.getObjectId() != null) { - int sequence = test.getScreencastList().size(); - screencast.setTestObjectId(test.getObjectId()); - screencast.setSequence(sequence); - } - extent.addScreencast(test, screencast); - return this; - } - - /** - * Provides the current run status of the test or node - * - * @return {@link Status} - */ - public Status getStatus() { - return getModel().getStatus(); - } - - /** - * Returns the underlying test which controls the internal model - * - * @return {@link Test} object - */ - public Test getModel() { - return test; - } - - /** - * Returns the {@link ExtentReports} instance associated with this test - * - * @return the {@link ExtentReports} instance associated with this test - */ - public ExtentReports getExtent() { - return extent; - } - - void setUseManualConfiguration(Boolean b) { - getModel().setUseManualConfiguration(b); - } - + *
+ * + * @param t {@link Throwable} + * @param provider A {@link MediaEntityModelProvider} object + * + * @return An {@link ExtentTest} object + */ + public ExtentTest skip(Throwable t, MediaEntityModelProvider provider) { + log(Status.SKIP, t, provider); + return this; + } + + /** + * Logs an event with Status.SKIP and exception + * + * @param t {@link Throwable} + * + * @return {@link ExtentTest} object + */ + public ExtentTest skip(Throwable t) { + return skip(t, null); + } + + /** + * Logs an event with Status.SKIP and custom {@link Markup} such + * as: + * + *
    + *
  • Code block
  • + *
  • Label
  • + *
  • Table
  • + *
+ * + * @param m {@link Markup} + * + * @return {@link ExtentTest} object + */ + public ExtentTest skip(Markup m) { + log(Status.SKIP, m); + return this; + } + + /** + * Logs an Status.DEBUG event with an exception and a media object: + * {@link ScreenCapture} + * + * @param details Details + * @param provider A {@link MediaEntityModelProvider} object + * + * @return An {@link ExtentTest} object + */ + public ExtentTest debug(String details, MediaEntityModelProvider provider) { + log(Status.DEBUG, details, provider); + return this; + } + + /** + * Logs an event Status.DEBUG with details + * + * @param details Details + * + * @return {@link ExtentTest} object + */ + public ExtentTest debug(String details) { + return debug(details, null); + } + + /** + * Logs an Status.DEBUG event with an exception and a media object: + * {@link ScreenCapture} + * + *

+ * Example: + *

+ * + *
+	 * Exception exception = new NullPointerException();
+	 * test.debug(exception, MediaEntityBuilder.createScreenCaptureFromPath("screen.png").build());
+	 * 
+ * + * @param t {@link Throwable} + * @param provider A {@link MediaEntityModelProvider} object + * + * @return An {@link ExtentTest} object + */ + public ExtentTest debug(Throwable t, MediaEntityModelProvider provider) { + log(Status.DEBUG, t, provider); + return this; + } + + /** + * Logs an event with Status.SKIP and exception + * + * @param t {@link Throwable} + * + * @return {@link ExtentTest} object + */ + public ExtentTest debug(Throwable t) { + return debug(t, null); + } + + /** + * Logs an event with Status.DEBUG and custom {@link Markup} such + * as: + * + *
    + *
  • Code block
  • + *
  • Label
  • + *
  • Table
  • + *
+ * + * @param m {@link Markup} + * + * @return {@link ExtentTest} object + */ + public ExtentTest debug(Markup m) { + log(Status.DEBUG, m); + return this; + } + + /** + * Assigns a category or group + * + * @param category Category name + * + * @return {@link ExtentTest} object + */ + public ExtentTest assignCategory(String... category) { + if (category == null) { + return this; + } + Arrays.stream(category).filter(StringUtil::isNotNullOrEmpty).forEach(c -> { + Category cat = new Category(c.replace(" ", "")); + test.getCategoryContext().add(cat); + extent.assignCategory(test, cat); + }); + return this; + } + + /** + * Assigns an author + * + * @param author Author name + * + * @return {@link ExtentTest} object + */ + public ExtentTest assignAuthor(String... author) { + Arrays.stream(author).filter(StringUtil::isNotNullOrEmpty).forEach(x -> { + Author a = new Author(x.replace(" ", "")); + test.getAuthorContext().add(a); + extent.assignAuthor(test, a); + }); + return this; + } + + /** + * Assign a device + * + * @param device Device name + * + * @return {@link ExtentTest} object + */ + public ExtentTest assignDevice(String... device) { + Arrays.stream(device).filter(StringUtil::isNotNullOrEmpty).forEach(x -> { + Device d = new Device(x.replace(" ", "")); + test.getDeviceContext().add(d); + extent.assignDevice(test, d); + }); + return this; + } + + @Override + public ExtentTest addScreenCaptureFromPath(String imagePath, String title) throws IOException { + if (imagePath == null || imagePath.isEmpty()) + throw new IllegalArgumentException("imagePath cannot be null or empty"); + + ScreenCapture screenCapture = new ScreenCapture(); + screenCapture.setPath(imagePath); + if (title != null) { + screenCapture.setName(title); + } + /* + * if (test.getObjectId() != null) { + * screenCapture.setTestObjectId(test.getObjectId()); } + */ + extent.addScreenCapture(test, screenCapture); + return addScreenCapture(screenCapture); + } + + private ExtentTest addScreenCapture(ScreenCapture screenCapture) { + test.getScreenCaptureContext().add(screenCapture); + /* + * if (test.getObjectId() != null) { int sequence = + * test.getScreenCaptureList().size(); + * screenCapture.setTestObjectId(test.getObjectId()); + * screenCapture.setSequence(sequence); } + */ + return this; + } + + @Override + public ExtentTest addScreenCaptureFromPath(String imagePath) throws IOException { + return addScreenCaptureFromPath(imagePath, null); + } + + @Override + public ExtentTest addScreenCaptureFromBase64String(String s, String title) { + ScreenCapture screenCapture = new ScreenCapture(); + screenCapture.setBase64String(s); + screenCapture.setName(title); + + /* + * if (test.getObjectId() != null) + * screenCapture.setTestObjectId(test.getObjectId()); + */ + + try { + extent.addScreenCapture(test, screenCapture); + } catch (IOException e) { + } + + return addScreenCapture(screenCapture); + } + + @Override + public ExtentTest addScreenCaptureFromBase64String(String s) { + return addScreenCaptureFromBase64String(s, null); + } + + /** + * Provides the current run status of the test or node + * + * @return {@link Status} + */ + public Status getStatus() { + extent.generateRecentStatus(); + return getModel().getStatus(); + } + + /** + * Returns the underlying test which controls the internal model + * + * @return {@link Test} object + */ + public Test getModel() { + return test; + } + + /** + * Returns the {@link ExtentReports} instance associated with this test + * + * @return the {@link ExtentReports} instance associated with this test + */ + public ExtentReports getExtent() { + return extent; + } + + void setUseManualConfiguration(Boolean b) { + getModel().setUsesManualConfiguration(b); + } + } \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/GherkinKeyword.java b/src/main/java/com/aventstack/extentreports/GherkinKeyword.java index 49a2d53..f61ca5e 100644 --- a/src/main/java/com/aventstack/extentreports/GherkinKeyword.java +++ b/src/main/java/com/aventstack/extentreports/GherkinKeyword.java @@ -6,7 +6,6 @@ import java.util.logging.Level; import java.util.logging.Logger; -import com.aventstack.extentreports.exceptions.GherkinKeywordNotFoundException; import com.aventstack.extentreports.gherkin.GherkinDialect; import com.aventstack.extentreports.gherkin.GherkinDialectProvider; import com.aventstack.extentreports.gherkin.model.Asterisk; @@ -15,16 +14,18 @@ import freemarker.template.utility.StringUtil; /** - * Allows {@link IGherkinFormatterModel} to be returned by using a name, from the below gherkin model classes: + * Allows {@link IGherkinFormatterModel} to be returned by using a name, from + * the below gherkin model classes: * *
    - *
  • {@link com.aventstack.extentreports.gherkin.model.Feature}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Background}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Scenario}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Given}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.When}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Then}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.And}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Feature}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Background}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Scenario}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Given}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.When}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Then}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.And}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.But}
  • *
* *

@@ -41,46 +42,46 @@ public class GherkinKeyword { private static final Logger logger = Logger.getLogger(GherkinKeyword.class.getName()); - - private Class clazz = IGherkinFormatterModel.class; - private IGherkinFormatterModel keywordClazz; - - public GherkinKeyword(String keyword) throws ClassNotFoundException { - GherkinDialect dialect = null; - String apiKeyword = StringUtil.capitalize(keyword.trim()); - String refPath = clazz.getPackage().getName(); - - try { - apiKeyword = apiKeyword.equals("*") ? Asterisk.class.getSimpleName() : apiKeyword; - dialect = GherkinDialectProvider.getDialect(); - if (dialect != null && !dialect.getLanguage().equalsIgnoreCase(GherkinDialectProvider.getDefaultLanguage())) { - apiKeyword = null; - Map> keywords = dialect.getKeywords(); - - for (Entry> key : keywords.entrySet()) { - boolean keywordLocated = key.getValue() - .stream() - .anyMatch(x -> x.trim().equalsIgnoreCase(keyword.trim())); - if (keywordLocated) { - apiKeyword = StringUtil.capitalize(key.getKey()); - break; - } - } - } - - if (apiKeyword == null) { - throw new GherkinKeywordNotFoundException("Keyword " + apiKeyword + " cannot be null"); - } - - String clazzName = refPath + "." + apiKeyword.replace(" ", ""); - Class c = Class.forName(clazzName); - keywordClazz = (IGherkinFormatterModel) c.newInstance(); - } catch (InstantiationException | IllegalAccessException e) { - logger.log(Level.SEVERE, "", e); - } - } - - IGherkinFormatterModel getKeyword() { - return keywordClazz; - } -} + + private Class clazz = IGherkinFormatterModel.class; + private IGherkinFormatterModel keywordClazz; + + public GherkinKeyword(String keyword) throws ClassNotFoundException { + GherkinDialect dialect = null; + String apiKeyword = StringUtil.capitalize(keyword.trim()); + String refPath = clazz.getPackage().getName(); + + try { + apiKeyword = apiKeyword.equals("*") ? Asterisk.class.getSimpleName() : apiKeyword; + dialect = GherkinDialectProvider.getDialect(); + if (dialect != null + && !dialect.getLanguage().equalsIgnoreCase(GherkinDialectProvider.getDefaultLanguage())) { + apiKeyword = null; + Map> keywords = dialect.getKeywords(); + + for (Entry> key : keywords.entrySet()) { + boolean keywordLocated = key.getValue().stream() + .anyMatch(x -> x.trim().equalsIgnoreCase(keyword.trim())); + if (keywordLocated) { + apiKeyword = StringUtil.capitalize(key.getKey()); + break; + } + } + } + + if (apiKeyword == null) { + throw new GherkinKeywordNotFoundException("Keyword " + apiKeyword + " cannot be null"); + } + + String clazzName = refPath + "." + apiKeyword.replace(" ", ""); + Class c = Class.forName(clazzName); + keywordClazz = (IGherkinFormatterModel) c.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + logger.log(Level.SEVERE, "", e); + } + } + + IGherkinFormatterModel getKeyword() { + return keywordClazz; + } +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/exceptions/GherkinKeywordNotFoundException.java b/src/main/java/com/aventstack/extentreports/GherkinKeywordNotFoundException.java similarity index 53% rename from src/main/java/com/aventstack/extentreports/exceptions/GherkinKeywordNotFoundException.java rename to src/main/java/com/aventstack/extentreports/GherkinKeywordNotFoundException.java index 2e623a3..198412f 100644 --- a/src/main/java/com/aventstack/extentreports/exceptions/GherkinKeywordNotFoundException.java +++ b/src/main/java/com/aventstack/extentreports/GherkinKeywordNotFoundException.java @@ -1,12 +1,11 @@ -package com.aventstack.extentreports.exceptions; +package com.aventstack.extentreports; -public class GherkinKeywordNotFoundException - extends ClassNotFoundException { +public class GherkinKeywordNotFoundException extends ClassNotFoundException { private static final long serialVersionUID = 3140022717738862603L; public GherkinKeywordNotFoundException(String message) { super(message); } - -} + +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/IAddsMedia.java b/src/main/java/com/aventstack/extentreports/IAddsMedia.java new file mode 100644 index 0000000..daff630 --- /dev/null +++ b/src/main/java/com/aventstack/extentreports/IAddsMedia.java @@ -0,0 +1,55 @@ +package com.aventstack.extentreports; + +import java.io.IOException; + +public interface IAddsMedia { + + /** + * Adds a snapshot to the test or log with title + * + * @param mediaPath Image path + * @param title Image title + * + * @return Object this method is called from, generally + * {@link com.aventstack.extentreports.ExtentTest} or {@link com.aventstack.extentreports.model.Log} + * + * @throws IOException thrown if the imagePath of image is not + * found + */ + T addScreenCaptureFromPath(String mediaPath, String title) throws IOException; + + /** + * Adds a snapshot to test or log + * + * @param mediaPath Image path + * + * @return Object this method is called from, generally + * {@link com.aventstack.extentreports.ExtentTest} or {@link com.aventstack.extentreports.model.Log} + * + * @throws IOException thrown if the imagePath of image is not + * found + */ + T addScreenCaptureFromPath(String mediaPath) throws IOException; + + /** + * Adds a base64 screenshot + * + * @param base64 base64 string + * @param title Image title + * + * @return Object this method is called from, generally + * {@link com.aventstack.extentreports.ExtentTest} or {@link com.aventstack.extentreports.model.Log} + */ + T addScreenCaptureFromBase64String(String base64, String title); + + /** + * Adds a base64 screenshot + * + * @param base64 base64 string + * + * @return Object this method is called from, generally + * {@link com.aventstack.extentreports.ExtentTest} or {@link com.aventstack.extentreports.model.Log} + */ + T addScreenCaptureFromBase64String(String base64); + +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/AnalysisStrategyService.java b/src/main/java/com/aventstack/extentreports/IAnalysisStrategyMethod.java similarity index 83% rename from src/main/java/com/aventstack/extentreports/AnalysisStrategyService.java rename to src/main/java/com/aventstack/extentreports/IAnalysisStrategyMethod.java index c89664f..4a92a99 100644 --- a/src/main/java/com/aventstack/extentreports/AnalysisStrategyService.java +++ b/src/main/java/com/aventstack/extentreports/IAnalysisStrategyMethod.java @@ -4,10 +4,10 @@ * Marker interface for a class that uses an {@link AnalysisStrategy} * */ -public interface AnalysisStrategyService { +public interface IAnalysisStrategyMethod { void setAnalysisStrategy(AnalysisStrategy strategy); AnalysisStrategy getAnalysisStrategy(); -} +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/exceptions/InvalidAnalysisStrategyException.java b/src/main/java/com/aventstack/extentreports/InvalidAnalysisStrategyException.java similarity index 81% rename from src/main/java/com/aventstack/extentreports/exceptions/InvalidAnalysisStrategyException.java rename to src/main/java/com/aventstack/extentreports/InvalidAnalysisStrategyException.java index dabf365..4ab1c81 100644 --- a/src/main/java/com/aventstack/extentreports/exceptions/InvalidAnalysisStrategyException.java +++ b/src/main/java/com/aventstack/extentreports/InvalidAnalysisStrategyException.java @@ -1,4 +1,4 @@ -package com.aventstack.extentreports.exceptions; +package com.aventstack.extentreports; public class InvalidAnalysisStrategyException extends IllegalArgumentException { @@ -7,5 +7,5 @@ public class InvalidAnalysisStrategyException extends IllegalArgumentException { public InvalidAnalysisStrategyException(String message) { super(message); } - -} + +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/MediaEntityBuilder.java b/src/main/java/com/aventstack/extentreports/MediaEntityBuilder.java index 7c11ca6..e008747 100644 --- a/src/main/java/com/aventstack/extentreports/MediaEntityBuilder.java +++ b/src/main/java/com/aventstack/extentreports/MediaEntityBuilder.java @@ -3,7 +3,6 @@ import java.io.IOException; import com.aventstack.extentreports.model.Media; -import com.aventstack.extentreports.model.MediaType; import com.aventstack.extentreports.model.ScreenCapture; /** @@ -13,55 +12,59 @@ public class MediaEntityBuilder { private static ThreadLocal media = new ThreadLocal<>(); - + private static class MediaBuilderInstance { - static final MediaEntityBuilder INSTANCE = new MediaEntityBuilder(); - - private MediaBuilderInstance() { } - } - - private MediaEntityBuilder() { } - - private static synchronized MediaEntityBuilder getInstance() { - return MediaBuilderInstance.INSTANCE; - } - + static final MediaEntityBuilder INSTANCE = new MediaEntityBuilder(); + + private MediaBuilderInstance() { + } + } + + private MediaEntityBuilder() { + } + + private static synchronized MediaEntityBuilder getInstance() { + return MediaBuilderInstance.INSTANCE; + } + public MediaEntityModelProvider build() { return new MediaEntityModelProvider(media.get()); } - - public static synchronized MediaEntityBuilder createScreenCaptureFromPath(String path, String title) throws IOException { - if (path == null || path.isEmpty()) - throw new IOException("ScreenCapture path cannot be null or empty."); - - return createScreenCapture(path, title, false); - } - - public static synchronized MediaEntityBuilder createScreenCaptureFromPath(String path) throws IOException { - return createScreenCaptureFromPath(path, null); - } - - public static synchronized MediaEntityBuilder createScreenCaptureFromBase64String(String base64String) throws IOException { - if (base64String == null || base64String.trim().equals("")) - throw new IOException("Base64 string cannot be null or empty."); - - return createScreenCapture(base64String, null, true); - } - - private static synchronized MediaEntityBuilder createScreenCapture(String pathOrBase64String, String title, boolean isBase64String) { - ScreenCapture sc = new ScreenCapture(); - sc.setMediaType(MediaType.IMG); - if (isBase64String) - sc.setBase64String(pathOrBase64String); - else - sc.setPath(pathOrBase64String); - - if (title != null) - sc.setName(title); - - media.set(sc); - - return getInstance(); - } - -} + + public static synchronized MediaEntityBuilder createScreenCaptureFromPath(String path, String title) + throws IOException { + if (path == null || path.isEmpty()) + throw new IOException("ScreenCapture path cannot be null or empty."); + + return createScreenCapture(path, title, false); + } + + public static synchronized MediaEntityBuilder createScreenCaptureFromPath(String path) throws IOException { + return createScreenCaptureFromPath(path, null); + } + + public static synchronized MediaEntityBuilder createScreenCaptureFromBase64String(String base64String) + throws IOException { + if (base64String == null || base64String.trim().equals("")) + throw new IOException("Base64 string cannot be null or empty."); + + return createScreenCapture(base64String, null, true); + } + + private static synchronized MediaEntityBuilder createScreenCapture(String pathOrBase64String, String title, + boolean isBase64String) { + ScreenCapture sc = new ScreenCapture(); + if (isBase64String) + sc.setBase64String(pathOrBase64String); + else + sc.setPath(pathOrBase64String); + + if (title != null) + sc.setName(title); + + media.set(sc); + + return getInstance(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/MediaEntityModelProvider.java b/src/main/java/com/aventstack/extentreports/MediaEntityModelProvider.java index 3b2f290..ef13f46 100644 --- a/src/main/java/com/aventstack/extentreports/MediaEntityModelProvider.java +++ b/src/main/java/com/aventstack/extentreports/MediaEntityModelProvider.java @@ -2,10 +2,6 @@ import com.aventstack.extentreports.model.Media; -/** - * Media singleton - * - */ public class MediaEntityModelProvider { private Media m; @@ -18,4 +14,4 @@ public Media getMedia() { return m; } -} +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/ReportAggregates.java b/src/main/java/com/aventstack/extentreports/ReportAggregates.java index de16347..e1558f2 100644 --- a/src/main/java/com/aventstack/extentreports/ReportAggregates.java +++ b/src/main/java/com/aventstack/extentreports/ReportAggregates.java @@ -1,5 +1,6 @@ package com.aventstack.extentreports; +import java.util.Collection; import java.util.Date; import java.util.List; @@ -7,6 +8,9 @@ import com.aventstack.extentreports.model.Category; import com.aventstack.extentreports.model.Device; import com.aventstack.extentreports.model.Test; +import com.aventstack.extentreports.model.context.ExceptionTestContextStore; +import com.aventstack.extentreports.model.context.SystemAttributeContext; +import com.aventstack.extentreports.model.context.TestAttributeTestContextStore; /** * Aggregator for report elements and collections @@ -16,16 +20,16 @@ public class ReportAggregates { private List testList; private List testRunnerLogs; - private TestAttributeTestContextProvider categoryContext; - private TestAttributeTestContextProvider authorContext; - private TestAttributeTestContextProvider deviceContext; - private ExceptionTestContextImpl exceptionContext; + private TestAttributeTestContextStore categoryContext; + private TestAttributeTestContextStore authorContext; + private TestAttributeTestContextStore deviceContext; + private ExceptionTestContextStore exceptionContext; private SystemAttributeContext systemAttributeContext; private ReportStatusStats reportStatusStats; - private List statusList; + private Collection statusCollection; private Date startTime; private Date endTime; - + public Date getStartTime() { return startTime; } @@ -43,7 +47,7 @@ public void setEndTime(Date endTime) { } public Status getStatus() { - return Status.getHighestStatus(getStatusList()); + return Status.getHighestStatus(getStatusCollection()); } public List getTestList() { @@ -62,35 +66,35 @@ public void setTestRunnerLogs(List testRunnerLogs) { this.testRunnerLogs = testRunnerLogs; } - public TestAttributeTestContextProvider getCategoryContext() { + public TestAttributeTestContextStore getCategoryContext() { return categoryContext; } - public void setCategoryContext(TestAttributeTestContextProvider categoryContext) { + public void setCategoryContext(TestAttributeTestContextStore categoryContext) { this.categoryContext = categoryContext; } - public TestAttributeTestContextProvider getAuthorContext() { + public TestAttributeTestContextStore getAuthorContext() { return authorContext; } - public void setAuthorContext(TestAttributeTestContextProvider authorContext) { + public void setAuthorContext(TestAttributeTestContextStore authorContext) { this.authorContext = authorContext; } - public TestAttributeTestContextProvider getDeviceContext() { + public TestAttributeTestContextStore getDeviceContext() { return deviceContext; } - public void setDeviceContext(TestAttributeTestContextProvider deviceContext) { + public void setDeviceContext(TestAttributeTestContextStore deviceContext) { this.deviceContext = deviceContext; } - public ExceptionTestContextImpl getExceptionContext() { + public ExceptionTestContextStore getExceptionContext() { return exceptionContext; } - public void setExceptionContext(ExceptionTestContextImpl exceptionContext) { + public void setExceptionContext(ExceptionTestContextStore exceptionContext) { this.exceptionContext = exceptionContext; } @@ -110,12 +114,12 @@ public void setReportStatusStats(ReportStatusStats reportStatusStats) { this.reportStatusStats = reportStatusStats; } - public List getStatusList() { - return statusList; + public Collection getStatusCollection() { + return statusCollection; } - public void setStatusList(List statusList) { - this.statusList = statusList; + public void setStatusCollection(Collection statusCollection) { + this.statusCollection = statusCollection; } -} +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/ReportAggregatesBuilder.java b/src/main/java/com/aventstack/extentreports/ReportAggregatesBuilder.java index d2e7084..bea527a 100644 --- a/src/main/java/com/aventstack/extentreports/ReportAggregatesBuilder.java +++ b/src/main/java/com/aventstack/extentreports/ReportAggregatesBuilder.java @@ -1,5 +1,6 @@ package com.aventstack.extentreports; +import java.util.Collection; import java.util.Date; import java.util.List; @@ -7,6 +8,9 @@ import com.aventstack.extentreports.model.Category; import com.aventstack.extentreports.model.Device; import com.aventstack.extentreports.model.Test; +import com.aventstack.extentreports.model.context.ExceptionTestContextStore; +import com.aventstack.extentreports.model.context.SystemAttributeContext; +import com.aventstack.extentreports.model.context.TestAttributeTestContextStore; /** * Builds {@link ReportAggregates} @@ -16,29 +20,29 @@ public class ReportAggregatesBuilder { private List testList; private List testRunnerLogs; - private TestAttributeTestContextProvider categoryContext; - private TestAttributeTestContextProvider authorContext; - private TestAttributeTestContextProvider deviceContext; - private ExceptionTestContextImpl exceptionContext; + private TestAttributeTestContextStore categoryContext; + private TestAttributeTestContextStore authorContext; + private TestAttributeTestContextStore deviceContext; + private ExceptionTestContextStore exceptionContext; private SystemAttributeContext systemAttributeContext; private ReportStatusStats reportStatusStats; - private List statusList; + private Collection statusCollection; private Date startTime; private Date endTime; - + public ReportAggregates build() { - ReportAggregates aggregates = new ReportAggregates(); - aggregates.setTestList(testList); - aggregates.setTestRunnerLogs(testRunnerLogs); - aggregates.setCategoryContext(categoryContext); - aggregates.setAuthorContext(authorContext); - aggregates.setDeviceContext(deviceContext); - aggregates.setExceptionContext(exceptionContext); - aggregates.setSystemAttributeContext(systemAttributeContext); - aggregates.setReportStatusStats(reportStatusStats); - aggregates.setStatusList(statusList); - aggregates.setStartTime(startTime); - aggregates.setEndTime(endTime); + ReportAggregates aggregates = new ReportAggregates(); + aggregates.setTestList(testList); + aggregates.setTestRunnerLogs(testRunnerLogs); + aggregates.setCategoryContext(categoryContext); + aggregates.setAuthorContext(authorContext); + aggregates.setDeviceContext(deviceContext); + aggregates.setExceptionContext(exceptionContext); + aggregates.setSystemAttributeContext(systemAttributeContext); + aggregates.setReportStatusStats(reportStatusStats); + aggregates.setStatusCollection(statusCollection); + aggregates.setStartTime(startTime); + aggregates.setEndTime(endTime); return aggregates; } @@ -52,22 +56,22 @@ public ReportAggregatesBuilder setTestRunnerLogs(List testRunnerLogs) { return this; } - public ReportAggregatesBuilder setCategoryContext(TestAttributeTestContextProvider categoryContext) { + public ReportAggregatesBuilder setCategoryContext(TestAttributeTestContextStore categoryContext) { this.categoryContext = categoryContext; return this; } - public ReportAggregatesBuilder setAuthorContext(TestAttributeTestContextProvider authorContext) { + public ReportAggregatesBuilder setAuthorContext(TestAttributeTestContextStore authorContext) { this.authorContext = authorContext; return this; } - public ReportAggregatesBuilder setDeviceContext(TestAttributeTestContextProvider deviceContext) { + public ReportAggregatesBuilder setDeviceContext(TestAttributeTestContextStore deviceContext) { this.deviceContext = deviceContext; return this; } - public ReportAggregatesBuilder setExceptionContext(ExceptionTestContextImpl exceptionContext) { + public ReportAggregatesBuilder setExceptionContext(ExceptionTestContextStore exceptionContext) { this.exceptionContext = exceptionContext; return this; } @@ -82,19 +86,19 @@ public ReportAggregatesBuilder setReportStatusStats(ReportStatusStats reportStat return this; } - public ReportAggregatesBuilder setStatusList(List statusList) { - this.statusList = statusList; + public ReportAggregatesBuilder setStatusCollection(Collection statusCollection) { + this.statusCollection = statusCollection; + return this; + } + + public ReportAggregatesBuilder setStartTime(Date startTime) { + this.startTime = startTime; + return this; + } + + public ReportAggregatesBuilder setEndTime(Date endTime) { + this.endTime = endTime; return this; } - public ReportAggregatesBuilder setStartTime(Date startTime) { - this.startTime = startTime; - return this; - } - - public ReportAggregatesBuilder setEndTime(Date endTime) { - this.endTime = endTime; - return this; - } - -} +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/ReportAggregatesListener.java b/src/main/java/com/aventstack/extentreports/ReportAggregatesListener.java index 6a6319f..a49863c 100644 --- a/src/main/java/com/aventstack/extentreports/ReportAggregatesListener.java +++ b/src/main/java/com/aventstack/extentreports/ReportAggregatesListener.java @@ -6,88 +6,97 @@ import com.aventstack.extentreports.model.Category; import com.aventstack.extentreports.model.Device; import com.aventstack.extentreports.model.Test; +import com.aventstack.extentreports.model.context.ExceptionTestContextStore; +import com.aventstack.extentreports.model.context.SystemAttributeContext; +import com.aventstack.extentreports.model.context.TestAttributeTestContextStore; /** - * Allows sharing of aggregates/collections to be shared with the started reporter. A few examples - * of these collections include: + * Allows sharing of aggregates/collections to be shared with the started + * reporter. A few examples of these collections include: * *

    - *
  • Category context - list of all categories and associated tests
  • - *
  • Exception context - list of all exceptions and associated tests
  • - *
  • Complete list of started tests
  • - *
  • System information
  • + *
  • Category context - list of all categories and associated tests
  • + *
  • Exception context - list of all exceptions and associated tests
  • + *
  • Complete list of started tests
  • + *
  • System information
  • *
*/ public interface ReportAggregatesListener { - - /** - * Allows sharing the complete list of tests with the reporter - * - * @param testList list of all tests created by {@link ExtentReports} - */ - void setTestList(List testList); - - /** - * Passes the complete list of logs to the reporter - * - * @param logs testrunner logs - */ - void setTestRunnerLogs(List logs); - - /** - * Allows sharing the complete list of category and associated tests with the reporter - * - * @param categoryContext collection containing categories and all associated tests - */ - void setCategoryContextInfo(TestAttributeTestContextProvider categoryContext); - /** - * Allows sharing the complete list of author and associated tests with the reporter - * - * @param authorContext collection containing author and all associated tests - */ - void setAuthorContextInfo(TestAttributeTestContextProvider authorContext); - - /** - * Allows sharing the complete list of device and associated tests with the reporter - * - * @param deviceContext collection containing devices and all associated tests - */ - void setDeviceContextInfo(TestAttributeTestContextProvider deviceContext); - - - /** - * Allows sharing the complete list of exceptions and associated tests with the reporter - * - * @param exceptionContext collection containing exception and all associated tests - */ - void setExceptionContextInfo(ExceptionTestContextImpl exceptionContext); - - /** - * Passes all system information to the reporter - * - * @param systemAttributeContext system information - */ - void setSystemAttributeContext(SystemAttributeContext systemAttributeContext); - - /** - * Report Status stats of the run session for all possible levels: - * - *
    - *
  • Features/Tests
  • - *
  • Scenarios/Logs
  • - *
  • Steps
  • - *
- * - * @param sc {@link ReportStatusStats} represents stats of each hierarchical level of test/event - */ - void setReportStatusStats(ReportStatusStats sc); - - /** - * A distinct list of status assigned to tests - * - * @param statusList a distinct list of {@link Status} - */ - void setStatusList(List statusList); - -} + /** + * Allows sharing the complete list of tests with the reporter + * + * @param testList list of all tests created by {@link ExtentReports} + */ + void setTestList(List testList); + + /** + * Passes the complete list of logs to the reporter + * + * @param logs testrunner logs + */ + void setTestRunnerLogs(List logs); + + /** + * Allows sharing the complete list of category and associated tests with the + * reporter + * + * @param categoryContext collection containing categories and all associated + * tests + */ + void setCategoryContextInfo(TestAttributeTestContextStore categoryContext); + + /** + * Allows sharing the complete list of author and associated tests with the + * reporter + * + * @param authorContext collection containing author and all associated tests + */ + void setAuthorContextInfo(TestAttributeTestContextStore authorContext); + + /** + * Allows sharing the complete list of device and associated tests with the + * reporter + * + * @param deviceContext collection containing devices and all associated tests + */ + void setDeviceContextInfo(TestAttributeTestContextStore deviceContext); + + /** + * Allows sharing the complete list of exceptions and associated tests with the + * reporter + * + * @param exceptionContext collection containing exception and all associated + * tests + */ + void setExceptionContextInfo(ExceptionTestContextStore exceptionContext); + + /** + * Passes all system information to the reporter + * + * @param systemAttributeContext system information + */ + void setSystemAttributeContext(SystemAttributeContext systemAttributeContext); + + /** + * Report Status stats of the run session for all possible levels: + * + *
    + *
  • Features/Tests
  • + *
  • Scenarios/Logs
  • + *
  • Steps
  • + *
+ * + * @param sc {@link ReportStatusStats} represents stats of each hierarchical + * level of test/event + */ + void setReportStatusStats(ReportStatusStats sc); + + /** + * A distinct list of status assigned to tests + * + * @param statusList a distinct list of {@link Status} + */ + void setStatusList(List statusList); + +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/ReportConfigurator.java b/src/main/java/com/aventstack/extentreports/ReportConfigurator.java index 6443523..3469eaf 100644 --- a/src/main/java/com/aventstack/extentreports/ReportConfigurator.java +++ b/src/main/java/com/aventstack/extentreports/ReportConfigurator.java @@ -2,20 +2,22 @@ public class ReportConfigurator { - private static class ReportConfiguratorInstance { - static final ReportConfigurator INSTANCE = new ReportConfigurator(); - - private ReportConfiguratorInstance() { } - } + private static class ReportConfiguratorInstance { + static final ReportConfigurator INSTANCE = new ReportConfigurator(); - private ReportConfigurator() { } - - public static ReportConfigurator getInstance() { - return ReportConfiguratorInstance.INSTANCE; - } + private ReportConfiguratorInstance() { + } + } + + private ReportConfigurator() { + } + + public static ReportConfigurator getInstance() { + return ReportConfiguratorInstance.INSTANCE; + } + + public StatusConfigurator statusConfigurator() { + return StatusConfigurator.getInstance(); + } - public StatusConfigurator statusConfigurator() { - return StatusConfigurator.getInstance(); - } - } \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/ReportObservable.java b/src/main/java/com/aventstack/extentreports/ReportObservable.java new file mode 100644 index 0000000..f523429 --- /dev/null +++ b/src/main/java/com/aventstack/extentreports/ReportObservable.java @@ -0,0 +1,597 @@ +package com.aventstack.extentreports; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import com.aventstack.extentreports.model.Author; +import com.aventstack.extentreports.model.Category; +import com.aventstack.extentreports.model.Device; +import com.aventstack.extentreports.model.Log; +import com.aventstack.extentreports.model.ScreenCapture; +import com.aventstack.extentreports.model.SystemAttribute; +import com.aventstack.extentreports.model.Test; +import com.aventstack.extentreports.model.context.ExceptionTestContextStore; +import com.aventstack.extentreports.model.context.SystemAttributeContext; +import com.aventstack.extentreports.model.context.TestAttributeTestContextStore; +import com.aventstack.extentreports.model.context.helpers.TestRemover; +import com.aventstack.extentreports.model.service.ScreenCaptureService; +import com.aventstack.extentreports.model.service.TestService; +import com.aventstack.extentreports.reporter.BasicFileReporter; +import com.aventstack.extentreports.reporter.ExtentReporter; + +abstract class ReportObservable implements ReportService { + + /** + * The current AnalysisStrategy for the run session. This decides the technique + * used to count the test status at differing levels. For example, for a BDD + * style report, the levels to be calculated are Feature, Scenario and Step (3 + * levels). For a generic, non-BDD style report, levels can be dynamic. For a + * non-BDD style report, levels typically consist of: + * + *

+ * 1 level: Test
+ * Test
+ * - Event + * + *

+ * 2 levels: Test & node
+ * Test
+ * - Node
+ * -- Event + * + *

+ * 2 levels: Test, the leaf-node
+ * Test
+ * - Node
+ * -- Leaf Node
+ * --- Event + * + */ + private AnalysisStrategy strategy = AnalysisStrategy.TEST; + + /** + * Use this setting when building post-execution reports, such as from TestNG + * IReporter. This setting allows setting test with your own variables and + * prevent update by Extent. As of today, with this enabled, Extent does not use + * time-stamps for tests at the time they were created + */ + private boolean usesManualConfiguration = false; + + /** + * The status of the entire report or build + */ + private Status reportStatus = Status.PASS; + + /** + * Time the report or build was started + */ + private Date reportStartDate = Calendar.getInstance().getTime(); + + /** + * Time the report or build ended. This value is updated everytime + * flush is called + */ + private Date reportEndDate; + + /** + * A collection of tests arranged by category + */ + private TestAttributeTestContextStore categoryContext = new TestAttributeTestContextStore<>(); + + /** + * A collection of tests arranged by author + */ + private TestAttributeTestContextStore authorContext = new TestAttributeTestContextStore<>(); + + /** + * A collection of tests arranged by author + */ + private TestAttributeTestContextStore deviceContext = new TestAttributeTestContextStore<>(); + + /** + * A collection of tests arranged by exception + */ + private ExceptionTestContextStore exceptionContext = new ExceptionTestContextStore(); + + /** + * A context of all system or environment variables + */ + private SystemAttributeContext systemAttributeContext = new SystemAttributeContext(); + + /** + * A list of all {@link ExtentReporter} reporters started by the + * attachReporter method + */ + private List reporterList = new ArrayList<>(); + + /** + * Any logs added by to the test runner can be added to Extent + * + *

+ * TestNG Example: + * + *

+ * Setting logs with TestNG: + * + *

+	 * Reporter.log("hello world")
+	 * 
+ * + *

+ * Informing Extent of any logs added: + * + *

+	 * for (String s : Reporter.getOutput()) {
+	 * 	extent.setTestRunnerOutput(s);
+	 * }
+	 * 
+ */ + private List testRunnerLogs = new ArrayList<>(); + + /** + * A list of all tests created + */ + private List testList = new ArrayList<>(); + + /** + * Instance of {@link ReportStatusStats} + */ + private ReportStatusStats stats = new ReportStatusStats(strategy); + + /** + * A unique collection of statuses tests are marked with + * + *

+ * Consider a report having 10 tests: + * + *

    + *
  1. Test1: PASS
  2. + *
  3. Test2: PASS
  4. + *
  5. Test3: PASS
  6. + *
  7. Test4: SKIP
  8. + *
  9. Test5: SKIP
  10. + *
  11. Test6: FAIL
  12. + *
  13. Test7: PASS
  14. + *
  15. Test8: PASS
  16. + *
  17. Test9: FAIL
  18. + *
  19. Test10: PASS
  20. + *
+ * + *

+ * Distinct list of contained status: + * + *

    + *
  1. PASS
  2. + *
  3. SKIP
  4. + *
  5. FAIL
  6. + *
+ */ + private Set statusSet = new HashSet(); + + /** + * Path of dirs to resolve relative image path so there is a direct access + */ + private String[] imagePathResolveDir; + + protected ReportObservable() { + } + + /** + * Subscribe the reporter to receive updates when making calls to the API + * + * @param reporter {@link ExtentReporter} reporter + */ + protected void register(ExtentReporter reporter) { + reporterList.add(reporter); + reporter.start(); + } + + /** + * Unsubscribe the reporter. Calling unsubscribe will call the stop + * method and also remove the reporter from the list of started reporters + * + * @param reporter {@link ExtentReporter} reporter to unsubscribe + */ + protected void deregister(ExtentReporter reporter) { + + if (reporterList.contains((Object) reporter)) { + reporter.stop(); + reporterList.remove(reporter); + } + } + + /** + * Retrieve a list of all started reporters + * + * @return a list of {@link ExtentReporter} objects + */ + protected List getReporterCollection() { + return reporterList; + } + + /** + * Saves the started test and notifies all started reporters + * + * @param test a {@link Test} object + */ + protected synchronized void saveTest(Test test) { + testList.add(test); + reporterList.forEach(x -> x.onTestStarted(test)); + } + + /** + * Removes the test and notifies all started reporters + * + * @param test a {@link Test} object + */ + protected void removeTest(Test test) { + removeTestTestList(test); + removeTestTestAttributeContext(test); + reporterList.forEach(x -> x.onTestRemoved(test)); + } + + /** + * Removes a test from test list + * + * @param test a {@link Test} object + */ + private void removeTestTestList(Test test) { + TestRemover.remove(testList, test); + refreshReportEntities(); + } + + /** + * Removes test from test list of each context + * + * @param test a {@link Test} object + */ + private void removeTestTestAttributeContext(Test test) { + if (TestService.testHasCategory(test)) { + categoryContext.removeTest(test); + } + if (TestService.testHasAuthor(test)) { + authorContext.removeTest(test); + } + if (TestService.testHasDevice(test)) { + deviceContext.removeTest(test); + } + } + + /** + * Refreshes report entities such as {@link ReportStatusStats} and list of + * distinct {@link Status} + */ + private void refreshReportEntities() { + refreshReportStats(); + refreshStatusList(); + } + + /** + * Refresh and notify all reports of {@link ReportStatusStats} + */ + private void refreshReportStats() { + stats.refresh(testList); + } + + /** + * Refresh and notify all reports of distinct status assigned to tests + */ + private synchronized void refreshStatusList() { + statusSet.clear(); + refreshStatusList(testList); + } + + /** + * Refreshes distinct status list + * + * @param list a list of started {@link Test} + */ + private synchronized void refreshStatusList(List list) { + if (list == null || list.isEmpty()) { + return; + } + list.forEach(x -> statusSet.add(x.getStatus())); + list.forEach(x -> refreshStatusList(x.getNodeContext().getAll())); + } + + /** + * Notify reporters of the added node + * + * @param node a {@link Test} node + */ + void addNode(Test node) { + reporterList.forEach(x -> x.onNodeStarted(node)); + } + + /** + * Notifies reporters with information of added {@link Log} + * + * @param test {@link Test} to which the event is added + * @param log {@link Log} + */ + void addLog(Test test, Log log) { + reporterList.forEach(x -> x.onLogAdded(test, log)); + } + + /** + * Notifies reporters with information of added {@link Category} + * + * @param test {@link Test} to which the Category is added + * @param category {@link Category} + */ + void assignCategory(Test test, Category category) { + reporterList.forEach(x -> x.onCategoryAssigned(test, category)); + } + + /** + * Notifies reporters with information of added {@link Author} + * + * @param test {@link Test} to which the Author is added + * @param author {@link Author} + */ + void assignAuthor(Test test, Author author) { + reporterList.forEach(x -> x.onAuthorAssigned(test, author)); + } + + /** + * Notifies reporters with information of added {@link Author} + * + * @param test {@link Test} to which the Device is added + * @param device {@link Device} + */ + void assignDevice(Test test, Device device) { + reporterList.forEach(x -> x.onDeviceAssigned(test, device)); + } + + /** + * Notifies reporters with information of added {@link ScreenCapture} + * + * @param test {@link Test} to which the ScreenCapture is added + * @param screenCapture {@link ScreenCapture} + * + * @throws IOException thrown if the {@link ScreenCapture} is not found + */ + void addScreenCapture(Test test, ScreenCapture screenCapture) throws IOException { + ScreenCaptureService.resolvePath(screenCapture, imagePathResolveDir); + for (ExtentReporter r : reporterList) { + r.onScreenCaptureAdded(test, screenCapture); + } + } + + /** + * Notifies reporters with information of added {@link ScreenCapture} + * + * @param test {@link Log} to which the ScreenCapture is added + * @param screenCapture {@link ScreenCapture} + * + * @throws IOException thrown if the {@link ScreenCapture} is not found + */ + void addScreenCapture(Log log, ScreenCapture screenCapture) throws IOException { + ScreenCaptureService.resolvePath(screenCapture, imagePathResolveDir); + for (ExtentReporter r : reporterList) { + r.onScreenCaptureAdded(log, screenCapture); + } + } + + /** + * Returns the context of author with the list of tests for each + * + * @return a {@link TestAttributeTestContextStore} object + */ + protected TestAttributeTestContextStore getAuthorContextInfo() { + return authorContext; + } + + /** + * Updates the status of the report or build + * + * @param status a {@link Status} + */ + private void updateReportStatus(Status status) { + int statusIndex = Status.getStatusHierarchy().indexOf(status); + int reportStatusIndex = Status.getStatusHierarchy().indexOf(reportStatus); + + reportStatus = statusIndex < reportStatusIndex ? status : reportStatus; + } + + /** + * Ends the test + * + * @param test a {@link Test} object + */ + private void endTest(Test test) { + test.end(); + updateReportStatus(test.getStatus()); + } + + /** + * Collects and updates all run information and notifies all reporters. + * Depending upon the type of reporter, additional events can occur such as: + * + *
    + *
  • A file written to disk (eg. case of {@link BasicFileReporter}
  • + *
  • A database being updated (eg. case of KlovReporter)
  • + *
+ */ + protected synchronized void flush() { + generateRecentStatus(); + notifyReporters(); + } + + /** + * Collects run information from all tests for assigned {@link Category}, + * {@link Author}, Exception, Nodes. This also ends and updates all internal + * test information and refreshes {@link ReportStatusStats} and the distinct + * list of {@link Status} + */ + public synchronized void generateRecentStatus() { + if (testList == null || testList.isEmpty()) + return; + + reportEndDate = Calendar.getInstance().getTime(); + + for (Test test : testList) { + endTest(test); + test.setUsesManualConfiguration(getAllowManualConfig()); + if (TestService.testHasCategory(test)) { + test.getCategoryContext().getAll().forEach(x -> categoryContext.setAttributeContext((Category) x, test)); + } + if (TestService.testHasAuthor(test)) { + test.getAuthorContext().getAll().forEach(x -> authorContext.setAttributeContext((Author) x, test)); + } + if (TestService.testHasDevice(test)) { + test.getDeviceContext().getAll().forEach(x -> deviceContext.setAttributeContext((Device) x, test)); + } + if (TestService.testHasException(test)) { + test.getExceptionInfoContext().getAll().forEach(x -> exceptionContext.setExceptionContext(x, test)); + } + if (TestService.testHasChildren(test)) { + Iterator iter = test.getNodeContext().getIterator(); + while (iter.hasNext()) { + Test node = iter.next(); + copyNodeAttributeAndRunTimeInfoToAttributeContexts(node); + node.setUsesManualConfiguration(getAllowManualConfig()); + } + } + } + + refreshReportEntities(); + updateReportStartTimeForManualConfigurationSetting(); + } + + /** + * In case where manual configuration is used, calculate the correct timestamps + * based upon the timestamps assigned to tests + */ + private void updateReportStartTimeForManualConfigurationSetting() { + if (getAllowManualConfig() && !testList.isEmpty()) { + Date minDate = testList.stream().map(t -> t.getStartTime()).min(Date::compareTo).get(); + Date maxDate = testList.stream().map(t -> t.getEndTime()).max(Date::compareTo).get(); + reportStartDate = reportStartDate.getTime() > minDate.getTime() ? minDate : reportStartDate; + reportEndDate = reportEndDate.getTime() < maxDate.getTime() ? maxDate : reportEndDate; + } + } + + /** + * Traverse all nodes and refresh {@link Category}, {@link Author}, Exception + * and Node context information + * + * @param node a {@link Test} node + */ + private void copyNodeAttributeAndRunTimeInfoToAttributeContexts(Test node) { + if (TestService.testHasCategory(node)) { + node.getCategoryContext().getAll().forEach(x -> categoryContext.setAttributeContext((Category) x, node)); + } + if (TestService.testHasAuthor(node)) { + node.getAuthorContext().getAll().forEach(x -> authorContext.setAttributeContext((Author) x, node)); + } + if (TestService.testHasDevice(node)) { + node.getDeviceContext().getAll().forEach(x -> deviceContext.setAttributeContext((Device) x, node)); + } + if (TestService.testHasException(node)) { + node.getExceptionInfoContext().getAll().forEach(x -> exceptionContext.setExceptionContext(x, node)); + } + if (TestService.testHasChildren(node)) { + node.getNodeContext().getAll().forEach(this::copyNodeAttributeAndRunTimeInfoToAttributeContexts); + } + } + + /** + * Notify all reporters with complete run information + */ + private synchronized void notifyReporters() { + if (!testList.isEmpty() && TestService.isTestBehaviorDriven(testList.get(0))) { + strategy = AnalysisStrategy.BDD; + } + ReportAggregates reportAggregates = new ReportAggregatesBuilder() + .setAuthorContext(authorContext) + .setCategoryContext(categoryContext) + .setDeviceContext(deviceContext) + .setExceptionContext(exceptionContext) + .setReportStatusStats(stats) + .setStatusCollection(statusSet) + .setSystemAttributeContext(systemAttributeContext) + .setTestList(testList) + .setTestRunnerLogs(testRunnerLogs) + .setStartTime(reportStartDate) + .setEndTime(reportEndDate) + .build(); + reporterList.forEach(x -> x.setAnalysisStrategy(strategy)); + reporterList.forEach(x -> x.flush(reportAggregates)); + } + + /** + * Ends logging, stops and clears the list of reporters + */ + protected void end() { + flush(); + reporterList.forEach(ExtentReporter::stop); + reporterList.clear(); + } + + /** + * Add a system attribute + * + * @param sa a {@link SystemAttribute} object + */ + protected void setSystemInfo(SystemAttribute sa) { + systemAttributeContext.setSystemAttribute(sa); + } + + /** + * Add a test runner log + * + * @param log a log event + */ + protected void setTestRunnerLogs(String log) { + testRunnerLogs.add(log); + } + + /** + * Updates the {@link AnalysisStrategy} + * + * @param strategy a {@link AnalysisStrategy} object + */ + protected void setAnalysisStrategy(AnalysisStrategy strategy) { + this.strategy = strategy; + stats = new ReportStatusStats(strategy); + } + + protected void setMediaPathResolveDir(String[] imagePathResolveDir) { + this.imagePathResolveDir = imagePathResolveDir; + } + + /** + * Setting to allow user driven configuration for test time-stamps + * + * @param useManualConfig setting for manual configuration + */ + protected void setAllowManualConfig(boolean useManualConfig) { + this.usesManualConfiguration = useManualConfig; + } + + /** + * Returns the current value of using manual configuration for test time-stamps + * + * @return setting for manual configuration + */ + protected boolean getAllowManualConfig() { + return usesManualConfiguration; + } + + /** + * Return the {@link ReportStatusStats} object + * + * @return a {@link ReportStatusStats} object + */ + protected ReportStatusStats getStats() { + generateRecentStatus(); + return stats; + } +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/ReportService.java b/src/main/java/com/aventstack/extentreports/ReportService.java index 4fdfde2..2932d67 100644 --- a/src/main/java/com/aventstack/extentreports/ReportService.java +++ b/src/main/java/com/aventstack/extentreports/ReportService.java @@ -1,13 +1,16 @@ package com.aventstack.extentreports; import com.aventstack.extentreports.reporter.AbstractReporter; +import com.aventstack.extentreports.reporter.ExtentReporter; /** - * The main service for {@link ExtentReports} which allows attaching a reporter of type - * {@link AbstractReporter} + * The main service for {@link ExtentReports} which allows attaching a reporter + * of type {@link AbstractReporter} */ public interface ReportService { - - void attachReporter(ExtentReporter... reporter); - -} + + void attachReporter(ExtentReporter... reporter); + + void generateRecentStatus(); + +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/ReportStatusStats.java b/src/main/java/com/aventstack/extentreports/ReportStatusStats.java index 5236617..8c5a7fc 100644 --- a/src/main/java/com/aventstack/extentreports/ReportStatusStats.java +++ b/src/main/java/com/aventstack/extentreports/ReportStatusStats.java @@ -1,387 +1,602 @@ package com.aventstack.extentreports; +import java.util.Iterator; import java.util.List; -import com.aventstack.extentreports.exceptions.InvalidAnalysisStrategyException; import com.aventstack.extentreports.gherkin.model.Scenario; +import com.aventstack.extentreports.model.Log; import com.aventstack.extentreports.model.Test; /** *

- * This class maintains the total count of tests and its nodes along with - * their statuses for a given run session + * This class maintains the total count of tests and its nodes along with their + * statuses for a given run session */ public class ReportStatusStats { - - private List testList; - private AnalysisStrategy strategy = AnalysisStrategy.TEST; - - private int parentPass = 0; - private int parentFail = 0; - private int parentFatal = 0; - private int parentError = 0; - private int parentWarning = 0; - private int parentSkip = 0; - private int parentExceptions = 0; - - private int childPass = 0; - private int childFail = 0; - private int childFatal = 0; - private int childError = 0; - private int childWarning = 0; - private int childSkip = 0; - private int childInfo = 0; - private int childDebug = 0; - private int childExceptions = 0; - - private int grandChildPass = 0; - private int grandChildFail = 0; - private int grandChildFatal = 0; - private int grandChildError = 0; - private int grandChildWarning = 0; - private int grandChildSkip = 0; - private int grandChildInfo = 0; - private int grandChildDebug = 0; - private int grandChildExceptions = 0; - - public ReportStatusStats(AnalysisStrategy strategy) { - this.strategy = strategy; - } - - public void refresh(List testList) { - reset(); - this.testList = testList; - refreshStats(); - } - - private void reset() { - parentPass = 0; - parentFail = 0; - parentFatal = 0; - parentError = 0; - parentWarning = 0; - parentSkip = 0; - parentExceptions = 0; - - childPass = 0; - childFail = 0; - childFatal = 0; - childError = 0; - childWarning = 0; - childSkip = 0; - childInfo = 0; - childExceptions = 0; - - grandChildPass = 0; - grandChildFail = 0; - grandChildFatal = 0; - grandChildError = 0; - grandChildWarning = 0; - grandChildSkip = 0; - grandChildInfo = 0; - grandChildExceptions = 0; - } - - public int getParentCount() { - return getParentCountPass() + - getParentCountFail() + - getParentCountFatal() + - getParentCountError() + - getParentCountWarning() + - getParentCountSkip(); - } - public int getParentCountPass() { return parentPass; } - public int getParentCountFail() { return parentFail; } - public int getParentCountFatal() { return parentFatal; } - public int getParentCountError() { return parentError; } - public int getParentCountWarning() { return parentWarning; } - public int getParentCountSkip() { return parentSkip; } - public int getParentCountExceptions() { return parentExceptions; } - - public float getParentPercentagePass() { - float p = getParentCount() > 0 ? (float)getParentCountPass()/(float)getParentCount() : 0; - return p*100; - } - public float getParentPercentageFail() { - float p = getParentCount() > 0 ? ((float)getParentCountFail()+(float)getParentCountFatal())/(float)getParentCount() : 0; - return p*100; - } - public float getParentPercentageOthers() { - float p = getParentCount() > 0 ? ((float)getParentCountWarning()+(float)getParentCountError())/(float)getParentCount() : 0; - return p*100; - } - public float getParentPercentageSkip() { - float p = getParentCount() > 0 ? (float)getParentCountSkip()/(float)getParentCount() : 0; - return p*100; - } - - public int getChildCount() { - return getChildCountPass() + - getChildCountFail() + - getChildCountFatal() + - getChildCountError() + - getChildCountWarning() + - getChildCountSkip() + - getChildCountInfo(); - } - public int getChildCountPass() { return childPass; } - public int getChildCountFail() { return childFail; } - public int getChildCountFatal() { return childFatal; } - public int getChildCountError() { return childError; } - public int getChildCountWarning() { return childWarning; } - public int getChildCountSkip() { return childSkip; } - public int getChildCountInfo() { return childInfo; } - public int getChildCountDebug() { return childDebug; } - public int getChildCountExceptions() { return childExceptions; } - - public float getChildPercentagePass() { - float p = getChildCount() > 0 ? (float)getChildCountPass()/(float)getChildCount() : 0; - return p*100; - } - public float getChildPercentageFail() { - float p = getChildCount() > 0 ? ((float)getChildCountFail()+(float)getChildCountFatal())/(float)getChildCount() : 0; - return p*100; - } - public float getChildPercentageOthers() { - float p = getChildCount() > 0 ? (((float)getChildCountWarning()+(float)getChildCountError()+(float)getChildCountSkip()+(float)getChildCountInfo())/(float)getChildCount()) : 0; - return p*100; - } - public float getChildPercentageSkip() { - float p = getChildCount() > 0 ? (float)getChildCountSkip()/(float)getChildCount() : 0; - return p*100; - } - - public int getGrandChildCount() { - return getGrandChildCountPass() + - getGrandChildCountFail() + - getGrandChildCountFatal() + - getGrandChildCountError() + - getGrandChildCountWarning() + - getGrandChildCountSkip() + - getGrandChildCountInfo(); - } - public int getGrandChildCountPass() { return grandChildPass; } - public int getGrandChildCountFail() { return grandChildFail; } - public int getGrandChildCountFatal() { return grandChildFatal; } - public int getGrandChildCountError() { return grandChildError; } - public int getGrandChildCountWarning() { return grandChildWarning; } - public int getGrandChildCountSkip() { return grandChildSkip; } - public int getGrandChildCountInfo() { return grandChildInfo; } - public int getGrandChildCountDebug() { return grandChildDebug; } - public int getGrandChildCountExceptions() { return grandChildExceptions; } - - public float getGrandChildPercentagePass() { - float p = getGrandChildCount() > 0 ? (float)getGrandChildCountPass()/(float)getGrandChildCount() : 0; - return p*100; - } - public float getGrandChildPercentageFail() { - float p = getGrandChildCount() > 0 ? ((float)getGrandChildCountFail()+(float)getGrandChildCountFatal())/(float)getGrandChildCount() : 0; - return p*100; - } - public float getGrandChildPercentageOthers() { - float p = getGrandChildCount() > 0 ? (((float)getGrandChildCountWarning()+(float)getGrandChildCountError()+(float)getGrandChildCountSkip()+(float)getGrandChildCountInfo())/(float)getGrandChildCount()) : 0; - return p*100; - } - public float getGrandChildPercentageSkip() { - float p = getGrandChildCount() > 0 ? (float)getGrandChildCountSkip()/(float)getGrandChildCount() : 0; - return p*100; - } - - private void refreshStats() { - testList.forEach(this::addTestForStatusStatsUpdate); - } - - private void addTestForStatusStatsUpdate(Test test) { - if (test.isBehaviorDrivenType() || (test.hasChildren() && test.getNodeContext().get(0).isBehaviorDrivenType())) { - updateGroupCountsBDD(test); - return; - } - - if (strategy == AnalysisStrategy.TEST || strategy == AnalysisStrategy.CLASS) { - updateGroupCountsTestStrategy(test); - return; - } - - if (strategy == AnalysisStrategy.SUITE) { - updateGroupCountsSuiteStrategy(test); - return; - } - - throw new InvalidAnalysisStrategyException("No such strategy found: " + strategy); - } - - private void updateGroupCountsSuiteStrategy(Test test) { - incrementItemCountByStatus(ItemLevel.PARENT, test.getStatus()); - - if (test.hasChildren()) { - test.getNodeContext().getAll().forEach(x -> { - incrementItemCountByStatus(ItemLevel.CHILD, x.getStatus()); - - if (x.hasChildren()) - x.getNodeContext().getAll().forEach(n -> incrementItemCountByStatus(ItemLevel.GRANDCHILD, n.getStatus())); - }); - } - } - - private void updateGroupCountsBDD(Test test) { - incrementItemCountByStatus(ItemLevel.PARENT, test.getStatus()); - - if (test.hasChildren()) { - test.getNodeContext().getAll().forEach(x -> { - if (x.getBehaviorDrivenType() == Scenario.class) - incrementItemCountByStatus(ItemLevel.CHILD, x.getStatus()); - - if (x.hasChildren()) { - x.getNodeContext().getAll().forEach(n -> { - if (n.getBehaviorDrivenType() == Scenario.class) { - incrementItemCountByStatus(ItemLevel.CHILD, n.getStatus()); - - n.getNodeContext().getAll().forEach(z -> incrementItemCountByStatus(ItemLevel.GRANDCHILD, z.getStatus())); - } - else { - incrementItemCountByStatus(ItemLevel.GRANDCHILD, n.getStatus()); - } - }); - } - }); - } - } - - private void updateGroupCountsTestStrategy(Test test) { - incrementItemCountByStatus(ItemLevel.PARENT, test.getStatus()); - - if (test.hasChildren()) { - updateGroupCountsTestStrategyChildren(test); - } - } - - private void updateGroupCountsTestStrategyChildren(Test test) { - test.getNodeContext().getAll().forEach(x -> { - if (!x.hasChildren()) { - incrementItemCountByStatus(ItemLevel.CHILD, x.getStatus()); - } else { - updateGroupCountsTestStrategyChildren(x); - } - }); - } - - enum ItemLevel { - PARENT, - CHILD, - GRANDCHILD - } - - private void incrementItemCountByStatus(ItemLevel item, Status status) { - switch (item) { - case PARENT: - incrementParent(status); - break; - - case CHILD: - incrementChild(status); - break; - - case GRANDCHILD: - incrementGrandChild(status); - break; - - default: - break; - } - } - - private void incrementParent(Status status) { - switch (status) { - case PASS: - parentPass++; - return; - case FAIL: - parentFail++; - break; - case FATAL: - parentFatal++; - break; - case ERROR: - parentError++; - break; - case WARNING: - parentWarning++; - break; - case SKIP: - parentSkip++; - break; - default: - break; - } - - parentExceptions++; - } - - private void incrementChild(Status status) { - switch (status) { - case PASS: - childPass++; - break; - case FAIL: - childFail++; - break; - case FATAL: - childFatal++; - break; - case ERROR: - childError++; - break; - case WARNING: - childWarning++; - break; - case SKIP: - childSkip++; - break; - case INFO: - childInfo++; - break; - case DEBUG: - childDebug++; - break; - default: - break; - } - - if (status != Status.PASS && status != Status.INFO) - childExceptions++; - } - - private void incrementGrandChild(Status status) { - switch (status) { - case PASS: - grandChildPass++; - break; - case FAIL: - grandChildFail++; - break; - case FATAL: - grandChildFatal++; - break; - case ERROR: - grandChildError++; - break; - case WARNING: - grandChildWarning++; - break; - case SKIP: - grandChildSkip++; - break; - case INFO: - grandChildInfo++; - break; - case DEBUG: - grandChildDebug++; - break; - default: - break; - } - - if (status != Status.PASS && status != Status.INFO) - grandChildExceptions++; - } -} + + private List testList; + private AnalysisStrategy strategy = AnalysisStrategy.TEST; + + private int parentPass = 0; + private int parentFail = 0; + private int parentFatal = 0; + private int parentError = 0; + private int parentWarning = 0; + private int parentSkip = 0; + private int parentExceptions = 0; + + private int childPass = 0; + private int childFail = 0; + private int childFatal = 0; + private int childError = 0; + private int childWarning = 0; + private int childSkip = 0; + private int childInfo = 0; + private int childDebug = 0; + private int childExceptions = 0; + + private int grandChildPass = 0; + private int grandChildFail = 0; + private int grandChildFatal = 0; + private int grandChildError = 0; + private int grandChildWarning = 0; + private int grandChildSkip = 0; + private int grandChildInfo = 0; + private int grandChildDebug = 0; + private int grandChildExceptions = 0; + + private int eventsPass = 0; + private int eventsFail = 0; + private int eventsFatal = 0; + private int eventsError = 0; + private int eventsWarning = 0; + private int eventsSkip = 0; + private int eventsInfo = 0; + private int eventsDebug = 0; + private int eventsExceptions = 0; + + public ReportStatusStats(AnalysisStrategy strategy) { + this.strategy = strategy; + } + + public void refresh(List testList) { + reset(); + this.testList = testList; + refreshStats(); + } + + private void reset() { + parentPass = 0; + parentFail = 0; + parentFatal = 0; + parentError = 0; + parentWarning = 0; + parentSkip = 0; + parentExceptions = 0; + + childPass = 0; + childFail = 0; + childFatal = 0; + childError = 0; + childWarning = 0; + childSkip = 0; + childInfo = 0; + childExceptions = 0; + + grandChildPass = 0; + grandChildFail = 0; + grandChildFatal = 0; + grandChildError = 0; + grandChildWarning = 0; + grandChildSkip = 0; + grandChildInfo = 0; + grandChildExceptions = 0; + + eventsPass = 0; + eventsFail = 0; + eventsFatal = 0; + eventsError = 0; + eventsWarning = 0; + eventsSkip = 0; + eventsInfo = 0; + eventsDebug = 0; + eventsExceptions = 0; + } + + public int getParentCount() { + return getParentCountPass() + getParentCountFail() + getParentCountFatal() + getParentCountError() + + getParentCountWarning() + getParentCountSkip(); + } + + public int getParentCountPass() { + return parentPass; + } + + public int getParentCountFail() { + return parentFail; + } + + public int getParentCountFatal() { + return parentFatal; + } + + public int getParentCountError() { + return parentError; + } + + public int getParentCountWarning() { + return parentWarning; + } + + public int getParentCountSkip() { + return parentSkip; + } + + public int getParentCountExceptions() { + return parentExceptions; + } + + public float getParentPercentagePass() { + float p = getParentCount() > 0 ? (float) getParentCountPass() / (float) getParentCount() : 0; + return p * 100; + } + + public float getParentPercentageFail() { + float p = getParentCount() > 0 + ? ((float) getParentCountFail() + (float) getParentCountFatal()) / (float) getParentCount() + : 0; + return p * 100; + } + + public float getParentPercentageOthers() { + float p = getParentCount() > 0 + ? ((float) getParentCountWarning() + (float) getParentCountError()) / (float) getParentCount() + : 0; + return p * 100; + } + + public float getParentPercentageSkip() { + float p = getParentCount() > 0 ? (float) getParentCountSkip() / (float) getParentCount() : 0; + return p * 100; + } + + public int getChildCount() { + return getChildCountPass() + getChildCountFail() + getChildCountFatal() + getChildCountError() + + getChildCountWarning() + getChildCountSkip() + getChildCountInfo(); + } + + public int getChildCountPass() { + return childPass; + } + + public int getChildCountFail() { + return childFail; + } + + public int getChildCountFatal() { + return childFatal; + } + + public int getChildCountError() { + return childError; + } + + public int getChildCountWarning() { + return childWarning; + } + + public int getChildCountSkip() { + return childSkip; + } + + public int getChildCountInfo() { + return childInfo; + } + + public int getChildCountDebug() { + return childDebug; + } + + public int getChildCountExceptions() { + return childExceptions; + } + + public float getChildPercentagePass() { + float p = getChildCount() > 0 ? (float) getChildCountPass() / (float) getChildCount() : 0; + return p * 100; + } + + public float getChildPercentageFail() { + float p = getChildCount() > 0 + ? ((float) getChildCountFail() + (float) getChildCountFatal()) / (float) getChildCount() + : 0; + return p * 100; + } + + public float getChildPercentageOthers() { + float p = getChildCount() > 0 + ? (((float) getChildCountWarning() + (float) getChildCountError() + (float) getChildCountSkip() + + (float) getChildCountInfo()) / (float) getChildCount()) + : 0; + return p * 100; + } + + public float getChildPercentageSkip() { + float p = getChildCount() > 0 ? (float) getChildCountSkip() / (float) getChildCount() : 0; + return p * 100; + } + + public int getGrandChildCount() { + return getGrandChildCountPass() + getGrandChildCountFail() + getGrandChildCountFatal() + + getGrandChildCountError() + getGrandChildCountWarning() + getGrandChildCountSkip() + + getGrandChildCountInfo(); + } + + public int getGrandChildCountPass() { + return grandChildPass; + } + + public int getGrandChildCountFail() { + return grandChildFail; + } + + public int getGrandChildCountFatal() { + return grandChildFatal; + } + + public int getGrandChildCountError() { + return grandChildError; + } + + public int getGrandChildCountWarning() { + return grandChildWarning; + } + + public int getGrandChildCountSkip() { + return grandChildSkip; + } + + public int getGrandChildCountInfo() { + return grandChildInfo; + } + + public int getGrandChildCountDebug() { + return grandChildDebug; + } + + public int getGrandChildCountExceptions() { + return grandChildExceptions; + } + + public float getGrandChildPercentagePass() { + float p = getGrandChildCount() > 0 ? (float) getGrandChildCountPass() / (float) getGrandChildCount() : 0; + return p * 100; + } + + public float getGrandChildPercentageFail() { + float p = getGrandChildCount() > 0 + ? ((float) getGrandChildCountFail() + (float) getGrandChildCountFatal()) / (float) getGrandChildCount() + : 0; + return p * 100; + } + + public float getGrandChildPercentageOthers() { + float p = getGrandChildCount() > 0 + ? (((float) getGrandChildCountWarning() + (float) getGrandChildCountError() + + (float) getGrandChildCountSkip() + (float) getGrandChildCountInfo()) + / (float) getGrandChildCount()) + : 0; + return p * 100; + } + + public float getGrandChildPercentageSkip() { + float p = getGrandChildCount() > 0 ? (float) getGrandChildCountSkip() / (float) getGrandChildCount() : 0; + return p * 100; + } + + public int getEventsCount() { + return getEventsCountPass() + getEventsCountFail() + getEventsCountFatal() + + getEventsCountError() + getEventsCountWarning() + getEventsCountSkip() + + getEventsCountInfo(); + } + + public int getEventsCountPass() { + return eventsPass; + } + + public int getEventsCountFail() { + return eventsFail; + } + + public int getEventsCountFatal() { + return eventsFatal; + } + + public int getEventsCountError() { + return eventsError; + } + + public int getEventsCountWarning() { + return eventsWarning; + } + + public int getEventsCountSkip() { + return eventsSkip; + } + + public int getEventsCountInfo() { + return eventsInfo; + } + + public int getEventsCountDebug() { + return eventsDebug; + } + + public int getEventsCountExceptions() { + return eventsExceptions; + } + + public float getEventsPercentagePass() { + float p = getEventsCount() > 0 ? (float) getEventsCountPass() / (float) getEventsCount() : 0; + return p * 100; + } + + public float getEventsPercentageFail() { + float p = getEventsCount() > 0 + ? ((float) getEventsCountFail() + (float) getEventsCountFatal()) / (float) getEventsCount() + : 0; + return p * 100; + } + + public float getEventsPercentageOthers() { + float p = getEventsCount() > 0 + ? (((float) getEventsCountWarning() + (float) getEventsCountError() + + (float) getEventsCountSkip() + (float) getEventsCountInfo()) + / (float) getEventsCount()) + : 0; + return p * 100; + } + + public float getEventsPercentageSkip() { + float p = getEventsCount() > 0 ? (float) getEventsCountSkip() / (float) getEventsCount() : 0; + return p * 100; + } + + private void refreshStats() { + testList.forEach(this::addTestForStatusStatsUpdate); + } + + private void addTestForStatusStatsUpdate(Test test) { + updateEventsCount(test); + + if (test.getBddType() != null + || (!test.getNodeContext().isEmpty() && test.getNodeContext().get(0).getBddType() != null)) { + updateGroupCountsBDD(test); + return; + } + + if (strategy == AnalysisStrategy.TEST || strategy == AnalysisStrategy.CLASS) { + updateGroupCountsTestStrategy(test); + return; + } + + if (strategy == AnalysisStrategy.SUITE) { + updateGroupCountsSuiteStrategy(test); + return; + } + + throw new InvalidAnalysisStrategyException("No such strategy found: " + strategy); + } + + private void updateEventsCount(Test test) { + test.getLogContext().getAll().stream() + .map(Log::getStatus) + .forEach(this::incrementEvent); + Iterator iter = test.getNodeContext().getIterator(); + while (iter.hasNext()) { + Test node = iter.next(); + updateEventsCount(node); + } + } + + private void updateGroupCountsSuiteStrategy(Test test) { + incrementItemCountByStatus(ItemLevel.PARENT, test.getStatus()); + + if (!test.getNodeContext().isEmpty()) { + for (Test x : test.getNodeContext().getAll()) { + incrementItemCountByStatus(ItemLevel.CHILD, x.getStatus()); + if (!x.getNodeContext().isEmpty()) { + x.getNodeContext().getAll() + .forEach(n -> incrementItemCountByStatus(ItemLevel.GRANDCHILD, n.getStatus())); + } + } + } + } + + private void updateGroupCountsBDD(Test test) { + incrementItemCountByStatus(ItemLevel.PARENT, test.getStatus()); + + if (!test.getNodeContext().isEmpty()) { + for (Test x : test.getNodeContext().getAll()) { + if (x.getBddType() == Scenario.class) { + incrementItemCountByStatus(ItemLevel.CHILD, x.getStatus()); + } + if (!x.getNodeContext().isEmpty()) { + for (Test n : x.getNodeContext().getAll()) { + if (n.getBddType() == Scenario.class) { + incrementItemCountByStatus(ItemLevel.CHILD, n.getStatus()); + n.getNodeContext().getAll() + .forEach(z -> incrementItemCountByStatus(ItemLevel.GRANDCHILD, z.getStatus())); + } else { + incrementItemCountByStatus(ItemLevel.GRANDCHILD, n.getStatus()); + } + } + } + } + } + } + + private void updateGroupCountsTestStrategy(Test test) { + incrementItemCountByStatus(ItemLevel.PARENT, test.getStatus()); + + if (!test.getNodeContext().isEmpty()) { + updateGroupCountsTestStrategyChildren(test); + } + } + + private void updateGroupCountsTestStrategyChildren(Test test) { + test.getNodeContext().getAll().forEach(x -> { + if (x.getNodeContext().isEmpty()) { + incrementItemCountByStatus(ItemLevel.CHILD, x.getStatus()); + } else { + updateGroupCountsTestStrategyChildren(x); + } + }); + } + + enum ItemLevel { + PARENT, CHILD, GRANDCHILD + } + + private void incrementItemCountByStatus(ItemLevel item, Status status) { + switch (item) { + case PARENT: + incrementParent(status); + break; + case CHILD: + incrementChild(status); + break; + case GRANDCHILD: + incrementGrandChild(status); + break; + default: + break; + } + } + + private void incrementParent(Status status) { + switch (status) { + case PASS: + parentPass++; + return; + case FAIL: + parentFail++; + break; + case FATAL: + parentFatal++; + break; + case ERROR: + parentError++; + break; + case WARNING: + parentWarning++; + break; + case SKIP: + parentSkip++; + break; + default: + break; + } + + parentExceptions++; + } + + private void incrementChild(Status status) { + switch (status) { + case PASS: + childPass++; + break; + case FAIL: + childFail++; + break; + case FATAL: + childFatal++; + break; + case ERROR: + childError++; + break; + case WARNING: + childWarning++; + break; + case SKIP: + childSkip++; + break; + case INFO: + childInfo++; + break; + case DEBUG: + childDebug++; + break; + default: + break; + } + + if (status != Status.PASS && status != Status.INFO) + childExceptions++; + } + + private void incrementGrandChild(Status status) { + switch (status) { + case PASS: + grandChildPass++; + break; + case FAIL: + grandChildFail++; + break; + case FATAL: + grandChildFatal++; + break; + case ERROR: + grandChildError++; + break; + case WARNING: + grandChildWarning++; + break; + case SKIP: + grandChildSkip++; + break; + case INFO: + grandChildInfo++; + break; + case DEBUG: + grandChildDebug++; + break; + default: + break; + } + + if (status != Status.PASS && status != Status.INFO) + grandChildExceptions++; + } + + private void incrementEvent(Status status) { + switch (status) { + case PASS: + eventsPass++; + break; + case FAIL: + eventsFail++; + break; + case FATAL: + eventsFatal++; + break; + case ERROR: + eventsError++; + break; + case WARNING: + eventsWarning++; + break; + case SKIP: + eventsSkip++; + break; + case INFO: + eventsInfo++; + break; + case DEBUG: + eventsDebug++; + break; + default: + break; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/RunResult.java b/src/main/java/com/aventstack/extentreports/RunResult.java index b608cf9..426197f 100644 --- a/src/main/java/com/aventstack/extentreports/RunResult.java +++ b/src/main/java/com/aventstack/extentreports/RunResult.java @@ -1,5 +1,4 @@ package com.aventstack.extentreports; - /** * Marker interface for the run result with a single getStatus() method * @@ -8,4 +7,4 @@ public interface RunResult { Status getStatus(); -} +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/Status.java b/src/main/java/com/aventstack/extentreports/Status.java index 8ab30bd..f4ca613 100644 --- a/src/main/java/com/aventstack/extentreports/Status.java +++ b/src/main/java/com/aventstack/extentreports/Status.java @@ -1,7 +1,7 @@ package com.aventstack.extentreports; - import java.io.Serializable; import java.util.Arrays; +import java.util.Collection; import java.util.List; /** @@ -48,12 +48,12 @@ public static List getStatusHierarchy() { return statusHierarchy; } - public static Status getHighestStatus(List statusList) { + public static Status getHighestStatus(Collection statusCollection) { Status highestStatus = Status.PASS; - if (statusList == null || statusList.isEmpty()) { + if (statusCollection == null || statusCollection.isEmpty()) { return highestStatus; } - for (Status status : statusList) { + for (Status status : statusCollection) { highestStatus = Status.getStatusHierarchy().indexOf(status) < Status.getStatusHierarchy().indexOf(highestStatus) ? status : highestStatus; diff --git a/src/main/java/com/aventstack/extentreports/StatusConfigurator.java b/src/main/java/com/aventstack/extentreports/StatusConfigurator.java index 70713b3..9e5cc6a 100644 --- a/src/main/java/com/aventstack/extentreports/StatusConfigurator.java +++ b/src/main/java/com/aventstack/extentreports/StatusConfigurator.java @@ -4,26 +4,29 @@ public class StatusConfigurator { - private static class StatusConfiguratorInstance { - static final StatusConfigurator INSTANCE = new StatusConfigurator(); - - private StatusConfiguratorInstance() { } - } - - private StatusConfigurator() { } - - public static StatusConfigurator getInstance() { - return StatusConfiguratorInstance.INSTANCE; - } - - public List getStatusHierarchy() { - return Status.getStatusHierarchy(); - } - public void setStatusHierarchy(List statusHierarchy) { - Status.setStatusHierarchy(statusHierarchy); - } - - public void resetStatusHierarchy() { - Status.resetStatusHierarchy(); - } + private static class StatusConfiguratorInstance { + static final StatusConfigurator INSTANCE = new StatusConfigurator(); + + private StatusConfiguratorInstance() { + } + } + + private StatusConfigurator() { + } + + public static StatusConfigurator getInstance() { + return StatusConfiguratorInstance.INSTANCE; + } + + public List getStatusHierarchy() { + return Status.getStatusHierarchy(); + } + + public void setStatusHierarchy(List statusHierarchy) { + Status.setStatusHierarchy(statusHierarchy); + } + + public void resetStatusHierarchy() { + Status.resetStatusHierarchy(); + } } \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/SystemAttributeContext.java b/src/main/java/com/aventstack/extentreports/SystemAttributeContext.java deleted file mode 100644 index 1bf48ea..0000000 --- a/src/main/java/com/aventstack/extentreports/SystemAttributeContext.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.aventstack.extentreports; - -import java.util.ArrayList; -import java.util.List; - -import com.aventstack.extentreports.model.SystemAttribute; - -/** - * A simple key-value pair collection to store System/Environment information - * - */ -public class SystemAttributeContext { - - private List sysAttrCollection; - - public SystemAttributeContext() { - sysAttrCollection = new ArrayList<>(); - } - - public void setSystemAttribute(SystemAttribute sa) { - sysAttrCollection.add(sa); - } - - public List getSystemAttributeList() { return sysAttrCollection; } - - public void clear() { - sysAttrCollection.clear(); - } -} diff --git a/src/main/java/com/aventstack/extentreports/TestAttributeTestContextProvider.java b/src/main/java/com/aventstack/extentreports/TestAttributeTestContextProvider.java deleted file mode 100644 index d24b48a..0000000 --- a/src/main/java/com/aventstack/extentreports/TestAttributeTestContextProvider.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.aventstack.extentreports; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Optional; - -import com.aventstack.extentreports.model.Test; -import com.aventstack.extentreports.model.TestAttribute; -import com.aventstack.extentreports.model.TestAttributeTestContext; - -/** - * Uses an attribute context for {@link TestAttribute} (Category, Device, Author etc.) - * and tracks the collection of tests segregated by the type {@link TestAttribute} - * - * @param A {@link TestAttribute} type - */ -public class TestAttributeTestContextProvider { - - private List> testAttrCollection; - - public TestAttributeTestContextProvider() { - testAttrCollection = new ArrayList<>(); - } - - public void setAttributeContext(T attr, Test test) { - Optional> testOptionalTestContext = testAttrCollection - .stream() - .filter(x -> x.getName().equals(attr.getName())) - .findFirst(); - - if (testOptionalTestContext.isPresent()) { - List testList = testOptionalTestContext.get().getTestList(); - - boolean b = testList - .stream() - .anyMatch(t -> t.getID() == test.getID()); - - if (!b) { - testOptionalTestContext.get().setTest(test); - } - testOptionalTestContext.get().refreshTestStatusCounts(); - } - else { - TestAttributeTestContext testAttrContext = new TestAttributeTestContext<>(attr); - testAttrContext.setTest(test); - testAttrCollection.add(testAttrContext); - } - } - - public void removeTest(Test test) { - Iterator> iter = testAttrCollection.iterator(); - while (iter.hasNext()) { - TestAttributeTestContext context = iter.next(); - TestRemover.remove(context.getTestList(), test); - if (context.isEmpty()) { - iter.remove(); - } - } - } - - public List> getTestAttributeTestContextList() { - return testAttrCollection; - } - -} diff --git a/src/main/java/com/aventstack/extentreports/TestListener.java b/src/main/java/com/aventstack/extentreports/TestListener.java index e526426..5201df4 100644 --- a/src/main/java/com/aventstack/extentreports/TestListener.java +++ b/src/main/java/com/aventstack/extentreports/TestListener.java @@ -7,98 +7,90 @@ import com.aventstack.extentreports.model.Device; import com.aventstack.extentreports.model.Log; import com.aventstack.extentreports.model.ScreenCapture; -import com.aventstack.extentreports.model.Screencast; import com.aventstack.extentreports.model.Test; /** * Listener methods invoked when an event occurs in the report: * *

    - *
  • A test or node is started
  • - *
  • A category or author is added
  • - *
  • A media object is added etc.
  • + *
  • A test or node is started
  • + *
  • A category or author is added
  • + *
  • A media object is added etc.
  • *
*/ public interface TestListener { - - /** - * Invoked when a test is started using createTest() - * - * @param test {@link com.aventstack.extentreports.model.Test} object - */ - void onTestStarted(Test test); - - /** - * Invoked when a test is removed using removeTest() - * - * @param test {@link com.aventstack.extentreports.model.Test} object - */ - void onTestRemoved(Test test); - - /** - * Invoked when a node is started using createNode() - * - * @param node {@link com.aventstack.extentreports.model.Test} object - */ - void onNodeStarted(Test node); - - /** - * Invoked each time a log is added to any test/node - * - * @param test {@link com.aventstack.extentreports.model.Test} object - * @param log {@link com.aventstack.extentreports.model.Log} object - */ - void onLogAdded(Test test, Log log); - - /** - * Invoked each time a category is assigned to any test/node - * - * @param test {@link com.aventstack.extentreports.model.Test} object - * @param category {@link com.aventstack.extentreports.model.Category} object - */ - void onCategoryAssigned(Test test, Category category); - - /** - * Invoked each time an author is assigned to any test/node - * - * @param test {@link com.aventstack.extentreports.model.Test} object - * @param author {@link com.aventstack.extentreports.model.Author} object - */ - void onAuthorAssigned(Test test, Author author); - - /** - * Invoked each time a device is assigned to any test/node - * - * @param test {@link com.aventstack.extentreports.model.Test} object - * @param device {@link com.aventstack.extentreports.model.Device} object - */ - void onDeviceAssigned(Test test, Device device); - - /** - * Invoked each time a screencapture is added to test - * - * @param test {@link com.aventstack.extentreports.model.Test} object - * @param screenCapture {@link com.aventstack.extentreports.model.ScreenCapture} object - * @throws IOException Exception thrown if the media object is not found - */ - void onScreenCaptureAdded(Test test, ScreenCapture screenCapture) throws IOException; - - /** - * Invoked each time a screencapture is added to log - * - * @param log {@link com.aventstack.extentreports.model.Log} object - * @param screenCapture {@link com.aventstack.extentreports.model.ScreenCapture} object - * @throws IOException Exception thrown if the media object is not found - */ - void onScreenCaptureAdded(Log log, ScreenCapture screenCapture) throws IOException; - - /** - * Invoked each time a screencast is added - * - * @param test {@link com.aventstack.extentreports.model.Test} object - * @param screencast {@link com.aventstack.extentreports.model.Screencast} object - * @throws IOException Exception thrown if the media object is not found - */ - void onScreencastAdded(Test test, Screencast screencast) throws IOException; - -} + + /** + * Invoked when a test is started using createTest() + * + * @param test {@link com.aventstack.extentreports.model.Test} object + */ + void onTestStarted(Test test); + + /** + * Invoked when a test is removed using removeTest() + * + * @param test {@link com.aventstack.extentreports.model.Test} object + */ + void onTestRemoved(Test test); + + /** + * Invoked when a node is started using createNode() + * + * @param node {@link com.aventstack.extentreports.model.Test} object + */ + void onNodeStarted(Test node); + + /** + * Invoked each time a log is added to any test/node + * + * @param test {@link com.aventstack.extentreports.model.Test} object + * @param log {@link com.aventstack.extentreports.model.Log} object + */ + void onLogAdded(Test test, Log log); + + /** + * Invoked each time a category is assigned to any test/node + * + * @param test {@link com.aventstack.extentreports.model.Test} object + * @param category {@link com.aventstack.extentreports.model.Category} object + */ + void onCategoryAssigned(Test test, Category category); + + /** + * Invoked each time an author is assigned to any test/node + * + * @param test {@link com.aventstack.extentreports.model.Test} object + * @param author {@link com.aventstack.extentreports.model.Author} object + */ + void onAuthorAssigned(Test test, Author author); + + /** + * Invoked each time a device is assigned to any test/node + * + * @param test {@link com.aventstack.extentreports.model.Test} object + * @param device {@link com.aventstack.extentreports.model.Device} object + */ + void onDeviceAssigned(Test test, Device device); + + /** + * Invoked each time a screencapture is added to test + * + * @param test {@link com.aventstack.extentreports.model.Test} object + * @param screenCapture {@link com.aventstack.extentreports.model.ScreenCapture} + * object + * @throws IOException Exception thrown if the media object is not found + */ + void onScreenCaptureAdded(Test test, ScreenCapture screenCapture) throws IOException; + + /** + * Invoked each time a screencapture is added to log + * + * @param log {@link com.aventstack.extentreports.model.Log} object + * @param screenCapture {@link com.aventstack.extentreports.model.ScreenCapture} + * object + * @throws IOException Exception thrown if the media object is not found + */ + void onScreenCaptureAdded(Log log, ScreenCapture screenCapture) throws IOException; + +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/TestRemover.java b/src/main/java/com/aventstack/extentreports/TestRemover.java deleted file mode 100644 index e442fd2..0000000 --- a/src/main/java/com/aventstack/extentreports/TestRemover.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.aventstack.extentreports; - -import java.util.List; -import java.util.stream.Collectors; - -import com.aventstack.extentreports.model.Test; - -class TestRemover { - - /** - * Helper for removing test recursively. This flag determines when to break - * out of recursion - */ - private static boolean removed = false; - - private TestRemover() { } - - /** - * Remove a test using its unique ID from a list - * - * @param list a list of {@link Test} - * @param test {@link Test} to be removed - */ - public static void remove(List testList, Test test) { - removed = false; - findAndRemoveTest(testList, test); - } - - /** - * Recursively traverses all tests, nodes upto the last leaf to find and remove - * the specified test - * - * @param list a list of {@link Test} - * @param test {@link Test} to be removed - */ - private static void findAndRemoveTest(List list, Test test) { - List filteredTestList = list - .stream() - .filter(x -> x.getID() == test.getID()) - .collect(Collectors.toList()); - - if (filteredTestList.size() == 1) { - removeTest(list, filteredTestList.get(0)); - removed = true; - return; - } - - for (Test t : list) { - if (removed) { - return; - } - findAndRemoveTest(t.getNodeContext().getAll(), test); - } - } - - /** - * Removes the test from a given list of tests - * - * @param list a list of {@link Test} - * @param test {@link Test} to be removed - */ - private static void removeTest(List list, Test test) { - list.remove(test); - } - -} diff --git a/src/main/java/com/aventstack/extentreports/configuration/ConfigurationBuilder.java b/src/main/java/com/aventstack/extentreports/configuration/ConfigurationBuilder.java new file mode 100644 index 0000000..c66ec17 --- /dev/null +++ b/src/main/java/com/aventstack/extentreports/configuration/ConfigurationBuilder.java @@ -0,0 +1,84 @@ +package com.aventstack.extentreports.configuration; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.w3c.dom.CharacterData; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +public class ConfigurationBuilder { + + private static final Logger logger = Logger.getLogger(ConfigurationBuilder.class.getName()); + + private ConfigurationStore store = new ConfigurationStore(); + private InputStream stream; + + public ConfigurationBuilder(URL url) { + try { + stream = url.openStream(); + } catch (IOException e) { + logger.log(Level.SEVERE, url.toString(), e); + } + } + + public ConfigurationBuilder(File file, Boolean silent) { + try { + if (silent && !file.exists()) + return; + stream = new FileInputStream(file); + } catch (FileNotFoundException e) { + logger.log(Level.SEVERE, file.getPath(), e); + } + } + + public ConfigurationStore getConfigurationStore() { + if (stream == null) + return null; + + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder documentBuilder; + String value; + + try { + documentBuilder = documentBuilderFactory.newDocumentBuilder(); + + Document doc = documentBuilder.parse(stream); + doc.getDocumentElement().normalize(); + + NodeList nodeList = doc.getElementsByTagName("configuration").item(0).getChildNodes(); + + for (int ix = 0; ix < nodeList.getLength(); ix++) { + Node node = nodeList.item(ix); + + Element el = node.getNodeType() == Node.ELEMENT_NODE ? (Element) node : null; + + if (el != null) { + value = el.getTextContent(); + + value = el instanceof CharacterData ? ((CharacterData) el).getData() : value; + store.storeConfig(el.getNodeName(), value); + } + } + + return store; + } catch (IOException | SAXException | ParserConfigurationException e) { + logger.log(Level.SEVERE, "Failed to load external configuration", e); + } + + return null; + } +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/configuration/ConfigurationStore.java b/src/main/java/com/aventstack/extentreports/configuration/ConfigurationStore.java new file mode 100644 index 0000000..51e2acb --- /dev/null +++ b/src/main/java/com/aventstack/extentreports/configuration/ConfigurationStore.java @@ -0,0 +1,43 @@ +package com.aventstack.extentreports.configuration; + +import java.util.HashMap; +import java.util.Map; + +public class ConfigurationStore { + + private Map store = new HashMap(); + + public Map getStore() { + return store; + } + + public void storeConfig(String key, Object value) { + store.put(key, value); + } + + public boolean containsConfig(String k) { + return store.containsKey(k); + } + + public void removeConfig(String k) { + store.remove(k); + } + + public Object getConfig(String k) { + return store.containsKey(k) ? store.get(k) : null; + } + + public void extendConfig(Map map) { + map.forEach((key, value) -> this.storeConfig(key, value)); + } + + public void extendConfig(ConfigurationStore config) { + Map map = config.store; + this.extendConfig(map); + } + + public boolean isEmpty() { + return store.isEmpty(); + } + +} diff --git a/src/main/java/com/aventstack/extentreports/convert/JsonDeserializer.java b/src/main/java/com/aventstack/extentreports/convert/JsonDeserializer.java new file mode 100644 index 0000000..669f6d0 --- /dev/null +++ b/src/main/java/com/aventstack/extentreports/convert/JsonDeserializer.java @@ -0,0 +1,24 @@ +package com.aventstack.extentreports.convert; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Type; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.List; + +import com.aventstack.extentreports.model.Test; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +class JsonDeserializer { + + public static List deserialize(File f) throws IOException { + Gson gson = new Gson(); + String json = new String(Files.readAllBytes(f.toPath())); + Type t = new TypeToken>() {}.getType(); + List tests = gson.fromJson(json, t); + return tests; + } + +} diff --git a/src/main/java/com/aventstack/extentreports/convert/TestModelReportBuilder.java b/src/main/java/com/aventstack/extentreports/convert/TestModelReportBuilder.java new file mode 100644 index 0000000..eeef8a9 --- /dev/null +++ b/src/main/java/com/aventstack/extentreports/convert/TestModelReportBuilder.java @@ -0,0 +1,71 @@ +package com.aventstack.extentreports.convert; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import com.aventstack.extentreports.ExtentReports; +import com.aventstack.extentreports.ExtentTest; +import com.aventstack.extentreports.GherkinKeyword; +import com.aventstack.extentreports.model.Log; +import com.aventstack.extentreports.model.Test; + +public class TestModelReportBuilder { + + public void createDomainFromJsonArchive(ExtentReports extent, File jsonFile) throws IOException { + if (!jsonFile.exists()) { + return; + } + Boolean configChanged = extent.getReportUsesManualConfiguration() ? false : true; + extent.setReportUsesManualConfiguration(true); + List tests = JsonDeserializer.deserialize(jsonFile); + for (Test test : tests) { + try { + if (test.getBehaviorDrivenTypeName() == null) { + createDomain(test, extent.createTest(test.getName(), test.getDescription())); + } else { + createDomain(test, extent.createTest(new GherkinKeyword(test.getBehaviorDrivenTypeName()), + test.getName(), test.getDescription())); + + } + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } + if (configChanged) { + extent.setReportUsesManualConfiguration(false); + } + } + + public void createDomain(Test test, ExtentTest extentTest) throws ClassNotFoundException { + extentTest.getModel().setStartTime(test.getStartTime()); + extentTest.getModel().setEndTime(test.getEndTime()); + extentTest.getModel().computeEndTimeFromChildren(); + + // create events + for (Log log : test.getLogContext().getAll()) { + if (log.getDetails() != null) + extentTest.log(log.getStatus(), log.getDetails()); + if (log.getExceptionInfo() != null) + extentTest.log(log.getStatus(), log.getExceptionInfo()); + } + + // assign attributes + test.getAuthorContext().getAll().forEach(x -> extentTest.assignAuthor(x.getName())); + test.getCategoryContext().getAll().forEach(x -> extentTest.assignCategory(x.getName())); + test.getDeviceContext().getAll().forEach(x -> extentTest.assignDevice(x.getName())); + + // handle nodes + for (Test node : test.getNodeContext().getAll()) { + ExtentTest extentNode = null; + if (node.getBehaviorDrivenTypeName() == null) { + extentNode = extentTest.createNode(node.getName(), node.getDescription()); + } else { + extentNode = extentTest.createNode(new GherkinKeyword(node.getBehaviorDrivenTypeName()), node.getName(), + node.getDescription()); + } + createDomain(node, extentNode); + } + } + +} diff --git a/src/main/java/com/aventstack/extentreports/exceptions/ExtentTestInterruptedException.java b/src/main/java/com/aventstack/extentreports/exceptions/ExtentTestInterruptedException.java deleted file mode 100644 index fda727b..0000000 --- a/src/main/java/com/aventstack/extentreports/exceptions/ExtentTestInterruptedException.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.aventstack.extentreports.exceptions; - -@SuppressWarnings("serial") -public class ExtentTestInterruptedException extends RuntimeException { - public ExtentTestInterruptedException(Throwable t) { - super(t); - } - - public ExtentTestInterruptedException(String string) { - super(string); - } - - public ExtentTestInterruptedException(String string, Throwable t) { - super(string, t); - } - -} diff --git a/src/main/java/com/aventstack/extentreports/exceptions/InvalidFileException.java b/src/main/java/com/aventstack/extentreports/exceptions/InvalidFileException.java deleted file mode 100644 index 4cf981b..0000000 --- a/src/main/java/com/aventstack/extentreports/exceptions/InvalidFileException.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.aventstack.extentreports.exceptions; - -@SuppressWarnings("serial") -public class InvalidFileException extends Exception { - public InvalidFileException() { - super(); - } - - public InvalidFileException(Throwable t) { - super(t); - } - - public InvalidFileException(String string) { - super(string); - } - - public InvalidFileException(String string, Throwable t) { - super(string, t); - } - -} diff --git a/src/main/java/com/aventstack/extentreports/externalconfig/ConfigLoader.java b/src/main/java/com/aventstack/extentreports/externalconfig/ConfigLoader.java deleted file mode 100644 index e9be842..0000000 --- a/src/main/java/com/aventstack/extentreports/externalconfig/ConfigLoader.java +++ /dev/null @@ -1,107 +0,0 @@ -package com.aventstack.extentreports.externalconfig; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -import org.w3c.dom.CharacterData; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; - -import com.aventstack.extentreports.externalconfig.model.Config; -import com.aventstack.extentreports.externalconfig.model.ConfigMap; - -public class ConfigLoader { - - private static final Logger logger = Logger.getLogger(ConfigLoader.class.getName()); - - private ConfigMap configContext; - private InputStream stream; - - ConfigLoader() { - configContext = new ConfigMap(); - } - - public ConfigLoader(URL url) { - this(); - - try { - stream = url.openStream(); - } - catch (IOException e) { - logger.log(Level.SEVERE, url.toString(), e); - } - } - - public ConfigLoader(File file, Boolean silent) { - this(); - - try { - if (silent && !file.exists()) - return; - stream = new FileInputStream(file); - } - catch (FileNotFoundException e) { - logger.log(Level.SEVERE, file.getPath(), e); - } - } - - public ConfigMap getConfigurationHash() { - if (stream == null) - return null; - - DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); - DocumentBuilder dBuilder; - String value; - - try { - dBuilder = dbFactory.newDocumentBuilder(); - - Document doc = dBuilder.parse(stream); - doc.getDocumentElement().normalize(); - - NodeList nodeList = doc.getElementsByTagName("configuration").item(0).getChildNodes(); - - for (int ix = 0; ix < nodeList.getLength(); ix++) { - Node node = nodeList.item(ix); - - Element el = node.getNodeType() == Node.ELEMENT_NODE - ? (Element) node - : null; - - if (el != null) { - value = el.getTextContent(); - - value = el instanceof CharacterData - ? ((CharacterData) el).getData() - : value; - - Config c = new Config(); - c.setKey(el.getNodeName()); - c.setValue(value); - - configContext.setConfig(c); - } - } - - return configContext; - } - catch (IOException|SAXException|ParserConfigurationException e) { - logger.log(Level.SEVERE, "Config", e); - } - - return null; - } -} diff --git a/src/main/java/com/aventstack/extentreports/externalconfig/model/Config.java b/src/main/java/com/aventstack/extentreports/externalconfig/model/Config.java deleted file mode 100644 index e1d34dc..0000000 --- a/src/main/java/com/aventstack/extentreports/externalconfig/model/Config.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.aventstack.extentreports.externalconfig.model; - -public class Config { - - private String k; - private Object v; - - public void setKey(String k) { - this.k = k; - } - - public String getKey() { - return k; - } - - public void setValue(Object v) { - this.v = v; - } - - public Object getValue() { - return v; - } -} diff --git a/src/main/java/com/aventstack/extentreports/externalconfig/model/ConfigMap.java b/src/main/java/com/aventstack/extentreports/externalconfig/model/ConfigMap.java deleted file mode 100644 index 258a669..0000000 --- a/src/main/java/com/aventstack/extentreports/externalconfig/model/ConfigMap.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.aventstack.extentreports.externalconfig.model; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -public class ConfigMap { - - private List configList; - - public ConfigMap() { - configList = new ArrayList<>(); - } - - public void setConfig(Config c) { - if (containsKey(c.getKey())) - removeKey(c.getKey()); - - configList.add(c); - } - - public List getConfigList() { return configList; } - - public boolean containsKey(String k) { - return configList.stream() - .anyMatch(x -> x.getKey().equals(k)); - } - - void removeKey(String k) { - configList.removeIf(x -> x.getKey().equals(k)); - } - - public Object getValue(String k) { - Optional c = configList.stream() - .filter(x -> x.getKey().equals(k)) - .findFirst(); - - if (c.isPresent()) - return c.get().getValue(); - - return null; - } -} diff --git a/src/main/java/com/aventstack/extentreports/gherkin/GherkinDialect.java b/src/main/java/com/aventstack/extentreports/gherkin/GherkinDialect.java index 974510e..37b51a5 100644 --- a/src/main/java/com/aventstack/extentreports/gherkin/GherkinDialect.java +++ b/src/main/java/com/aventstack/extentreports/gherkin/GherkinDialect.java @@ -5,7 +5,7 @@ /** *

- * Modified version of GherkinKeyword.java from cucumber/gherkin. Source url: + * Modified version of GherkinKeyword.java from cucumber/gherkin. Source url: * https://raw.githubusercontent.com/cucumber/cucumber/master/gherkin/java/src/main/java/gherkin/GherkinDialect.java * *

@@ -13,21 +13,23 @@ * */ public class GherkinDialect { - private final Map> keywords; - private String language; + + private final Map> keywords; + private String language; - public GherkinDialect(String language, Map> keywords) { - this.language = language; - this.keywords = keywords; - } + public GherkinDialect(String language, Map> keywords) { + keywords.remove("name"); + keywords.remove("native"); + this.language = language; + this.keywords = keywords; + } - public Map> getKeywords() { - keywords.remove("name"); - keywords.remove("native"); - return keywords; - } + public Map> getKeywords() { + return keywords; + } - public String getLanguage() { - return language; - } + public String getLanguage() { + return language; + } + } \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/gherkin/GherkinDialectProvider.java b/src/main/java/com/aventstack/extentreports/gherkin/GherkinDialectProvider.java index 32c815b..4cc01cc 100644 --- a/src/main/java/com/aventstack/extentreports/gherkin/GherkinDialectProvider.java +++ b/src/main/java/com/aventstack/extentreports/gherkin/GherkinDialectProvider.java @@ -10,7 +10,8 @@ /** *

- * Modified version of GherkinDialectProvider.java from cucumber/gherkin. Source url: + * Modified version of GherkinDialectProvider.java from cucumber/gherkin. Source + * url: * https://github.com/cucumber/cucumber/blob/master/gherkin/java/src/main/java/gherkin/GherkinDialectProvider.java. * *

@@ -20,54 +21,57 @@ @SuppressWarnings("unchecked") public class GherkinDialectProvider { - private static final String DEFAULT_LANGUAGE = "en"; - private static final String GHERKIN_LANGUAGES_JSON_URL = "https://github.com/cucumber/cucumber/blob/master/gherkin/java/src/main/resources/gherkin/gherkin-languages.json"; - - private static GherkinDialect currentDialect; - private static Map>> dialects; - private static String language; - - static { - Gson gson = new Gson(); - try { - Reader d = new InputStreamReader(GherkinDialectProvider.class.getResourceAsStream("gherkin-languages.json"), "UTF-8"); - dialects = gson.fromJson(d, Map.class); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - } - - public static GherkinDialect getDialect() { - return currentDialect; - } - - public static String getDefaultLanguage() { - return DEFAULT_LANGUAGE; - } - - public static String getLanguage() { - if (language == null || language.isEmpty()) - language = DEFAULT_LANGUAGE; - - return language; - } - - /** - * Sets/changes the default language - * - * @param lang A valid dialect from - * gherkin-languages.json - * - * @throws UnsupportedEncodingException Thrown if the language is one of the supported language from - * gherkin-languages.json - */ - public static void setLanguage(String lang) throws UnsupportedEncodingException { - language = lang; - Map> map = dialects.get(GherkinDialectProvider.language); - if (map == null) - throw new UnsupportedEncodingException("Invalid language [" + language + "]. See list of supported languages: " + GHERKIN_LANGUAGES_JSON_URL); - - currentDialect = new GherkinDialect(language, map); - } - + private static final String DEFAULT_LANGUAGE = "en"; + private static final String GHERKIN_LANGUAGES_JSON_URL = "https://github.com/cucumber/cucumber/blob/master/gherkin/gherkin-languages.json"; + private static final String GHERKIN_LANGUAGES_PATH = "gherkin-languages.json"; + + private static GherkinDialect currentDialect; + private static Map>> dialects; + private static String language; + + static { + Gson gson = new Gson(); + try { + Reader d = new InputStreamReader(GherkinDialectProvider.class.getResourceAsStream(GHERKIN_LANGUAGES_PATH), + "UTF-8"); + dialects = gson.fromJson(d, Map.class); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + public static GherkinDialect getDialect() { + return currentDialect; + } + + public static String getDefaultLanguage() { + return DEFAULT_LANGUAGE; + } + + public static String getLanguage() { + if (language == null || language.isEmpty()) { + language = DEFAULT_LANGUAGE; + } + return language; + } + + /** + * Sets/changes the default language + * + * @param lang A valid dialect from + * https://github.com/cucumber/cucumber/blob/master/gherkin/gherkin-languages.json + * + * @throws UnsupportedEncodingException Thrown if the language is one of the + * supported language from + * https://github.com/cucumber/cucumber/blob/master/gherkin/gherkin-languages.json + */ + public static void setLanguage(String lang) throws UnsupportedEncodingException { + language = lang; + Map> map = dialects.get(GherkinDialectProvider.language); + if (map == null) { + throw new UnsupportedEncodingException("Invalid language [" + language + "]. See list of supported languages: " + GHERKIN_LANGUAGES_JSON_URL); + } + currentDialect = new GherkinDialect(language, map); + } + } \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/gherkin/model/And.java b/src/main/java/com/aventstack/extentreports/gherkin/model/And.java index fdf6983..c2a2bff 100644 --- a/src/main/java/com/aventstack/extentreports/gherkin/model/And.java +++ b/src/main/java/com/aventstack/extentreports/gherkin/model/And.java @@ -2,19 +2,18 @@ import java.io.Serializable; -public class And - implements IGherkinFormatterModel, Serializable { +public class And implements IGherkinFormatterModel, Serializable { private static final long serialVersionUID = 8543289653944756660L; private static final String VALUE = "And"; - + public static String getGherkinName() { return VALUE; } - + @Override public String toString() { return getGherkinName(); } - + } diff --git a/src/main/java/com/aventstack/extentreports/gherkin/model/Asterisk.java b/src/main/java/com/aventstack/extentreports/gherkin/model/Asterisk.java index 05fe3af..c6e10d7 100644 --- a/src/main/java/com/aventstack/extentreports/gherkin/model/Asterisk.java +++ b/src/main/java/com/aventstack/extentreports/gherkin/model/Asterisk.java @@ -2,19 +2,18 @@ import java.io.Serializable; -public class Asterisk - implements IGherkinFormatterModel, Serializable { +public class Asterisk implements IGherkinFormatterModel, Serializable { private static final long serialVersionUID = 7251419811428200133L; private static final String VALUE = "*"; - + public static String getGherkinName() { return VALUE; } - + @Override public String toString() { return getGherkinName(); } - + } diff --git a/src/main/java/com/aventstack/extentreports/gherkin/model/Background.java b/src/main/java/com/aventstack/extentreports/gherkin/model/Background.java index e646aaa..1e42713 100644 --- a/src/main/java/com/aventstack/extentreports/gherkin/model/Background.java +++ b/src/main/java/com/aventstack/extentreports/gherkin/model/Background.java @@ -2,19 +2,18 @@ import java.io.Serializable; -public class Background - implements IGherkinFormatterModel, Serializable { +public class Background implements IGherkinFormatterModel, Serializable { private static final long serialVersionUID = -955371501488725151L; private static final String VALUE = "Background"; - + public static String getGherkinName() { return VALUE; } - + @Override public String toString() { return getGherkinName(); } - + } diff --git a/src/main/java/com/aventstack/extentreports/gherkin/model/But.java b/src/main/java/com/aventstack/extentreports/gherkin/model/But.java index c7f66b6..6d88158 100644 --- a/src/main/java/com/aventstack/extentreports/gherkin/model/But.java +++ b/src/main/java/com/aventstack/extentreports/gherkin/model/But.java @@ -2,19 +2,18 @@ import java.io.Serializable; -public class But - implements IGherkinFormatterModel, Serializable { +public class But implements IGherkinFormatterModel, Serializable { private static final long serialVersionUID = 3420514631996827220L; private static final String VALUE = "But"; - + public static String getGherkinName() { return VALUE; } - + @Override public String toString() { return getGherkinName(); } - + } diff --git a/src/main/java/com/aventstack/extentreports/gherkin/model/Feature.java b/src/main/java/com/aventstack/extentreports/gherkin/model/Feature.java index 4d55c8b..6475396 100644 --- a/src/main/java/com/aventstack/extentreports/gherkin/model/Feature.java +++ b/src/main/java/com/aventstack/extentreports/gherkin/model/Feature.java @@ -2,19 +2,18 @@ import java.io.Serializable; -public class Feature - implements IGherkinFormatterModel, Serializable { +public class Feature implements IGherkinFormatterModel, Serializable { private static final long serialVersionUID = -4719215211721789414L; private static final String VALUE = "Feature"; - + public static String getGherkinName() { return VALUE; } - + @Override public String toString() { return getGherkinName(); } - + } diff --git a/src/main/java/com/aventstack/extentreports/gherkin/model/GherkinModelSerializer.java b/src/main/java/com/aventstack/extentreports/gherkin/model/GherkinModelSerializer.java new file mode 100644 index 0000000..242fefa --- /dev/null +++ b/src/main/java/com/aventstack/extentreports/gherkin/model/GherkinModelSerializer.java @@ -0,0 +1,23 @@ +package com.aventstack.extentreports.gherkin.model; + +import java.io.IOException; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +public class GherkinModelSerializer extends TypeAdapter { + + @Override + public void write(JsonWriter out, IGherkinFormatterModel value) throws IOException { + // TODO Auto-generated method stub + + } + + @Override + public IGherkinFormatterModel read(JsonReader in) throws IOException { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/src/main/java/com/aventstack/extentreports/gherkin/model/Given.java b/src/main/java/com/aventstack/extentreports/gherkin/model/Given.java index 5ac6eca..483b0d2 100644 --- a/src/main/java/com/aventstack/extentreports/gherkin/model/Given.java +++ b/src/main/java/com/aventstack/extentreports/gherkin/model/Given.java @@ -2,19 +2,18 @@ import java.io.Serializable; -public class Given - implements IGherkinFormatterModel, Serializable { +public class Given implements IGherkinFormatterModel, Serializable { private static final long serialVersionUID = 939197985263690070L; private static final String VALUE = "Given"; - + public static String getGherkinName() { return VALUE; } - + @Override public String toString() { return getGherkinName(); } - + } diff --git a/src/main/java/com/aventstack/extentreports/gherkin/model/IGherkinFormatterModel.java b/src/main/java/com/aventstack/extentreports/gherkin/model/IGherkinFormatterModel.java index d9b3a0e..d150968 100644 --- a/src/main/java/com/aventstack/extentreports/gherkin/model/IGherkinFormatterModel.java +++ b/src/main/java/com/aventstack/extentreports/gherkin/model/IGherkinFormatterModel.java @@ -2,5 +2,5 @@ import java.io.Serializable; -public interface IGherkinFormatterModel - extends Serializable { } +public interface IGherkinFormatterModel extends Serializable { +} diff --git a/src/main/java/com/aventstack/extentreports/gherkin/model/Scenario.java b/src/main/java/com/aventstack/extentreports/gherkin/model/Scenario.java index 8f85f55..683f4d1 100644 --- a/src/main/java/com/aventstack/extentreports/gherkin/model/Scenario.java +++ b/src/main/java/com/aventstack/extentreports/gherkin/model/Scenario.java @@ -2,19 +2,18 @@ import java.io.Serializable; -public class Scenario - implements IGherkinFormatterModel, Serializable { +public class Scenario implements IGherkinFormatterModel, Serializable { private static final long serialVersionUID = 7401124129196617280L; private static final String VALUE = "Scenario"; - + public static String getGherkinName() { return VALUE; } - + @Override public String toString() { return getGherkinName(); } - + } diff --git a/src/main/java/com/aventstack/extentreports/gherkin/model/ScenarioOutline.java b/src/main/java/com/aventstack/extentreports/gherkin/model/ScenarioOutline.java index 481c890..6b84733 100644 --- a/src/main/java/com/aventstack/extentreports/gherkin/model/ScenarioOutline.java +++ b/src/main/java/com/aventstack/extentreports/gherkin/model/ScenarioOutline.java @@ -2,19 +2,18 @@ import java.io.Serializable; -public class ScenarioOutline - implements IGherkinFormatterModel, Serializable { +public class ScenarioOutline implements IGherkinFormatterModel, Serializable { private static final long serialVersionUID = -2058398543903906031L; private static final String VALUE = "Scenario Outline"; - + public static String getGherkinName() { return VALUE; } - + @Override public String toString() { return getGherkinName(); } - + } diff --git a/src/main/java/com/aventstack/extentreports/gherkin/model/Then.java b/src/main/java/com/aventstack/extentreports/gherkin/model/Then.java index 427a738..2ad2bc7 100644 --- a/src/main/java/com/aventstack/extentreports/gherkin/model/Then.java +++ b/src/main/java/com/aventstack/extentreports/gherkin/model/Then.java @@ -2,19 +2,18 @@ import java.io.Serializable; -public class Then - implements IGherkinFormatterModel, Serializable { +public class Then implements IGherkinFormatterModel, Serializable { private static final long serialVersionUID = 2493591502473169772L; private static final String VALUE = "Then"; - + public static String getGherkinName() { return VALUE; } - + @Override public String toString() { return getGherkinName(); } - + } diff --git a/src/main/java/com/aventstack/extentreports/gherkin/model/When.java b/src/main/java/com/aventstack/extentreports/gherkin/model/When.java index 5da0d15..d9460db 100644 --- a/src/main/java/com/aventstack/extentreports/gherkin/model/When.java +++ b/src/main/java/com/aventstack/extentreports/gherkin/model/When.java @@ -2,19 +2,18 @@ import java.io.Serializable; -public class When - implements IGherkinFormatterModel, Serializable { +public class When implements IGherkinFormatterModel, Serializable { private static final long serialVersionUID = 8337259741948416898L; private static final String VALUE = "When"; - + public static String getGherkinName() { return VALUE; } - + @Override public String toString() { return getGherkinName(); } - + } diff --git a/src/main/java/com/aventstack/extentreports/io/FileWriterBuffered.java b/src/main/java/com/aventstack/extentreports/io/FileWriterBuffered.java new file mode 100644 index 0000000..76b1bcb --- /dev/null +++ b/src/main/java/com/aventstack/extentreports/io/FileWriterBuffered.java @@ -0,0 +1,35 @@ +package com.aventstack.extentreports.io; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class FileWriterBuffered { + + private static class WriterInstance { + static final FileWriterBuffered INSTANCE = new FileWriterBuffered(); + + private WriterInstance() { + } + } + + static final Logger logger = Logger.getLogger(FileWriterBuffered.class.getName()); + + private FileWriterBuffered() { + } + + public synchronized void write(final File f, String text) { + try (BufferedWriter writer = new BufferedWriter(new FileWriter(f))) { + writer.write(text); + } catch (Exception e) { + logger.log(Level.SEVERE, f.getPath(), e); + } + } + + public static FileWriterBuffered getInstance() { + return WriterInstance.INSTANCE; + } + +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/io/ResourceUtil.java b/src/main/java/com/aventstack/extentreports/io/ResourceUtil.java new file mode 100644 index 0000000..6069081 --- /dev/null +++ b/src/main/java/com/aventstack/extentreports/io/ResourceUtil.java @@ -0,0 +1,54 @@ +package com.aventstack.extentreports.io; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; + +public class ResourceUtil { + + public static void moveResource(String resourcePath, String copyPath) { + if (copyPath != null) + copyPath = copyPath.replace("\\", "/"); + if (resourcePath != null) + resourcePath = resourcePath.replace("\\", "/"); + + try { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + InputStream in = classLoader.getResourceAsStream(resourcePath); + + FileOutputStream out = new FileOutputStream(copyPath); + + byte[] b = new byte[1024]; + int noOfBytes = 0; + + while ((noOfBytes = in.read(b)) != -1) { + out.write(b, 0, noOfBytes); + } + + in.close(); + out.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static void moveBinaryFile(String resourcePath, String copyPath) { + URI uri = new File(resourcePath).toURI(); + Path path = Paths.get(uri); + try { + Files.copy(path, new File(copyPath).toPath(), StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + e.printStackTrace(); + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/markuputils/CodeBlock.java b/src/main/java/com/aventstack/extentreports/markuputils/CodeBlock.java index ea8a18a..d378816 100644 --- a/src/main/java/com/aventstack/extentreports/markuputils/CodeBlock.java +++ b/src/main/java/com/aventstack/extentreports/markuputils/CodeBlock.java @@ -1,43 +1,65 @@ package com.aventstack.extentreports.markuputils; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; -class CodeBlock implements Markup { - - private static final long serialVersionUID = -5532095355983830164L; - - private static final AtomicInteger id = new AtomicInteger(0); - - private String code; - private CodeLanguage lang; - - public void setCodeBlock(String code) { - this.code = code; - } - public String getCodeBlock() { - return code; - } - - public void setCodeBlock(String code, CodeLanguage lang) { - this.code = code; - this.lang = lang; - } - - @Override - public String getMarkup() { - if (lang == CodeLanguage.JSON) { - int index = id.getAndIncrement(); - return "

" + - ""; - } - - String lhs = ""; - - return lhs + code + rhs; - } +import freemarker.template.Template; +import freemarker.template.TemplateException; + +class CodeBlock extends MarkupTemplate implements Markup { + + private static final long serialVersionUID = -5532095355983830164L; + private static final AtomicInteger id = new AtomicInteger(0); + private static final String CODEBLOCK_TEMPLATE = "codeblock.ftl"; + private static final String CODEBLOCK_JSON_TEMPLATE = "codeblock.json.ftl"; + private static Template codeblock; + private static Template codeblockJson; + private String code; + private CodeLanguage lang; + + static { + try { + codeblock = ft.createTemplate(CODEBLOCK_TEMPLATE); + codeblockJson = ft.createTemplate(CODEBLOCK_JSON_TEMPLATE); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void setCodeBlock(String code) { + this.code = code; + } + + public String getCodeBlock() { + return code; + } + + public void setCodeBlock(String code, CodeLanguage lang) { + this.code = code; + this.lang = lang; + } + + @Override + public String getMarkup() { + int index = 0; + Template t = codeblock; + if (lang == CodeLanguage.JSON) { + index = id.getAndIncrement(); + t = codeblockJson; + } + Map map = new HashMap<>(); + map.put("code", code); + map.put("index", index); + try { + return ft.getSource(t, map); + } catch (TemplateException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } } diff --git a/src/main/java/com/aventstack/extentreports/markuputils/Markup.java b/src/main/java/com/aventstack/extentreports/markuputils/Markup.java index ff0a803..bd8856c 100644 --- a/src/main/java/com/aventstack/extentreports/markuputils/Markup.java +++ b/src/main/java/com/aventstack/extentreports/markuputils/Markup.java @@ -4,5 +4,5 @@ @FunctionalInterface public interface Markup extends Serializable { - String getMarkup(); + String getMarkup(); } diff --git a/src/main/java/com/aventstack/extentreports/markuputils/MarkupHelper.java b/src/main/java/com/aventstack/extentreports/markuputils/MarkupHelper.java index 92a12a5..42ca33d 100644 --- a/src/main/java/com/aventstack/extentreports/markuputils/MarkupHelper.java +++ b/src/main/java/com/aventstack/extentreports/markuputils/MarkupHelper.java @@ -1,30 +1,30 @@ package com.aventstack.extentreports.markuputils; public class MarkupHelper { - - public static Markup createLabel(String text, ExtentColor color) { - Label l = new Label(); - l.setText(text); - l.setColor(color); - return l; - } - - public static Markup createCodeBlock(String code) { - CodeBlock cb = new CodeBlock(); - cb.setCodeBlock(code); - return cb; - } - - public static Markup createCodeBlock(String code, CodeLanguage lang) { - CodeBlock cb = new CodeBlock(); - cb.setCodeBlock(code, lang); - return cb; - } - - public static Markup createTable(String[][] data) { - Table t = new Table(); - t.setData(data); - return t; - } - + + public static Markup createLabel(String text, ExtentColor color) { + Label l = new Label(); + l.setText(text); + l.setColor(color); + return l; + } + + public static Markup createCodeBlock(String code) { + CodeBlock cb = new CodeBlock(); + cb.setCodeBlock(code); + return cb; + } + + public static Markup createCodeBlock(String code, CodeLanguage lang) { + CodeBlock cb = new CodeBlock(); + cb.setCodeBlock(code, lang); + return cb; + } + + public static Markup createTable(String[][] data) { + Table t = new Table(); + t.setData(data); + return t; + } + } diff --git a/src/main/java/com/aventstack/extentreports/markuputils/MarkupTemplate.java b/src/main/java/com/aventstack/extentreports/markuputils/MarkupTemplate.java new file mode 100644 index 0000000..f5db943 --- /dev/null +++ b/src/main/java/com/aventstack/extentreports/markuputils/MarkupTemplate.java @@ -0,0 +1,10 @@ +package com.aventstack.extentreports.markuputils; + +import com.aventstack.extentreports.ExtentReports; +import com.aventstack.extentreports.templating.FreemarkerTemplate; + +class MarkupTemplate { + + protected static final FreemarkerTemplate ft = new FreemarkerTemplate(ExtentReports.class, "markup/", "UTF-8"); + +} diff --git a/src/main/java/com/aventstack/extentreports/mediastorage/KlovMediaStorageHandler.java b/src/main/java/com/aventstack/extentreports/mediastorage/KlovMediaStorageHandler.java index c1e25a9..b233c44 100644 --- a/src/main/java/com/aventstack/extentreports/mediastorage/KlovMediaStorageHandler.java +++ b/src/main/java/com/aventstack/extentreports/mediastorage/KlovMediaStorageHandler.java @@ -30,9 +30,11 @@ public void saveScreenCapture(BasicMongoReportElement el, ScreenCapture media) t Document doc = new Document("project", klovMedia.getProjectId()) .append("report", klovMedia.getReportId()) .append("sequence", media.getSequence()) - .append("mediaType", media.getMediaType().toString().toLowerCase()) - .append("test", media.getTestObjectId()); + .append("test", media.getBsonId().get("testId")); + if (media.isBase64()) { + doc.append("base64String", media.getBase64String()); + } if (el.getClass() != Test.class) { doc.append("log", el.getObjectId()); } else { @@ -41,9 +43,8 @@ public void saveScreenCapture(BasicMongoReportElement el, ScreenCapture media) t klovMedia.getMediaCollection().insertOne(doc); ObjectId mediaId = MongoUtil.getId(doc); - media.setObjectId(mediaId); - - media.setReportObjectId(klovMedia.getReportId()); + media.getBsonId().put("id", mediaId); + media.getBsonId().put("reportId", klovMedia.getReportId()); mediaStorage.storeMedia((ScreenCapture)media); } diff --git a/src/main/java/com/aventstack/extentreports/mediastorage/impl/HttpMediaManagerImplKlov.java b/src/main/java/com/aventstack/extentreports/mediastorage/impl/HttpMediaManagerImplKlov.java index 043777a..a671248 100644 --- a/src/main/java/com/aventstack/extentreports/mediastorage/impl/HttpMediaManagerImplKlov.java +++ b/src/main/java/com/aventstack/extentreports/mediastorage/impl/HttpMediaManagerImplKlov.java @@ -16,6 +16,7 @@ import com.aventstack.extentreports.mediastorage.MediaStorage; import com.aventstack.extentreports.model.Media; +import com.aventstack.extentreports.model.ScreenCapture; import com.aventstack.extentreports.utils.FileUtil; public class HttpMediaManagerImplKlov @@ -36,10 +37,13 @@ public void init(String host) throws IOException { @Override public void storeMedia(Media m) throws IOException { - if (m.getPath() == null || m.getBase64String() != null) + if (m.getPath() == null) { return; - - File f = new File(m.getPath()); + } + if (m instanceof ScreenCapture && ((ScreenCapture)m).getBase64String() != null) { + return; + } + File f = new File(m.getResolvedPath()); if (!f.exists()) { throw new IOException("The system cannot find the file specified " + m.getPath()); } @@ -54,14 +58,13 @@ public void storeMedia(Media m) throws IOException { MultipartEntityBuilder builder = MultipartEntityBuilder.create(); builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); builder.addPart("name",new StringBody(m.getSequence() + "." + ext, ContentType.TEXT_PLAIN)); - builder.addPart("id", new StringBody(m.getObjectId().toString(), ContentType.TEXT_PLAIN)); - builder.addPart("reportId", new StringBody(m.getReportObjectId().toString(), ContentType.TEXT_PLAIN)); - builder.addPart("testId", new StringBody(m.getTestObjectId().toString(), ContentType.TEXT_PLAIN)); - builder.addPart("mediaType", new StringBody(String.valueOf(m.getMediaType()).toLowerCase(), ContentType.TEXT_PLAIN)); - builder.addPart("f", new FileBody(new File(m.getPath()))); + builder.addPart("id", new StringBody(m.getBsonId().get("id").toString(), ContentType.TEXT_PLAIN)); + builder.addPart("reportId", new StringBody(m.getBsonId().get("reportId").toString(), ContentType.TEXT_PLAIN)); + builder.addPart("testId", new StringBody(m.getBsonId().get("testId").toString(), ContentType.TEXT_PLAIN)); + builder.addPart("f", new FileBody(new File(m.getResolvedPath()))); post.setEntity(builder.build()); - String logId = m.getLogObjectId() == null ? "" : m.getLogObjectId().toString(); + String logId = m.getBsonId().get("logId") == null ? "" : m.getBsonId().get("logId").toString(); builder.addPart("logId", new StringBody(logId, ContentType.TEXT_PLAIN)); HttpClient client = HttpClientBuilder.create().build(); @@ -76,7 +79,7 @@ public void storeMedia(Media m) throws IOException { } private boolean isResponseValid(int responseCode) { - return 200 <= responseCode && responseCode <= 399; + return responseCode >= 200 && responseCode < 400; } } diff --git a/src/main/java/com/aventstack/extentreports/model/AbstractStructure.java b/src/main/java/com/aventstack/extentreports/model/AbstractStructure.java index 38fd521..356fc13 100644 --- a/src/main/java/com/aventstack/extentreports/model/AbstractStructure.java +++ b/src/main/java/com/aventstack/extentreports/model/AbstractStructure.java @@ -11,12 +11,8 @@ public class AbstractStructure implements Serializable { private static final long serialVersionUID = -2630417398255980331L; - private transient List list; + private List list = Collections.synchronizedList(new ArrayList<>()); - AbstractStructure() { - list = Collections.synchronizedList(new ArrayList<>()); - } - public void add(T t) { list.add(t); } @@ -38,8 +34,9 @@ public List getAll() { } public int size() { - if (list == null) + if (list == null) { return 0; + } return list.size(); } @@ -76,4 +73,4 @@ public void remove() { } } -} +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/model/Attribute.java b/src/main/java/com/aventstack/extentreports/model/Attribute.java index 2b1e436..77494d7 100644 --- a/src/main/java/com/aventstack/extentreports/model/Attribute.java +++ b/src/main/java/com/aventstack/extentreports/model/Attribute.java @@ -2,36 +2,39 @@ import java.io.Serializable; -abstract class Attribute - implements Serializable { - - private static final long serialVersionUID = 6491172989326625178L; - - private String k; - private String v; - - public Attribute(String k, String v) { - this.k = k; - this.v = v; - } - - public Attribute(String k) { - this(k, null); - } - - protected String getKey() { - return k; - } - - protected void setKey(String k) { - this.k = k; - } - - public String getValue() { - return v; - } - - public void setValue(String v) { - this.v = v; - } -} +public class Attribute implements Serializable { + + private static final long serialVersionUID = 6491172989326625178L; + + private String k; + private String v; + + public Attribute() { + } + + public Attribute(String k, String v) { + this.k = k; + this.v = v; + } + + public Attribute(String k) { + this(k, null); + } + + public String getName() { + return k; + } + + public void setName(String k) { + this.k = k; + } + + public String getValue() { + return v; + } + + public void setValue(String v) { + this.v = v; + } + +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/model/Author.java b/src/main/java/com/aventstack/extentreports/model/Author.java index 3e26b3a..2e3b6b1 100644 --- a/src/main/java/com/aventstack/extentreports/model/Author.java +++ b/src/main/java/com/aventstack/extentreports/model/Author.java @@ -1,12 +1,15 @@ package com.aventstack.extentreports.model; -public class Author - extends TestAttribute { +public class Author extends Attribute { - private static final long serialVersionUID = 5358337504569462439L; + private static final long serialVersionUID = -6374771272610470521L; - public Author(String k) { - super(k); - } - -} + public Author(String k) { + super(k); + } + + public Author(String k, String v) { + super(k, v); + } + +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/model/Category.java b/src/main/java/com/aventstack/extentreports/model/Category.java index a2195ac..f9eb334 100644 --- a/src/main/java/com/aventstack/extentreports/model/Category.java +++ b/src/main/java/com/aventstack/extentreports/model/Category.java @@ -1,12 +1,15 @@ package com.aventstack.extentreports.model; -public class Category - extends TestAttribute { +public class Category extends Attribute { - private static final long serialVersionUID = -7850780488330456977L; + private static final long serialVersionUID = 2652701333761577144L; - public Category(String k) { - super(k); - } - -} + public Category(String k) { + super(k); + } + + public Category(String k, String v) { + super(k, v); + } + +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/model/Device.java b/src/main/java/com/aventstack/extentreports/model/Device.java index 05a99f5..e148219 100644 --- a/src/main/java/com/aventstack/extentreports/model/Device.java +++ b/src/main/java/com/aventstack/extentreports/model/Device.java @@ -1,12 +1,15 @@ package com.aventstack.extentreports.model; -public class Device - extends TestAttribute { +public class Device extends Attribute { - private static final long serialVersionUID = 4823653818257315805L; + private static final long serialVersionUID = -3675996041755598043L; - public Device(String device) { - super(device); + public Device(String k) { + super(k); + } + + public Device(String k, String v) { + super(k, v); } -} +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/model/ExceptionInfo.java b/src/main/java/com/aventstack/extentreports/model/ExceptionInfo.java index ee05a60..bbadc83 100644 --- a/src/main/java/com/aventstack/extentreports/model/ExceptionInfo.java +++ b/src/main/java/com/aventstack/extentreports/model/ExceptionInfo.java @@ -2,39 +2,31 @@ import java.io.Serializable; -import com.aventstack.extentreports.utils.ExceptionUtil; - public class ExceptionInfo implements Serializable { private static final long serialVersionUID = 2672123037706464734L; private String exceptionName; private String stackTrace; - private Throwable t; - - public ExceptionInfo() { } - - public ExceptionInfo(Throwable t) { - setException(t); - setExceptionName(ExceptionUtil.getExceptionHeadline(t)); - setStackTrace(ExceptionUtil.getStackTrace(t)); - } - - // exception-name - public String getExceptionName() { return exceptionName; } - - public void setExceptionName(String exceptionName) { this.exceptionName = exceptionName; } - - // stack-trace - public String getStackTrace() { return stackTrace; } - - public void setStackTrace(String stackTrace) { - this.stackTrace = stackTrace; - } - - // exception - public void setException(Throwable t) { this.t = t; } - - public Throwable getException() { return t; } - + private Throwable throwable; + + public String getExceptionName() { + return exceptionName; + } + public void setExceptionName(String exceptionName) { + this.exceptionName = exceptionName; + } + public String getStackTrace() { + return stackTrace; + } + public void setStackTrace(String stackTrace) { + this.stackTrace = stackTrace; + } + public Throwable getThrowable() { + return throwable; + } + public void setThrowable(Throwable throwable) { + this.throwable = throwable; + } + } \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/model/ExceptionTestContext.java b/src/main/java/com/aventstack/extentreports/model/ExceptionTestContext.java deleted file mode 100644 index 1d30a1c..0000000 --- a/src/main/java/com/aventstack/extentreports/model/ExceptionTestContext.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.aventstack.extentreports.model; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -public class ExceptionTestContext - implements Serializable { - - private static final long serialVersionUID = -2516200535748363722L; - - private ExceptionInfo exceptionInfo; - private List testList = new ArrayList<>(); - - public ExceptionTestContext(ExceptionInfo exceptionInfo) { - this.exceptionInfo = exceptionInfo; - } - - public void setTest(Test test) { - testList.add(test); - } - - public List getTestList() { - return testList; - } - - public ExceptionInfo getExceptionInfo() { - return exceptionInfo; - } - -} diff --git a/src/main/java/com/aventstack/extentreports/model/IAddsMedia.java b/src/main/java/com/aventstack/extentreports/model/IAddsMedia.java deleted file mode 100644 index 87d95d3..0000000 --- a/src/main/java/com/aventstack/extentreports/model/IAddsMedia.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.aventstack.extentreports.model; - -import java.io.IOException; - -public interface IAddsMedia { - - /** - * Adds a snapshot to the test or log with title - * - * @param imagePath Image path - * @param title Image title - * - * @return Object this method is called from, generally {@link com.aventstack.extentreports.ExtentTest} or {@link Log} - * - * @throws IOException thrown if the imagePath of image is not found - */ - T addScreenCaptureFromPath(String imagePath, String title) throws IOException; - - /** - * Adds a snapshot to test or log - * - * @param imagePath Image path - * - * @return Object this method is called from, generally {@link com.aventstack.extentreports.ExtentTest} or {@link Log} - * - * @throws IOException thrown if the imagePath of image is not found - */ - T addScreenCaptureFromPath(String imagePath) throws IOException; - - /** - * Adds a base64 screenshot - * - * @param s base64 string - * @param title Image title - * - * @return Object this method is called from, generally {@link com.aventstack.extentreports.ExtentTest} or {@link Log} - */ - T addScreenCaptureFromBase64String(String s, String title); - - /** - * Adds a base64 screenshot - * - * @param s base64 string - * - * @return Object this method is called from, generally {@link com.aventstack.extentreports.ExtentTest} or {@link Log} - */ - T addScreenCaptureFromBase64String(String s); - - /** - * Adds a screencast to test or log - * - * @param screencastPath Screencast path - * - * @return Object this method is called from, generally {@link com.aventstack.extentreports.ExtentTest} or {@link Log} - * - * @throws IOException thrown if the screencastPath of image is not found - */ - T addScreencastFromPath(String screencastPath) throws IOException; -} diff --git a/src/main/java/com/aventstack/extentreports/model/Log.java b/src/main/java/com/aventstack/extentreports/model/Log.java index 204d2d0..3532094 100644 --- a/src/main/java/com/aventstack/extentreports/model/Log.java +++ b/src/main/java/com/aventstack/extentreports/model/Log.java @@ -6,147 +6,93 @@ import org.bson.types.ObjectId; -import com.aventstack.extentreports.ExtentTest; import com.aventstack.extentreports.RunResult; import com.aventstack.extentreports.Status; -import com.aventstack.extentreports.markuputils.Markup; - -public class Log - implements RunResult, Serializable, BasicMongoReportElement { - - private static final long serialVersionUID = 1594512136869286425L; - - private AbstractStructure screenCaptureContext; - private AbstractStructure screencastContext; - private ExtentTest parent; - private Test parentModel; - private Markup markup; - private Date timestamp = Calendar.getInstance().getTime(); - private Status logStatus; - private String stepName; - private String details; - private int sequence; - private ObjectId objectId; - private ExceptionInfo exceptionInfo; - - public Log(Test test) { - this.parentModel = test; - } - - public Log(ExtentTest test) { - this.parent = test; - } - - public Date getTimestamp() { - return timestamp; - } - public void setTimestamp(Date timestamp) { - this.timestamp = timestamp; - } - - public void setStatus(Status logStatus) { - this.logStatus = logStatus; - } - public Status getStatus() { - return logStatus; - } - - public void setStepName(String stepName) { - this.stepName = stepName; - } - public String getStepName() { - return stepName; - } - - public void setDetails(String details) { - this.details = details; - } - public String getDetails() { - return details; - } - - public void setMarkup(Markup markup) { - this.markup = markup; - } - public Markup getMarkup() { - return markup; - } - - public void setSequence(int sequence) { - this.sequence = sequence; - } - public int getSequence() { - return sequence; - } - - public void setScreenCapture(ScreenCapture screenCapture) { - if (screenCaptureContext == null) { - screenCaptureContext = new AbstractStructure<>(); - } - screenCaptureContext.add(screenCapture); - screenCapture.setTestObjectId(getParent().getModel().getObjectId()); - } - - public AbstractStructure getScreenCaptureContext() { - return screenCaptureContext; - } - - public boolean hasScreenCapture() { - return screenCaptureContext != null - && screenCaptureContext.size() > 0; - } - - public void setScreencast(Screencast screencast) { - if (screencastContext == null) { - screencastContext = new AbstractStructure<>(); - } - screencastContext.add(screencast); - } - - public AbstractStructure getScreencastContext() { - return screencastContext; - } - - public boolean hasScreencast() { - return screencastContext != null - && screencastContext.size() > 0; - } - - public ExtentTest getParent() { - return parent; - } - - public Test getParentModel() { - return parent == null - ? parentModel - : parent.getModel(); - } - - @Override - public ObjectId getObjectId() { - return objectId; - } - - @Override - public void setObjectId(ObjectId id) { - objectId = id; - } - - public void setExceptionInfo(ExceptionInfo exceptionInfo) { - this.exceptionInfo = exceptionInfo; - } - - public ExceptionInfo getExceptionInfo() { - return exceptionInfo; - } - - @Override - public String toString() { - return "[log] " + - " {timestamp: " + getTimestamp() + "," + - " status: " + getStatus() + "," + - " details: " + getDetails() + - " }"; - } - -} \ No newline at end of file + +public class Log implements Serializable, RunResult, BasicMongoReportElement { + + private static final long serialVersionUID = 8072065800800347981L; + private Date timestamp = Calendar.getInstance().getTime(); + + private ExceptionInfo exceptionInfo; + private AbstractStructure screenCaptureContext; + private transient Test test; + private Status status; + private String details; + private int sequence; + private ObjectId objectId; + + public Log(Test test) { + this.test = test; + } + + public Date getTimestamp() { + return timestamp; + } + + public void setTimestamp(Date timestamp) { + this.timestamp = timestamp; + } + + public ExceptionInfo getExceptionInfo() { + return exceptionInfo; + } + + public void setExceptionInfo(ExceptionInfo exceptionInfo) { + this.exceptionInfo = exceptionInfo; + } + + public AbstractStructure getScreenCaptureContext() { + if (screenCaptureContext == null) { + screenCaptureContext = new AbstractStructure<>(); + } + return screenCaptureContext; + } + + public void setScreenCaptureContext(AbstractStructure screenCapture) { + this.screenCaptureContext = screenCapture; + } + + public Test getTest() { + return test; + } + + public void setTest(Test test) { + this.test = test; + } + + public Status getStatus() { + return status; + } + + public void setStatus(Status status) { + this.status = status; + } + + public String getDetails() { + return details; + } + + public void setDetails(String details) { + this.details = details; + } + + public int getSequence() { + return sequence; + } + + public void setSequence(int sequence) { + this.sequence = sequence; + } + + @Override + public ObjectId getObjectId() { + return objectId; + } + + @Override + public void setObjectId(ObjectId id) { + this.objectId = id; + } + +} diff --git a/src/main/java/com/aventstack/extentreports/model/Media.java b/src/main/java/com/aventstack/extentreports/model/Media.java index f87ea9e..b5343c5 100644 --- a/src/main/java/com/aventstack/extentreports/model/Media.java +++ b/src/main/java/com/aventstack/extentreports/model/Media.java @@ -1,119 +1,79 @@ package com.aventstack.extentreports.model; import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; import org.bson.types.ObjectId; -import com.aventstack.extentreports.utils.FileUtil; - -public class Media - implements Serializable { - - private static final long serialVersionUID = -5706630485211806728L; - - private ObjectId id; - private ObjectId reportId; - private ObjectId testId; - private ObjectId logId; - private String name; - private String description; - private String path; - private String base64String; - private int seq; - private long fileSize = 0; - - private MediaType mediaType; - - public void setObjectId(ObjectId id) { - this.id = id; - } - - public ObjectId getObjectId() { - return id; +public class Media implements Serializable { + + private static final long serialVersionUID = 2620739620884939951L; + private String name = ""; + private String description; + private String path; + private int sequence; + private long fileSize = 0; + private Map bsonId; + private String resolvedPath; + + public String getName() { + return name; } - - public void setReportObjectId(ObjectId reportId) { - this.reportId = reportId; - } - - public ObjectId getReportObjectId() { - return reportId; + + public void setName(String name) { + this.name = name; } - public void setTestObjectId(ObjectId testId) { - this.testId = testId; - } - - public ObjectId getTestObjectId() { - return testId; + public String getDescription() { + return description; } - - public void setLogObjectId(ObjectId logId) { - this.logId = logId; - } - - public ObjectId getLogObjectId() { - return logId; + + public void setDescription(String description) { + this.description = description; } - - public void setName(String name) { - this.name = name; - } - - public String getName() { - return name; + + public String getPath() { + return path; } - - protected void setDescription(String description) { - this.description = description; - } - - protected String getDescription() { - return description; + + public void setPath(String path) { + this.path = path; } - - public void setPath(String path) { - this.path = path; - setFileSize(FileUtil.getFileSize(path)); - if (getName() == null || getName().isEmpty()) - setName(FileUtil.getFileName(path)); - } - - public String getPath() { - return path; + + public int getSequence() { + return sequence; } - public long getFileSize() { - return fileSize; - } + public void setSequence(int sequence) { + this.sequence = sequence; + } - public void setFileSize(long fileSize) { - this.fileSize = fileSize; - } + public long getFileSize() { + return fileSize; + } + + public void setFileSize(long fileSize) { + this.fileSize = fileSize; + } + + public Map getBsonId() { + if (bsonId == null) { + bsonId = new HashMap<>(); + } + return bsonId; + } + + public void setBsonId(Map bsonId) { + this.bsonId = bsonId; + } - public void setMediaType(MediaType mediaType) { - this.mediaType = mediaType; - } - - public MediaType getMediaType() { - return mediaType; + public String getResolvedPath() { + return resolvedPath == null ? getPath() : resolvedPath; } - public void setSequence(int seq) { - this.seq = seq; - } - - public int getSequence() { - return seq; + public void setResolvedPath(String resolvedPath) { + this.resolvedPath = resolvedPath; } - public void setBase64String(String string) { - string = string.contains("data:") || string.contains("image/") ? string : "data:image/png;base64," + string; - this.base64String = string; - } - - public String getBase64String() { - return base64String; - } - } diff --git a/src/main/java/com/aventstack/extentreports/model/MediaType.java b/src/main/java/com/aventstack/extentreports/model/MediaType.java deleted file mode 100644 index 6163475..0000000 --- a/src/main/java/com/aventstack/extentreports/model/MediaType.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.aventstack.extentreports.model; - -public enum MediaType { - IMG, - VID -} diff --git a/src/main/java/com/aventstack/extentreports/model/ScreenCapture.java b/src/main/java/com/aventstack/extentreports/model/ScreenCapture.java index 1021c4a..493d296 100644 --- a/src/main/java/com/aventstack/extentreports/model/ScreenCapture.java +++ b/src/main/java/com/aventstack/extentreports/model/ScreenCapture.java @@ -1,26 +1,31 @@ package com.aventstack.extentreports.model; -public class ScreenCapture - extends Media { +public class ScreenCapture extends Media { - private static final long serialVersionUID = -3413285738443448335L; + private static final long serialVersionUID = 3876935785138278521L; + private String base64; - public String getSource() { - if (getBase64String() != null) - return "base64-img"; + public String getBase64String() { + return base64; + } - return ""; - } - - public String getSourceWithIcon() { - return "img"; - } - - public String getScreenCapturePath() { - return getPath() != null ? getPath() : getBase64String(); - } + public void setBase64String(String base64) { + base64 = base64.contains("data:") || base64.contains("image/") ? base64 : "data:image/png;base64," + base64; + this.base64 = base64; + } + + public String getScreenCapturePath() { + return getPath() != null ? getPath() : getBase64String(); + } - public Boolean isBase64() { - return getBase64String() != null; + public Boolean isBase64() { + return getBase64String() != null; + } + + public String getSource() { + if (getBase64String() != null) + return "base64-img"; + return ""; } -} \ No newline at end of file + +} diff --git a/src/main/java/com/aventstack/extentreports/model/Screencast.java b/src/main/java/com/aventstack/extentreports/model/Screencast.java deleted file mode 100644 index e3c3c81..0000000 --- a/src/main/java/com/aventstack/extentreports/model/Screencast.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.aventstack.extentreports.model; - -public class Screencast - extends Media { - - private static final long serialVersionUID = -3413285738443448335L; - - public String getSource() { - return ""; - } - - public String getSourceWithIcon() { - return getSource(); - } - -} diff --git a/src/main/java/com/aventstack/extentreports/model/SystemAttribute.java b/src/main/java/com/aventstack/extentreports/model/SystemAttribute.java index 13baa26..27ed149 100644 --- a/src/main/java/com/aventstack/extentreports/model/SystemAttribute.java +++ b/src/main/java/com/aventstack/extentreports/model/SystemAttribute.java @@ -1,20 +1,15 @@ package com.aventstack.extentreports.model; -public class SystemAttribute - extends Attribute { +public class SystemAttribute extends Attribute { - private static final long serialVersionUID = 7531709191041382750L; + private static final long serialVersionUID = -6374771272610470521L; - public SystemAttribute(String k, String v) { - super(k, v); - } - - public String getName() { - return getKey(); - } - - public void setName(String name) { - setKey(name); - } + public SystemAttribute(String k) { + super(k); + } -} + public SystemAttribute(String k, String v) { + super(k, v); + } + +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/model/Test.java b/src/main/java/com/aventstack/extentreports/model/Test.java index 9ae3719..0df24fb 100644 --- a/src/main/java/com/aventstack/extentreports/model/Test.java +++ b/src/main/java/com/aventstack/extentreports/model/Test.java @@ -1,12 +1,9 @@ package com.aventstack.extentreports.model; import java.io.Serializable; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.ArrayList; import java.util.Calendar; import java.util.Date; -import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import org.bson.types.ObjectId; @@ -15,505 +12,373 @@ import com.aventstack.extentreports.RunResult; import com.aventstack.extentreports.Status; import com.aventstack.extentreports.gherkin.model.IGherkinFormatterModel; +import com.google.gson.annotations.Expose; -public class Test - implements BasicMongoReportElement, RunResult, Serializable { +public class Test implements Serializable, RunResult, BasicMongoReportElement { - private static final long serialVersionUID = 5590943223572254960L; - private static final AtomicInteger atomicInt = new AtomicInteger(0); - - /** - * An instance of {@link ExtentReports} - */ - private transient ExtentReports extent; - - /** - * Level describes the hierarchy of the test in the tree. A level 0 indicates a parent - * test. Level 1 indicates an immediate child of the parent, level 2 indicates an immediate - * child of the Child and so on.. The bottom-most test in the hierarchy is considered - * a leaf - */ - private int level = 0; - - /** - * A unique ID, generated by AtomicInteger - */ - private int testId = atomicInt.incrementAndGet(); - - /** - * If this Test is at the top-most level, or in other words, has a level value of 0, parent - * will be null. This field will only contain a value if the Test is a child, or has a level - * 1 or greater. - */ - private Test parent; - - /** - * {@link Status} of this test, defaults to PASS - */ - private Status status = Status.PASS; - - /** - * A structure containing all nodes of this test - */ - private AbstractStructure node; - - /** - * A structure containing all logs/events of this test - */ - private AbstractStructure log; - - /** - * A structure containing all categories assigned to this test - */ - private AbstractStructure category; + private static final long serialVersionUID = -8681630689550647312L; + private static final AtomicInteger atomicInt = new AtomicInteger(0); - /** - * A structure containing all authors assigned to this test - */ - private AbstractStructure author; - - /** - * A structure containing all devices assigned to this test - */ - private AbstractStructure device; - - /** - * Time the test was started - */ - private Date startTime = Calendar.getInstance().getTime(); - - /** - * Time the test was ended - */ - private Date endTime = Calendar.getInstance().getTime(); - - /** + /** + * An instance of {@link ExtentReports} + */ + private transient ExtentReports extent; + + /** + * Level describes the hierarchy of the test in the tree. A level 0 indicates a + * parent test. Level 1 indicates an immediate child of the parent, level 2 + * indicates an immediate child of the Child and so on.. The bottom-most test in + * the hierarchy is considered a leaf + */ + private int level = 0; + + /** + * A unique ID, generated by AtomicInteger + */ + private transient int id = atomicInt.incrementAndGet(); + + /** * An assigned {@link ObjectId} */ - private ObjectId mongoId; - - /** - * Type of BDD object represented by {@link IGherkinFormatterModel}. It can have one - * of the following values: - * - *
    - *
  • {@link com.aventstack.extentreports.gherkin.model.Feature}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Background}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Scenario}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Given}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.When}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.Then}
  • - *
  • {@link com.aventstack.extentreports.gherkin.model.And}
  • - *
- */ - private Class bddType; - - /** - * A list of {@link ScreenCapture} - */ - private transient List screenCaptureList; - - /** - * A list of {@link Screencast} - */ - private transient List screencastList; - - /** - * A list of {@link ExceptionInfo} - */ - private transient List exceptionList; - - /** - * Name of the test - */ - private String name; - - /** - * Hierarchical name of the test - * - *

- * Note: This field will equal the name if the test is the top-most level. - * - *

- * For tests having level 1 or greater, the hierarchical name would be separated by - * a dot character as: - * - * Test.Child.GrandChild - */ - private String hierarchicalName; - - /** - * Description - */ - private String description; - - /** - * Indicates if the test has ended - */ - private boolean ended = false; - - /** - * This setting allows setting test with your own time-stamps. With this enabled, Extent - * does not use time-stamps for tests at the time they were created - */ - private boolean usesManualConfiguration = false; - - - // if used via listener, allow manual configuration of model - public void setUseManualConfiguration(boolean b) { - this.usesManualConfiguration = b; - } - - public ExtentReports getExtentInstance() { - return extent; - } - - public void setExtentInstance(ExtentReports extent) { - this.extent = extent; - } - - public boolean isChildNode() { - return level > 0; - } - - public int getLevel() { - return level; - } - - public void setLevel(int level) { - this.level = level; - } - - - public void setParent(Test parent) { - this.parent = parent; - } - - public Test getParent() { return parent; } - - public AbstractStructure getNodeContext() { - if (node == null) { - node = new AbstractStructure<>(); - } - - return node; - } - - public boolean hasChildren() { - return node != null && node.getAll() != null && node.getAll().size() > 0; - } - - public void setStartTime(Date startTime) { - this.startTime = startTime; - } - - public Date getStartTime() { - return startTime; - } - - public void setEndTime(Date endTime) { - this.endTime = endTime; - } - - private void setEndTimeFromChildren() { - if (hasChildren()) { - setStartTime(getNodeContext().getFirst().getStartTime()); - setEndTime(getNodeContext().getLast().getEndTime()); - } else if (hasLog()) { - Date lastLogEndTime = getLogContext().getLast().getTimestamp(); - setEndTime(lastLogEndTime); - } - } - - public Date getEndTime() { - return endTime; - } - - public boolean hasEnded() { - return ended; - } - - public String getRunDuration() { - long diff = endTime.getTime() - startTime.getTime(); - - long secs = diff / 1000; - long millis = diff % 1000; - long mins = secs / 60; - secs = secs % 60; - long hours = mins / 60; - mins = mins % 60; - - return hours + "h " + mins + "m " + secs + "s+" + millis + "ms"; - } - - public Long getRunDurationMillis() { - return endTime.getTime() - startTime.getTime(); - } - - // default status when the test starts - public void setStatus(Status status) { - this.status = status; - } - - public Status getStatus() { - return status; - } - - public void trackLastRunStatus() { - getLogContext().getAll().forEach(x -> updateStatus(x.getStatus())); - - status = (status == Status.INFO || status == Status.DEBUG) - ? Status.PASS - : status; - } - - private synchronized void updateStatus(Status logStatus) { - int logStatusIndex = Status.getStatusHierarchy().indexOf(logStatus); - int testStatusIndex = Status.getStatusHierarchy().indexOf(status); - - status = logStatusIndex < testStatusIndex ? logStatus : status; - } - - public void end() { - updateTestStatusRecursive(this); - endChildrenRecursive(this); - - status = (status == Status.INFO || status == Status.DEBUG) - ? Status.PASS - : status; - - if (!usesManualConfiguration) - setEndTimeFromChildren(); - } - - private synchronized void updateTestStatusRecursive(Test test) { - test.getLogContext().getAll().forEach(x -> updateStatus(x.getStatus())); - - if (test.hasChildren()) { - test.getNodeContext().getAll().forEach(this::updateTestStatusRecursive); - } - - // if not all children are marked SKIP, then: - // ensure the parent has a status that is not SKIP - if (!test.isBehaviorDrivenType()) { - boolean hasNodeNotSkipped = test.getNodeContext().getAll() - .stream() - .anyMatch(x -> x.getStatus() != Status.SKIP); - - if (status == Status.SKIP && hasNodeNotSkipped) { - // reset status - status = Status.PASS; - // compute new status - test.getNodeContext().getAll() - .stream() - .filter(x -> x.getStatus() != Status.SKIP) - .forEach(this::updateTestStatusRecursive); - } - } - } - - private void endChildrenRecursive(Test test) { - test.getNodeContext().getAll().forEach(Test::end); - } - - public AbstractStructure getLogContext() { - if (log == null) { - log = new AbstractStructure<>(); - } - return log; - } - - public boolean hasLog() { - return log != null && !log.isEmpty(); - } - - public void setDescription(String description) { - this.description = description; - } - - public String getDescription() { return description; } - - public void setName(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public String getHierarchicalName() { - hierarchicalName = parent == null - ? name - : String.join(".", parent.getHierarchicalName(), getName()); - return hierarchicalName; - } - - public boolean hasAttributes() { - return hasAuthor() || hasCategory() || hasDevice(); - } - - public AbstractStructure getCategoryContext() { - if (category == null) { - category = new AbstractStructure<>(); - } - return category; - } - - public boolean hasCategory(String name) { - return hasCategory() - && category.getAll() - .stream() - .anyMatch(x -> x.getName().equals(name)); - } - - public boolean hasCategoryNode(String name) { - return getNodeContext().getAll() - .stream() - .anyMatch(x -> x.hasCategory(name)); - } - - public boolean hasCategory() { - return category != null && !category.isEmpty(); - } - - public void setCategory(TestAttribute category) { - getCategoryContext().add(category); - } - - public TestAttribute getCategory(Integer index) { - if (hasCategory() && index < category.size()) { - return category.get(index); - } - return null; - } - - public AbstractStructure getAuthorContext() { - if (author == null) { - author = new AbstractStructure<>(); - } - return author; - } - - public boolean hasAuthor() { - return author != null && !author.isEmpty(); - } - - public void setAuthor(TestAttribute author) { - getAuthorContext().add(author); - } - - public TestAttribute getAuthor(Integer index) { - if (hasAuthor() && index < author.size()) { - return author.get(index); - } - return null; - } - - public AbstractStructure getDeviceContext() { - if (device == null) { - device = new AbstractStructure<>(); - } - return device; - } - - public boolean hasDevice() { - return device != null && !device.isEmpty(); - } - - public void setDevice(TestAttribute device) { - getDeviceContext().add(device); - } - - public TestAttribute getDevice(Integer index) { - if (hasDevice() && index < author.size()) { - return device.get(index); - } - return null; - } - - public void setExceptionInfo(ExceptionInfo exceptionInfo) { - if (exceptionList == null) { - exceptionList = new ArrayList<>(); - } - exceptionList.add(exceptionInfo); - } - - public List getExceptionInfoList() { - return exceptionList; - } - - public boolean hasException() { - return exceptionList != null && !exceptionList.isEmpty(); - } - - public boolean hasMedia() { - return screenCaptureList != null - && !screenCaptureList.isEmpty() - && screencastList != null - && !screencastList.isEmpty(); - } - - public void setScreenCapture(ScreenCapture screenCapture) { - if (screenCaptureList == null) { - screenCaptureList = new ArrayList<>(); - } - screenCaptureList.add(screenCapture); - } - - public List getScreenCaptureList() { - return screenCaptureList; - } - - public Boolean hasScreenCapture() { - return screenCaptureList != null && !screenCaptureList.isEmpty(); - } - - public void setScreencast(Screencast screencast) { - if (screencastList == null) { - screencastList = new ArrayList<>(); - } - screencastList.add(screencast); - } - - public List getScreencastList() { - return screencastList; - } - - public boolean isBehaviorDrivenType() { - return bddType != null; - } - - public void setBehaviorDrivenType(IGherkinFormatterModel type) { - bddType = type.getClass(); - } - - public void setBehaviorDrivenType(Class type) { - bddType = type; - } - - public Class getBehaviorDrivenType() { - return bddType; - } - - public String getBehaviorDrivenTypeName() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { - Method method = bddType.getMethod("getGherkinName"); - Object o = method.invoke(null, (Object[]) null); - return o.toString(); - } - - void setID(int id) { - testId = id; - } - - public int getID() { - return testId; - } - - public void setObjectId(ObjectId id) { - mongoId = id; - } - - public ObjectId getObjectId() { - return mongoId; + private ObjectId objectId; + + /** + * If this Test is at the top-most level, or in other words, has a level value + * of 0, parent will be null. This field will only contain a value if the Test + * is a child, or has a level 1 or greater. + */ + private transient Test parent; + + /** + * {@link Status} of this test, defaults to PASS + */ + private Status status = Status.PASS; + + /** + * A structure containing all nodes of this test + */ + private AbstractStructure nodeContext; + + /** + * A structure containing all logs/events of this test + */ + private AbstractStructure logContext; + + /** + * A structure containing all categories assigned to this test + */ + private AbstractStructure categoryContext; + + /** + * A structure containing all authors assigned to this test + */ + private AbstractStructure authorContext; + + /** + * A structure containing all devices assigned to this test + */ + private AbstractStructure deviceContext; + + /** + * Time the test was started + */ + private Date startTime = Calendar.getInstance().getTime(); + + /** + * Time the test was ended + */ + private Date endTime = Calendar.getInstance().getTime(); + + /** + * Type of BDD object represented by {@link IGherkinFormatterModel}. It can have + * one of the following values: + * + *

    + *
  • {@link com.aventstack.extentreports.gherkin.model.Feature}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Background}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Scenario}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Given}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.When}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.Then}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.And}
  • + *
  • {@link com.aventstack.extentreports.gherkin.model.But}
  • + *
+ */ + private transient Class bddType; + + @Expose + private String bddTypeName; + + /** + * A list of {@link ScreenCapture} + */ + private transient AbstractStructure screenCaptureContext; + + /** + * A list of {@link ExceptionInfo} + */ + private transient AbstractStructure exceptionInfoContext; + + /** + * Name of the test + */ + private String name; + + /** + * Description + */ + private String description; + + /** + * This setting allows setting test with your own time-stamps. With this + * enabled, Extent does not use time-stamps for tests at the time they were + * created + */ + private boolean usesManualConfiguration = false; + + public ExtentReports getExtent() { + return extent; + } + + public void setExtent(ExtentReports extent) { + this.extent = extent; } + + public int getLevel() { + return level; + } + + public void setLevel(int level) { + this.level = level; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public Test getParent() { + return parent; + } + + public void setParent(Test parent) { + this.parent = parent; + } + + public Status getStatus() { + return status; + } + + public void setStatus(Status status) { + this.status = status; + } + + public AbstractStructure getNodeContext() { + if (nodeContext == null) { + nodeContext = new AbstractStructure<>(); + } + return nodeContext; + } + + public void setNodeContext(AbstractStructure node) { + this.nodeContext = node; + } + + public AbstractStructure getLogContext() { + if (logContext == null) { + logContext = new AbstractStructure<>(); + } + return logContext; + } + + public void setLogContext(AbstractStructure log) { + this.logContext = log; + } + + public AbstractStructure getCategoryContext() { + if (categoryContext == null) { + categoryContext = new AbstractStructure<>(); + } + return categoryContext; + } + + public void setCategoryContext(AbstractStructure category) { + this.categoryContext = category; + } + + public AbstractStructure getAuthorContext() { + if (authorContext == null) { + authorContext = new AbstractStructure<>(); + } + return authorContext; + } + + public void setAuthorContext(AbstractStructure author) { + this.authorContext = author; + } + + public AbstractStructure getDeviceContext() { + if (deviceContext == null) { + deviceContext = new AbstractStructure<>(); + } + return deviceContext; + } + + public void setDeviceContext(AbstractStructure device) { + this.deviceContext = device; + } + + public Date getStartTime() { + return startTime; + } + + public void setStartTime(Date startTime) { + this.startTime = startTime; + } + + public Date getEndTime() { + return endTime; + } + + public void setEndTime(Date endTime) { + this.endTime = endTime; + } + + public Class getBddType() { + return bddType; + } + + public void setBddType(Class bddType) { + this.bddType = bddType; + bddTypeName = getBehaviorDrivenTypeName(); + } + + public AbstractStructure getScreenCaptureContext() { + if (screenCaptureContext == null) { + screenCaptureContext = new AbstractStructure<>(); + } + return screenCaptureContext; + } + + public void setScreenCaptureContext(AbstractStructure screenCapture) { + this.screenCaptureContext = screenCapture; + } + + public AbstractStructure getExceptionInfoContext() { + if (exceptionInfoContext == null) { + exceptionInfoContext = new AbstractStructure<>(); + } + return exceptionInfoContext; + } + + public void setExceptionInfoContext(AbstractStructure exception) { + this.exceptionInfoContext = exception; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public boolean isUsesManualConfiguration() { + return usesManualConfiguration; + } + + public void setUsesManualConfiguration(boolean usesManualConfiguration) { + this.usesManualConfiguration = usesManualConfiguration; + } + + private synchronized void updateStatus(Status logStatus) { + int logStatusIndex = Status.getStatusHierarchy().indexOf(logStatus); + int testStatusIndex = Status.getStatusHierarchy().indexOf(status); + status = logStatusIndex < testStatusIndex ? logStatus : status; + } + + public void end() { + updateTestStatusRecursive(this); + endChildrenRecursive(this); + status = (status == Status.INFO || status == Status.DEBUG) ? Status.PASS : status; + if (!usesManualConfiguration) { + computeEndTimeFromChildren(); + } + } + + private synchronized void updateTestStatusRecursive(Test test) { + test.getLogContext().getAll().forEach(x -> updateStatus(x.getStatus())); + + if (!test.getNodeContext().isEmpty()) { + test.getNodeContext().getAll().forEach(this::updateTestStatusRecursive); + } + + // if not all children are marked SKIP, then: + // ensure the parent has a status that is not SKIP + if (test.bddType == null) { + boolean hasNodeNotSkipped = test.getNodeContext().getAll().stream() + .anyMatch(x -> x.getStatus() != Status.SKIP); + + if (status == Status.SKIP && hasNodeNotSkipped) { + // reset status + status = Status.PASS; + // compute new status + test.getNodeContext().getAll().stream().filter(x -> x.getStatus() != Status.SKIP) + .forEach(this::updateTestStatusRecursive); + } + } + } + + private void endChildrenRecursive(Test test) { + test.getNodeContext().getAll().forEach(Test::end); + } + + public void computeEndTimeFromChildren() { + if (!getNodeContext().isEmpty()) { + setStartTime(getNodeContext().getFirst().getStartTime()); + setEndTime(getNodeContext().getLast().getEndTime()); + } else if (!getLogContext().isEmpty()) { + Date lastLogEndTime = getLogContext().getLast().getTimestamp(); + setEndTime(lastLogEndTime); + } + } + + public String getBehaviorDrivenTypeName() { + if (bddTypeName != null) { + return bddTypeName; + } + try { + Method method = bddType.getMethod("getGherkinName"); + Object o = method.invoke(null, (Object[]) null); + return o.toString(); + } catch (Exception e) { + return null; + } + } + + public Boolean isBehaviorDrivenType() { + return getBddType() != null; + } + + @Override + public ObjectId getObjectId() { + return objectId; + } + + @Override + public void setObjectId(ObjectId id) { + this.objectId = id; + } + } diff --git a/src/main/java/com/aventstack/extentreports/model/TestAttribute.java b/src/main/java/com/aventstack/extentreports/model/TestAttribute.java deleted file mode 100644 index 1d6fe70..0000000 --- a/src/main/java/com/aventstack/extentreports/model/TestAttribute.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.aventstack.extentreports.model; - -import java.io.Serializable; - -public abstract class TestAttribute - extends Attribute - implements Serializable { - - static final long serialVersionUID = 1010210091204302766L; - - public TestAttribute(String k) { - super(k); - } - - public String getName() { - return getKey(); - } - - public void setName(String name) { - setKey(name); - } - - public String getDescription() { - return getValue(); - } - - public void setDescription(String description) { - setValue(description); - } - -} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/model/TestAttributeTestContext.java b/src/main/java/com/aventstack/extentreports/model/TestAttributeTestContext.java deleted file mode 100644 index be32402..0000000 --- a/src/main/java/com/aventstack/extentreports/model/TestAttributeTestContext.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.aventstack.extentreports.model; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -import com.aventstack.extentreports.Status; - -public class TestAttributeTestContext - implements Serializable { - - private static final long serialVersionUID = 2595632998970711190L; - - private T testAttribute; - private List testList = new ArrayList<>(); - private int passed = 0; - private int failed = 0; - private int skip = 0; - private int others = 0; - - public TestAttributeTestContext(T testAttribute) { - this.testAttribute = testAttribute; - } - - public void setTest(Test test) { - updateTestStatusCounts(test); - testList.add(test); - } - - private void updateTestStatusCounts(Test test) { - passed += test.getStatus() == Status.PASS ? 1 : 0; - failed += test.getStatus() == Status.FAIL || test.getStatus() == Status.FATAL ? 1 : 0; - skip += test.getStatus() == Status.SKIP ? 1 : 0; - others += test.getStatus() != Status.PASS - && test.getStatus() != Status.FATAL - && test.getStatus() != Status.FAIL - && test.getStatus() != Status.SKIP? 1 : 0; - } - - public void refreshTestStatusCounts() { - passed = 0; - failed = 0; - skip = 0; - others = 0; - testList.forEach(this::updateTestStatusCounts); - } - - public List getTestList() { - return testList; - } - - public String getName() { - return testAttribute.getName(); - } - - public int getPassed() { - return passed; - } - - public int getFailed() { - return failed; - } - - public int getSkipped() { - return skip; - } - - public int getOthers() { - return others; - } - - public int size() { - return testList == null ? 0 : testList.size(); - } - - public boolean isEmpty() { - return size() == 0; - } - - public T getAttribute() { - return testAttribute; - } -} - diff --git a/src/main/java/com/aventstack/extentreports/model/context/ExceptionTestContext.java b/src/main/java/com/aventstack/extentreports/model/context/ExceptionTestContext.java new file mode 100644 index 0000000..7080bd9 --- /dev/null +++ b/src/main/java/com/aventstack/extentreports/model/context/ExceptionTestContext.java @@ -0,0 +1,33 @@ +package com.aventstack.extentreports.model.context; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import com.aventstack.extentreports.model.ExceptionInfo; +import com.aventstack.extentreports.model.Test; + +public class ExceptionTestContext implements Serializable { + + private static final long serialVersionUID = -2516200535748363722L; + + private ExceptionInfo exceptionInfo; + private List tests = new ArrayList<>(); + + public ExceptionTestContext(ExceptionInfo exceptionInfo) { + this.exceptionInfo = exceptionInfo; + } + + public void setTest(Test test) { + tests.add(test); + } + + public List getTests() { + return tests; + } + + public ExceptionInfo getExceptionInfo() { + return exceptionInfo; + } + +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/model/context/ExceptionTestContextStore.java b/src/main/java/com/aventstack/extentreports/model/context/ExceptionTestContextStore.java new file mode 100644 index 0000000..b15dea3 --- /dev/null +++ b/src/main/java/com/aventstack/extentreports/model/context/ExceptionTestContextStore.java @@ -0,0 +1,41 @@ +package com.aventstack.extentreports.model.context; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import com.aventstack.extentreports.model.ExceptionInfo; +import com.aventstack.extentreports.model.Test; + +/** + * Provides and tracks the collection of tests segregated by the type of + * {@link Exception} + * + */ +public class ExceptionTestContextStore { + + private List exceptionTestContext = new ArrayList<>(); + + public void setExceptionContext(ExceptionInfo ei, Test test) { + Optional exOptionalTestContext = exceptionTestContext.stream() + .filter(x -> x.getExceptionInfo().getExceptionName().equals(ei.getExceptionName())).findFirst(); + + if (exOptionalTestContext.isPresent()) { + List testList = exOptionalTestContext.get().getTests(); + + boolean b = testList.stream().anyMatch(t -> t.getId() == test.getId()); + + if (!b) { + exOptionalTestContext.get().setTest(test); + } + } else { + ExceptionTestContext exTestContext = new ExceptionTestContext(ei); + exTestContext.setTest(test); + exceptionTestContext.add(exTestContext); + } + } + + public List getExceptionTestContext() { + return exceptionTestContext; + } +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/model/context/SystemAttributeContext.java b/src/main/java/com/aventstack/extentreports/model/context/SystemAttributeContext.java new file mode 100644 index 0000000..5de8207 --- /dev/null +++ b/src/main/java/com/aventstack/extentreports/model/context/SystemAttributeContext.java @@ -0,0 +1,35 @@ +package com.aventstack.extentreports.model.context; + +import java.util.ArrayList; +import java.util.List; + +import com.aventstack.extentreports.model.SystemAttribute; + +/** + * A simple key-value pair collection to store System/Environment information + * + */ +public class SystemAttributeContext { + + private List list = new ArrayList<>(); + + public void setSystemAttribute(SystemAttribute sa) { + list.add(sa); + } + + public String getSystemAttribute(String k) { + return list.stream() + .filter(x -> x.getName().equals(k)) + .map(SystemAttribute::getValue) + .findFirst() + .orElse(null); + } + + public List getSystemAttributeList() { + return list; + } + + public void clear() { + list.clear(); + } +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/model/context/TestAttributeTestContext.java b/src/main/java/com/aventstack/extentreports/model/context/TestAttributeTestContext.java new file mode 100644 index 0000000..9354028 --- /dev/null +++ b/src/main/java/com/aventstack/extentreports/model/context/TestAttributeTestContext.java @@ -0,0 +1,84 @@ +package com.aventstack.extentreports.model.context; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import com.aventstack.extentreports.Status; +import com.aventstack.extentreports.model.Attribute; +import com.aventstack.extentreports.model.Test; + +public class TestAttributeTestContext implements Serializable { + + private static final long serialVersionUID = 2595632998970711190L; + + private List tests = new ArrayList<>(); + private T attr; + private int passed = 0; + private int failed = 0; + private int skipped = 0; + private int others = 0; + + public TestAttributeTestContext(T attr) { + this.attr = attr; + } + + public void setTest(Test test) { + updateTestStatusCounts(test); + tests.add(test); + } + + private void updateTestStatusCounts(Test test) { + if (test.getStatus() == Status.PASS) { + passed++; + } else if (test.getStatus() == Status.FAIL || test.getStatus() == Status.FATAL) { + failed++; + } else if (test.getStatus() == Status.SKIP) { + skipped++; + } else { + others++; + } + } + + public void refreshTestStatusCounts() { + passed = failed = skipped = others = 0; + tests.forEach(this::updateTestStatusCounts); + } + + public List getTests() { + return tests; + } + + public String getName() { + return attr.getName(); + } + + public int getPassed() { + return passed; + } + + public int getFailed() { + return failed; + } + + public int getSkipped() { + return skipped; + } + + public int getOthers() { + return others; + } + + public int size() { + return tests == null ? 0 : tests.size(); + } + + public boolean isEmpty() { + return size() == 0; + } + + public T getAttribute() { + return attr; + } + +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/model/context/TestAttributeTestContextStore.java b/src/main/java/com/aventstack/extentreports/model/context/TestAttributeTestContextStore.java new file mode 100644 index 0000000..0926fdc --- /dev/null +++ b/src/main/java/com/aventstack/extentreports/model/context/TestAttributeTestContextStore.java @@ -0,0 +1,62 @@ +package com.aventstack.extentreports.model.context; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Optional; + +import com.aventstack.extentreports.model.Attribute; +import com.aventstack.extentreports.model.Test; +import com.aventstack.extentreports.model.context.helpers.TestRemover; + +/** + * Uses an attribute context for {@link Attribute} (Category, Device, Author + * etc.) and tracks the collection of tests segregated by the type + * {@link Attribute} + * + * @param A {@link Attribute} type + */ +public class TestAttributeTestContextStore { + + private List> testAttrTestContext; + + public TestAttributeTestContextStore() { + testAttrTestContext = new ArrayList<>(); + } + + public void setAttributeContext(T attr, Test test) { + Optional> optTestContext = testAttrTestContext.stream() + .filter(x -> x.getName().equals(attr.getName())).findFirst(); + + if (optTestContext.isPresent()) { + List tests = optTestContext.get().getTests(); + + boolean b = tests.stream().anyMatch(t -> t.getId() == test.getId()); + + if (!b) { + optTestContext.get().setTest(test); + } + optTestContext.get().refreshTestStatusCounts(); + } else { + TestAttributeTestContext testAttrContext = new TestAttributeTestContext<>(attr); + testAttrContext.setTest(test); + testAttrTestContext.add(testAttrContext); + } + } + + public synchronized void removeTest(Test test) { + Iterator> iter = testAttrTestContext.iterator(); + while (iter.hasNext()) { + TestAttributeTestContext context = iter.next(); + TestRemover.remove(context.getTests(), test); + if (context.isEmpty()) { + iter.remove(); + } + } + } + + public List> getTestAttributeTestContext() { + return testAttrTestContext; + } + +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/model/context/helpers/TestRemover.java b/src/main/java/com/aventstack/extentreports/model/context/helpers/TestRemover.java new file mode 100644 index 0000000..b9837d1 --- /dev/null +++ b/src/main/java/com/aventstack/extentreports/model/context/helpers/TestRemover.java @@ -0,0 +1,65 @@ +package com.aventstack.extentreports.model.context.helpers; + +import java.util.List; +import java.util.stream.Collectors; + +import com.aventstack.extentreports.model.Test; + +public class TestRemover { + + /** + * Helper for removing test recursively. This flag determines when to break out + * of recursion + */ + private static boolean removed = false; + + private TestRemover() { + } + + /** + * Remove a test using its unique ID from a list + * + * @param testList a list of {@link Test} + * @param test {@link Test} to be removed + */ + public static void remove(List testList, Test test) { + removed = false; + findAndRemoveTest(testList, test); + testList.forEach(Test::end); + } + + /** + * Recursively traverses all tests, nodes upto the last leaf to find and remove + * the specified test + * + * @param list a list of {@link Test} + * @param test {@link Test} to be removed + */ + private synchronized static void findAndRemoveTest(List list, Test test) { + List filteredTestList = list.stream().filter(x -> x.getId() == test.getId()).collect(Collectors.toList()); + + if (filteredTestList.size() == 1) { + removeTest(list, filteredTestList.get(0)); + removed = true; + return; + } + + for (Test t : list) { + if (removed) { + return; + } + findAndRemoveTest(t.getNodeContext().getAll(), test); + } + } + + /** + * Removes the test from a given list of tests + * + * @param list a list of {@link Test} + * @param test {@link Test} to be removed + */ + private static void removeTest(List list, Test test) { + list.remove(test); + } + +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/model/service/LogService.java b/src/main/java/com/aventstack/extentreports/model/service/LogService.java new file mode 100644 index 0000000..daf9f53 --- /dev/null +++ b/src/main/java/com/aventstack/extentreports/model/service/LogService.java @@ -0,0 +1,11 @@ +package com.aventstack.extentreports.model.service; + +import com.aventstack.extentreports.model.Log; + +public class LogService { + + public static Boolean logHasScreenCapture(Log log) { + return !log.getScreenCaptureContext().isEmpty(); + } + +} diff --git a/src/main/java/com/aventstack/extentreports/model/service/ScreenCaptureService.java b/src/main/java/com/aventstack/extentreports/model/service/ScreenCaptureService.java new file mode 100644 index 0000000..bc3c0d3 --- /dev/null +++ b/src/main/java/com/aventstack/extentreports/model/service/ScreenCaptureService.java @@ -0,0 +1,35 @@ +package com.aventstack.extentreports.model.service; + +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; + +import com.aventstack.extentreports.model.ScreenCapture; +import com.aventstack.extentreports.utils.FileUtil; + +public class ScreenCaptureService { + + public static void resolvePath(ScreenCapture capture, String[] paths) { + if (paths == null || capture.isBase64()) { + return; + } + String capturePath = capture.getPath(); + String captureFileName = new File(capturePath).getName(); + if (!FileUtil.fileExists(capturePath)) { + for (String p : paths) { + Path path = Paths.get(p, capturePath); + if (path.toFile().exists()) { + capturePath = path.toFile().getAbsolutePath(); + break; + } + path = Paths.get(p, captureFileName); + if (path.toFile().exists()) { + capturePath = path.toFile().getAbsolutePath(); + break; + } + } + } + capture.setResolvedPath(capturePath); + } + +} diff --git a/src/main/java/com/aventstack/extentreports/model/service/TestService.java b/src/main/java/com/aventstack/extentreports/model/service/TestService.java new file mode 100644 index 0000000..1de5b69 --- /dev/null +++ b/src/main/java/com/aventstack/extentreports/model/service/TestService.java @@ -0,0 +1,84 @@ +package com.aventstack.extentreports.model.service; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import com.aventstack.extentreports.gherkin.model.IGherkinFormatterModel; +import com.aventstack.extentreports.model.Test; + +public class TestService { + + public static Boolean testHasAttributes(Test test) { + return testHasAuthor(test) || testHasCategory(test) || testHasDevice(test); + } + + public static Boolean testHasAuthor(Test test) { + return !test.getAuthorContext().isEmpty(); + } + + public static Boolean testHasCategory(Test test) { + return !test.getCategoryContext().isEmpty(); + } + + public static Boolean testHasDevice(Test test) { + return !test.getDeviceContext().isEmpty(); + } + + public static Boolean testHasException(Test test) { + return !test.getExceptionInfoContext().isEmpty(); + } + + public static Boolean testHasChildren(Test test) { + return !test.getNodeContext().isEmpty(); + } + + public static Boolean testHasLog(Test test) { + return !test.getLogContext().isEmpty(); + } + + public static Boolean testHasScreenCapture(Test test) { + return !test.getScreenCaptureContext().isEmpty(); + } + + public static Boolean isTestBehaviorDriven(Test test) { + return test.getBddType() != null; + } + + public static String getBehaviorDrivenTypeName(Class bddType) + throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, + InvocationTargetException { + Method method = bddType.getMethod("getGherkinName"); + Object o = method.invoke(null, (Object[]) null); + return o.toString(); + } + + public static String getBehaviorDrivenTypeName(Test test) throws NoSuchMethodException, SecurityException, + IllegalAccessException, IllegalArgumentException, InvocationTargetException { + return getBehaviorDrivenTypeName(test.getBddType()); + } + + public static String getRunDuration(Test test) { + long diff = test.getEndTime().getTime() - test.getStartTime().getTime(); + long secs = diff / 1000; + long millis = diff % 1000; + long mins = secs / 60; + secs = secs % 60; + long hours = mins / 60; + mins = mins % 60; + return hours + "h " + mins + "m " + secs + "s+" + millis + "ms"; + } + + public static Long getRunDurationMillis(Test test) { + return test.getEndTime().getTime() - test.getStartTime().getTime(); + } + + public static String getHierarchicalName(Test test) { + StringBuilder sb = new StringBuilder(test.getName()); + while (test.getParent() != null) { + test = test.getParent(); + sb.insert(0, test.getName() + "."); + } + return sb.toString(); + } + +} diff --git a/src/main/java/com/aventstack/extentreports/resource/OfflineResxDelegate.java b/src/main/java/com/aventstack/extentreports/offline/OfflineResxDelegate.java similarity index 71% rename from src/main/java/com/aventstack/extentreports/resource/OfflineResxDelegate.java rename to src/main/java/com/aventstack/extentreports/offline/OfflineResxDelegate.java index 1cecae7..d4d043e 100644 --- a/src/main/java/com/aventstack/extentreports/resource/OfflineResxDelegate.java +++ b/src/main/java/com/aventstack/extentreports/offline/OfflineResxDelegate.java @@ -1,28 +1,28 @@ -package com.aventstack.extentreports.resource; +package com.aventstack.extentreports.offline; import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; +import com.aventstack.extentreports.io.ResourceUtil; import com.aventstack.extentreports.utils.FileUtil; -import com.aventstack.extentreports.utils.ResourceUtil; public class OfflineResxDelegate { - + public static void saveOfflineResources(String baseResourceDirectory, String[] resx, String toPath) { FileUtil.createDirectory(toPath); for (String f : resx) { Path path = Paths.get(baseResourceDirectory, f); String fromPath = path.toString(); String toPathComplete = Paths.get(toPath, new File(f).getName()).toString(); - ResourceUtil.moveResource(fromPath, toPathComplete); - } + ResourceUtil.moveResource(fromPath, toPathComplete); + } } - + public static void saveOfflineResources(String[] resx, String toPath) { for (String f : resx) { - ResourceUtil.moveResource(f, toPath); - } + ResourceUtil.moveResource(f, toPath); + } } } diff --git a/src/main/java/com/aventstack/extentreports/reporter/AbstractReporter.java b/src/main/java/com/aventstack/extentreports/reporter/AbstractReporter.java index 36332b7..1dedb56 100644 --- a/src/main/java/com/aventstack/extentreports/reporter/AbstractReporter.java +++ b/src/main/java/com/aventstack/extentreports/reporter/AbstractReporter.java @@ -1,74 +1,189 @@ package com.aventstack.extentreports.reporter; +import java.io.IOException; import java.util.Calendar; +import java.util.Collection; import java.util.Date; import java.util.List; import com.aventstack.extentreports.AnalysisStrategy; import com.aventstack.extentreports.ReportAggregates; +import com.aventstack.extentreports.ReportStatusStats; import com.aventstack.extentreports.Status; +import com.aventstack.extentreports.mediastorage.LocalMediaStorageHandler; +import com.aventstack.extentreports.mediastorage.MediaStorage; +import com.aventstack.extentreports.model.Author; +import com.aventstack.extentreports.model.Category; +import com.aventstack.extentreports.model.Device; +import com.aventstack.extentreports.model.Log; +import com.aventstack.extentreports.model.ScreenCapture; +import com.aventstack.extentreports.model.Test; +import com.aventstack.extentreports.model.context.ExceptionTestContextStore; +import com.aventstack.extentreports.model.context.SystemAttributeContext; +import com.aventstack.extentreports.model.context.TestAttributeTestContextStore; -/** - * A base class for all Reporter types - * - */ -public abstract class AbstractReporter - extends ConfigurableReporter { - - protected List levels; - protected Date startTime = Calendar.getInstance().getTime(); - protected Date endTime = startTime; - protected List statusList; - +public abstract class AbstractReporter implements ExtentReporter { + + private Date startTime = Calendar.getInstance().getTime(); + private Date endTime = startTime; private AnalysisStrategy strategy = AnalysisStrategy.TEST; + private MediaStorage media; + private List testList; + private List testRunnerLogs; + private ExceptionTestContextStore exceptionContext; + private TestAttributeTestContextStore categoryContext; + private TestAttributeTestContextStore authorContext; + private TestAttributeTestContextStore deviceContext; + private SystemAttributeContext systemAttributeContext; + private ReportStatusStats stats; + private Collection statusCollection; + public void flush(ReportAggregates reportAggregates) { - this.startTime = reportAggregates.getStartTime(); - this.endTime = reportAggregates.getEndTime(); - this.statusList = reportAggregates.getStatusList(); + startTime = reportAggregates.getStartTime(); + endTime = reportAggregates.getEndTime(); + this.authorContext = reportAggregates.getAuthorContext(); + this.categoryContext = reportAggregates.getCategoryContext(); + this.deviceContext = reportAggregates.getDeviceContext(); + this.exceptionContext = reportAggregates.getExceptionContext(); + this.stats = reportAggregates.getReportStatusStats(); + this.systemAttributeContext = reportAggregates.getSystemAttributeContext(); + this.testList = reportAggregates.getTestList(); + this.testRunnerLogs = reportAggregates.getTestRunnerLogs(); + this.statusCollection = reportAggregates.getStatusCollection(); } - - protected Date getStartTime() { + + public Date getStartTime() { return startTime; } - - protected void setEndTime(Date endTime) { + + public void setStartTime(Date startTime) { + this.startTime = startTime; + } + + public void setEndTime(Date endTime) { this.endTime = endTime; } - - protected Date getEndTime() { + + public Date getEndTime() { return endTime; } - - @Override - public void setAnalysisStrategy(AnalysisStrategy strategy){ - this.strategy = strategy; - } - - @Override - public AnalysisStrategy getAnalysisStrategy() { - return strategy; - } - - public long getRunDuration() { - return endTime.getTime() - startTime.getTime(); - } - - public String getLongRunDuration() { + + public void setAnalysisStrategy(AnalysisStrategy strategy) { + this.strategy = strategy; + } + + public AnalysisStrategy getAnalysisStrategy() { + return strategy; + } + + public long getRunDuration() { + return endTime.getTime() - startTime.getTime(); + } + + public String getLongRunDuration() { long millis = getRunDuration(); - - long secs = millis / 1000; - long ms = millis % 1000; - long mins = secs / 60; - secs = (secs % 60); - long hours = mins / 60; - mins = mins % 60; - - return hours + "h " + mins + "m " + secs + "s+" + ms + "ms"; - } - - public List getStatusList() { - return statusList; + + long secs = millis / 1000; + long ms = millis % 1000; + long mins = secs / 60; + secs = (secs % 60); + long hours = mins / 60; + mins = mins % 60; + + return hours + "h " + mins + "m " + secs + "s+" + ms + "ms"; + } + + public List getTestList() { + return testList; + } + + public List getTestRunnerLogs() { + return testRunnerLogs; + } + + public TestAttributeTestContextStore getCategoryContextInfo() { + return categoryContext; + } + + public TestAttributeTestContextStore getAuthorContextInfo() { + return authorContext; + } + + public TestAttributeTestContextStore getDeviceContextInfo() { + return deviceContext; + } + + public ExceptionTestContextStore getExceptionContextInfo() { + return exceptionContext; + } + + public SystemAttributeContext getSystemAttributeContext() { + return systemAttributeContext; + } + + public ReportStatusStats getReportStatusStats() { + return stats; + } + + public Collection getStatusCollection() { + return statusCollection; + } + + @Override + public void onTestStarted(Test test) { + } + + @Override + public void onTestRemoved(Test test) { + } + + @Override + public void onNodeStarted(Test node) { + } + + @Override + public void onLogAdded(Test test, Log log) { + } + + @Override + public void onCategoryAssigned(Test test, Category category) { + } + + @Override + public void onAuthorAssigned(Test test, Author author) { + } + + @Override + public void onDeviceAssigned(Test test, Device device) { + } + + @Override + public void onScreenCaptureAdded(Test test, ScreenCapture screenCapture) throws IOException { + } + + @Override + public void onScreenCaptureAdded(Log log, ScreenCapture screenCapture) throws IOException { + } + + protected void autoCreateRelativePathMedia(ScreenCapture screenCapture, Boolean autoCreateRelativePath, + String destination) throws IOException { + // if user has not specific a configuration, exit + if (screenCapture.isBase64()) { + return; + } + // check always so user has the option to disable this setting at anytime + if (autoCreateRelativePath) { + if (media == null) { + media = new LocalMediaStorageHandler(); + media.init(destination); + } + media.storeMedia(screenCapture); + } + } + + @Override + public void stop() { } } diff --git a/src/main/java/com/aventstack/extentreports/reporter/BasicFileReporter.java b/src/main/java/com/aventstack/extentreports/reporter/BasicFileReporter.java index 9b00c02..92cf3b3 100644 --- a/src/main/java/com/aventstack/extentreports/reporter/BasicFileReporter.java +++ b/src/main/java/com/aventstack/extentreports/reporter/BasicFileReporter.java @@ -2,37 +2,22 @@ import java.io.File; import java.io.IOException; -import java.io.StringWriter; -import java.util.Arrays; -import java.util.Date; import java.util.HashMap; -import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; -import com.aventstack.extentreports.ExceptionTestContextImpl; import com.aventstack.extentreports.ExtentReports; import com.aventstack.extentreports.ReportAggregates; -import com.aventstack.extentreports.ReportStatusStats; import com.aventstack.extentreports.Status; -import com.aventstack.extentreports.SystemAttributeContext; -import com.aventstack.extentreports.TestAttributeTestContextProvider; -import com.aventstack.extentreports.externalconfig.model.Config; -import com.aventstack.extentreports.mediastorage.LocalMediaStorageHandler; -import com.aventstack.extentreports.mediastorage.MediaStorage; -import com.aventstack.extentreports.model.Author; -import com.aventstack.extentreports.model.Category; -import com.aventstack.extentreports.model.Device; import com.aventstack.extentreports.model.Log; -import com.aventstack.extentreports.model.Media; import com.aventstack.extentreports.model.ScreenCapture; -import com.aventstack.extentreports.model.Screencast; import com.aventstack.extentreports.model.Test; -import com.aventstack.extentreports.reporter.configuration.BasicFileConfiguration; +import com.aventstack.extentreports.model.service.LogService; +import com.aventstack.extentreports.model.service.TestService; +import com.aventstack.extentreports.templating.FreemarkerTemplate; +import com.aventstack.extentreports.templating.TemplateConfig; import com.aventstack.extentreports.utils.FileUtil; -import com.aventstack.extentreports.utils.Writer; import com.aventstack.extentreports.viewdefs.Icon; import com.aventstack.extentreports.viewdefs.MaterialIcon; import com.aventstack.extentreports.viewdefs.TWBSColor; @@ -49,274 +34,145 @@ * A base class for all reporter types that generate an output file * */ -public abstract class BasicFileReporter - extends AbstractReporter { +public abstract class BasicFileReporter extends ConfigurableReporter { private static final Logger logger = Logger.getLogger(BasicFileReporter.class.getName()); - private static final String DEFAULT_MEDIA_SAVE_PROPERTY_NAME = "autoCreateRelativePathMedia"; private static final String TEMPLATE_LOCATION = "view/"; - + private static String encoding = "UTF-8"; - - private String source; - protected String filePath; - protected String destination; - protected Map templateMap; - - private BasicFileConfiguration userConfig; - private MediaStorage media; - private List testList; - private List testRunnerLogs; - private ExceptionTestContextImpl exceptionContext; - private TestAttributeTestContextProvider categoryContext; - private TestAttributeTestContextProvider authorContext; - private TestAttributeTestContextProvider deviceContext; - private SystemAttributeContext systemAttributeContext; - private ReportStatusStats stats; - private List statusList; - protected BasicFileReporter(String path) { - this.filePath = path; - } - - protected BasicFileReporter(File path) { - this.filePath = path.getAbsolutePath(); - } - - protected void setFilePath(String filePath) { - this.filePath = filePath; - } - - public String getFilePath() { - return filePath; - } - - public File getFileFile() { - return new File(filePath); - } - - protected void init(String[] configFilePath, BasicFileConfiguration userConfig) { - this.userConfig = userConfig; - - // Required to parse the start and end times in the HTML report. - Locale.setDefault(Locale.ENGLISH); - loadDefaultConfig(configFilePath); - - File f = new File(getFilePath()); - File parentFile; - if (f.isDirectory() || FileUtil.getExtension(f).isEmpty()) { - parentFile = f; - } else { - parentFile = f.getParentFile(); - } - destination = parentFile == null ? "" : parentFile.getAbsolutePath() + "/"; - File destinationFile = new File(destination); - if (!destinationFile.exists()) { - destinationFile.mkdirs(); - } - } - - protected void loadUserConfig() { - for (Map.Entry entry : userConfig.getConfigMap().entrySet()) { - if (entry.getValue() != null) { - Config c = new Config(); - c.setKey(entry.getKey()); - c.setValue(entry.getValue()); - configContext.setConfig(c); - } - } - } - - private void loadDefaultConfig(String[] configFilePath) { - ClassLoader loader = getClass().getClassLoader(); - Arrays.stream(configFilePath) - .map(x -> loader.getResourceAsStream(x)) - .filter(x -> x != null) - .findFirst() - .ifPresent(x -> loadConfig(x)); - } - - @Override - public void start() { - if (templateMap != null) { - return; - } - - templateMap = new HashMap<>(); - templateMap.put("report", this); - templateMap.put("MaterialIcon", new MaterialIcon()); - templateMap.put("Icon", new Icon()); - templateMap.put("TWBSColor", new TWBSColor()); - - BeansWrapperBuilder builder = new BeansWrapperBuilder(Configuration.VERSION_2_3_23); - BeansWrapper beansWrapper = builder.build(); - - try { - TemplateHashModel fieldTypeModel = (TemplateHashModel)beansWrapper.getEnumModels() - .get(Status.class.getName()); - templateMap.put("Status", fieldTypeModel); - } catch (TemplateModelException e) { - logger.log(Level.SEVERE, "", e); - } - } - - @Override - public synchronized void flush(ReportAggregates reportAggregates) { - super.flush(reportAggregates); - this.authorContext = reportAggregates.getAuthorContext(); - this.categoryContext = reportAggregates.getCategoryContext(); - this.deviceContext = reportAggregates.getDeviceContext(); - this.exceptionContext = reportAggregates.getExceptionContext(); - this.stats = reportAggregates.getReportStatusStats(); - this.systemAttributeContext = reportAggregates.getSystemAttributeContext(); - this.testList = reportAggregates.getTestList(); - this.testRunnerLogs = reportAggregates.getTestRunnerLogs(); - this.statusList = reportAggregates.getStatusList(); - } - - public List getTestList() { - return testList; + private String filePath; + private String destination; + private Map templateModel; + private String source; + private Configuration freemarkerConfig; + + protected BasicFileReporter(File f) { + this.filePath = f.getAbsolutePath(); + File parentFile; + if (f.isDirectory() || FileUtil.getExtension(f).isEmpty()) { + parentFile = f; + } else { + parentFile = f.getParentFile(); + } + destination = parentFile == null ? "" : parentFile.getAbsolutePath() + "/"; + File destinationFile = new File(destination); + if (!destinationFile.exists()) { + destinationFile.mkdirs(); + } } - - public List getTestRunnerLogs() { - return testRunnerLogs; - } - - public TestAttributeTestContextProvider getCategoryContextInfo() { - return categoryContext; - } - - public TestAttributeTestContextProvider getAuthorContextInfo() { - return authorContext; - } - public TestAttributeTestContextProvider getDeviceContextInfo() { - return deviceContext; + protected BasicFileReporter(String path) { + this(new File(path)); } - - public ExceptionTestContextImpl getExceptionContextInfo() { - return exceptionContext; - } - public SystemAttributeContext getSystemAttributeContext() { - return systemAttributeContext; - } - - public ReportStatusStats getReportStatusStats() { - return stats; - } - - @Override - public List getStatusList() { - return statusList; + protected void setFilePath(String filePath) { + this.filePath = filePath; } - - @Override - public void onTestStarted(Test test) { } - @Override - public void onTestRemoved(Test test) { } + public String getFilePath() { + return filePath; + } - @Override - public void onNodeStarted(Test node) { } + public File getFileFile() { + return new File(filePath); + } + + public String getDestinationPath() { + return destination; + } @Override - public void onLogAdded(Test test, Log log) { } + public void start() { + if (templateModel != null) { + return; + } + + templateModel = new HashMap<>(); + templateModel.put("report", this); + templateModel.put("MaterialIcon", new MaterialIcon()); + templateModel.put("Icon", new Icon()); + templateModel.put("TWBSColor", new TWBSColor()); + + BeansWrapperBuilder builder = new BeansWrapperBuilder(Configuration.VERSION_2_3_29); + BeansWrapper beansWrapper = builder.build(); + + try { + TemplateHashModel fieldTypeModel = (TemplateHashModel) beansWrapper.getEnumModels() + .get(Status.class.getName()); + templateModel.put("Status", fieldTypeModel); + fieldTypeModel = (TemplateHashModel) beansWrapper.getStaticModels() + .get(TestService.class.getName()); + templateModel.put("TestService", fieldTypeModel); + fieldTypeModel = (TemplateHashModel) beansWrapper.getStaticModels() + .get(LogService.class.getName()); + templateModel.put("LogService", fieldTypeModel); + } catch (TemplateModelException e) { + logger.log(Level.SEVERE, "", e); + } + } @Override - public void onCategoryAssigned(Test test, Category category) { } + public synchronized void flush(ReportAggregates reportAggregates) { + super.flush(reportAggregates); + } @Override - public void onAuthorAssigned(Test test, Author author) { } + public void onScreenCaptureAdded(Test test, ScreenCapture screenCapture) throws IOException { + onScreenCaptureAdded(screenCapture); + } @Override - public void onDeviceAssigned(Test test, Device device) { } - - @Override - public void onScreenCaptureAdded(Test test, ScreenCapture screenCapture) throws IOException { - mediaExists(screenCapture); - autoCreateRelativePathMedia(screenCapture); - } - - @Override - public void onScreenCaptureAdded(Log log, ScreenCapture screenCapture) throws IOException { - mediaExists(screenCapture); - autoCreateRelativePathMedia(screenCapture); - } - - private void mediaExists(Media m) { - if (m.getPath() != null && !new File(m.getPath()).exists()) { } - } - - private void autoCreateRelativePathMedia(ScreenCapture screenCapture) throws IOException { - // if user has not specific a configuration, exit - if (userConfig == null || screenCapture.isBase64()) - return; - - String autoCreateRelativePathMedia = userConfig.getConfigMap().get(DEFAULT_MEDIA_SAVE_PROPERTY_NAME); - // check always so user has the option to disable this setting at anytime - if (autoCreateRelativePathMedia != null && Boolean.valueOf(autoCreateRelativePathMedia)) { - if (media == null) { - media = new LocalMediaStorageHandler(); - media.init(destination); - } - media.storeMedia(screenCapture); - } - } - - @Override - public void stop() { } + public void onScreenCaptureAdded(Log log, ScreenCapture screenCapture) throws IOException { + onScreenCaptureAdded(screenCapture); + } - @Override - public Date getStartTime() { - return super.getStartTime(); - } - - @Override - public Date getEndTime() { - return super.getEndTime(); - } + private void onScreenCaptureAdded(ScreenCapture screenCapture) throws IOException { + if (getConfigurationStore() == null) + return; + String autoCreateRelativePathMedia = (String) getConfigurationStore() + .getConfig(DEFAULT_MEDIA_SAVE_PROPERTY_NAME); + if (autoCreateRelativePathMedia != null && Boolean.valueOf(autoCreateRelativePathMedia)) { + autoCreateRelativePathMedia(screenCapture, Boolean.valueOf(autoCreateRelativePathMedia), destination); + } + } - @Override - public void onScreencastAdded(Test test, Screencast screencast) throws IOException { } - public boolean containsStatus(String status) { Status s = Status.valueOf(status.toUpperCase()); return containsStatus(s); } - + public boolean containsStatus(Status status) { - return getStatusList() != null && !getStatusList().isEmpty() && getStatusList().contains(status); - } - + return getStatusCollection() != null && getStatusCollection().contains(status); + } + protected void processTemplate(Template template, File outputFile) throws TemplateException, IOException { - StringWriter out = new StringWriter(); - template.process(templateMap, out); - source = out.toString(); - Writer.getInstance().write(outputFile, source); - out.close(); - } - - protected String getSource() { + FreemarkerTemplate freemarkerTemplate = new FreemarkerTemplate(getFreemarkerConfig()); + freemarkerTemplate.writeTemplate(template, templateModel, outputFile); + } + + protected String getSource() { return source; } - + protected Configuration getFreemarkerConfig() { - Configuration cfg = new Configuration(Configuration.VERSION_2_3_22); - cfg.setClassForTemplateLoading(ExtentReports.class, TEMPLATE_LOCATION); - cfg.setDefaultEncoding(encoding); - return cfg; - } - - protected Boolean enforceOfflineMode() { - if (configContext.containsKey("enableOfflineMode")) { - String offlineMode = String.valueOf(configContext.getValue("enableOfflineMode")); - if (!configContext.containsKey("offlineDirectory") && offlineMode.equals("true")) { - return true; - } - } - return false; - } + if (freemarkerConfig == null) { + TemplateConfig freemarkerConfig = new TemplateConfig(); + this.freemarkerConfig = freemarkerConfig.getFreemarkerConfig(ExtentReports.class, TEMPLATE_LOCATION, + encoding); + } + return freemarkerConfig; + } + + protected Boolean enforceOfflineMode() { + if (getConfigurationStore().containsConfig("enableOfflineMode")) { + String offlineMode = String.valueOf(getConfigurationStore().containsConfig("enableOfflineMode")); + if (!getConfigurationStore().containsConfig("offlineDirectory") && offlineMode.equals("true")) { + return true; + } + } + return false; + } -} +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/reporter/ConfigurableReporter.java b/src/main/java/com/aventstack/extentreports/reporter/ConfigurableReporter.java index 1f4359b..e179883 100644 --- a/src/main/java/com/aventstack/extentreports/reporter/ConfigurableReporter.java +++ b/src/main/java/com/aventstack/extentreports/reporter/ConfigurableReporter.java @@ -5,118 +5,134 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.util.Arrays; +import java.util.Map; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; -import com.aventstack.extentreports.ExtentReporter; -import com.aventstack.extentreports.externalconfig.ConfigLoader; -import com.aventstack.extentreports.externalconfig.model.Config; -import com.aventstack.extentreports.externalconfig.model.ConfigMap; +import com.aventstack.extentreports.configuration.ConfigurationBuilder; +import com.aventstack.extentreports.configuration.ConfigurationStore; +import com.aventstack.extentreports.reporter.configuration.BasicConfiguration; -/** - * A base class to provide bootstrapping for loading custom configuration for the Reporter - * using XML or Properties file - * - */ -public abstract class ConfigurableReporter - implements ExtentReporter { +public abstract class ConfigurableReporter extends AbstractReporter { private static final Logger logger = Logger.getLogger(ConfigurableReporter.class.getName()); - /** - * A key-value pair holding information from default and the - * user-provided configuration - */ - protected ConfigMap configContext = new ConfigMap(); + private BasicConfiguration basicConfiguration; /** * Loads configuration from an XML file * * @param filePath Configuration file path - * @param silent Load configuration silently, no errors are thrown if the configuration file is not present + * @param silent Load configuration silently, no errors are thrown if the + * configuration file is not present */ public void loadXMLConfig(String filePath, Boolean silent) { - loadXMLConfig(new File(filePath), silent); - } - + loadXMLConfig(new File(filePath), silent); + } + /** * Loads configuration from an XML file * * @param filePath configuration file path */ - public void loadXMLConfig(String filePath) { - loadXMLConfig(filePath, false); - } - + public void loadXMLConfig(String filePath) { + loadXMLConfig(filePath, false); + } + /** * Loads configuration from an XML file * * @param file configuration {@link File} + */ + public void loadXMLConfig(File file) { + loadXMLConfig(file, false); + } + + /** + * Loads configuration from an XML file + * + * @param file configuration {@link File} * @param silent If silent, no errors will be thrown */ public void loadXMLConfig(File file, Boolean silent) { - ConfigLoader configLoader = new ConfigLoader(file, silent); - ConfigMap config = configLoader.getConfigurationHash(); - - if (config != null) - config.getConfigList().forEach(configContext::setConfig); - } - - /** - * Loads configuration from a Properties file - * - * @param properties a {@link Properties} object - */ - public void loadConfig(Properties properties) { - properties.entrySet().forEach(o -> { - Config c = new Config(); - c.setKey(o.getKey().toString()); - c.setValue(o.getValue()); - configContext.setConfig(c); - }); - } - - /** - * Loads configuration from an {@link InputStream} which is a - * {@link Properties} file - * - * @param stream an {@link InputStream} - */ + ConfigurationBuilder builder = new ConfigurationBuilder(file, silent); + ConfigurationStore store = builder.getConfigurationStore(); + basicConfiguration.getConfigurationStore().extendConfig(store); + } + + /** + * Loads configuration from a Properties file + * + * @param properties a {@link Properties} object + */ + public void loadConfig(Properties properties) { + properties.entrySet().forEach(o -> { + if (o.getKey() != null) { + basicConfiguration.getConfigurationStore().storeConfig(o.getKey().toString(), o.getValue()); + } + }); + } + + /** + * Loads configuration from an {@link InputStream} which is a {@link Properties} + * file + * + * @param stream an {@link InputStream} + */ public void loadConfig(InputStream stream) { - Properties properties = new Properties(); - - try { - properties.load(stream); - loadConfig(properties); - } catch (FileNotFoundException e) { - logger.log(Level.SEVERE, "Default Properties file not found", e); - } catch (IOException e) { - logger.log(Level.SEVERE, "Unable to load properties file", e); - } - } - + Properties properties = new Properties(); + + try { + properties.load(stream); + loadConfig(properties); + } catch (FileNotFoundException e) { + logger.log(Level.SEVERE, "Default Properties file not found", e); + } catch (IOException e) { + logger.log(Level.SEVERE, "Unable to load properties file", e); + } + } + /** - * Loads configuration from an path which is a {@link Properties} file - * - * @param filePath Properties file path - */ - public void loadConfig(String filePath) { - try { - InputStream is = new FileInputStream(filePath); - loadConfig(is); - } catch (FileNotFoundException e) { - logger.log(Level.SEVERE, "Default Properties file not found", e); - } - } - + * Loads configuration from an path which is a {@link Properties} file + * + * @param filePath Properties file path + */ + public void loadConfig(String filePath) { + try { + InputStream is = new FileInputStream(filePath); + loadConfig(is); + } catch (FileNotFoundException e) { + logger.log(Level.SEVERE, "Default Properties file not found", e); + } + } + + protected void loadUserConfig() { + for (Map.Entry entry : getConfigurationStore().getStore().entrySet()) { + getConfigurationStore().storeConfig(entry.getKey(), entry.getValue()); + } + } + + protected void init(String[] configFilePath, BasicConfiguration userConfig) { + basicConfiguration = userConfig; + loadInternalReporterConfiguration(configFilePath); + } + + protected void loadInternalReporterConfiguration(String[] configFilePath) { + ClassLoader loader = getClass().getClassLoader(); + Arrays.stream(configFilePath).map(x -> loader.getResourceAsStream(x)).filter(x -> x != null).findFirst() + .ifPresent(x -> loadConfig(x)); + } + /** * Returns the current configuration (default and user-defined) * - * @return a {@link ConfigMap} containing key-value pairs of config entries + * @return a {@link ConfigurationStore} containing key-value pairs of config + * entries */ - public ConfigMap getConfigContext() { - return configContext; - } - -} + public ConfigurationStore getConfigurationStore() { + return basicConfiguration == null ? null : basicConfiguration.getConfigurationStore(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/reporter/impl/ConsoleLogger.java b/src/main/java/com/aventstack/extentreports/reporter/ConsoleLogger.java similarity index 90% rename from src/main/java/com/aventstack/extentreports/reporter/impl/ConsoleLogger.java rename to src/main/java/com/aventstack/extentreports/reporter/ConsoleLogger.java index 950cba5..72f954f 100644 --- a/src/main/java/com/aventstack/extentreports/reporter/impl/ConsoleLogger.java +++ b/src/main/java/com/aventstack/extentreports/reporter/ConsoleLogger.java @@ -1,4 +1,4 @@ -package com.aventstack.extentreports.reporter.impl; +package com.aventstack.extentreports.reporter; import java.io.IOException; import java.util.logging.Level; @@ -9,9 +9,7 @@ import com.aventstack.extentreports.model.Device; import com.aventstack.extentreports.model.Log; import com.aventstack.extentreports.model.ScreenCapture; -import com.aventstack.extentreports.model.Screencast; import com.aventstack.extentreports.model.Test; -import com.aventstack.extentreports.reporter.AbstractReporter; public class ConsoleLogger extends AbstractReporter { @@ -71,9 +69,6 @@ public void onScreenCaptureAdded(Log log, ScreenCapture screenCapture) { LOGGER.log(Level.INFO, "A new screencapture for log " + log.getDetails() + " created"); } - @Override - public void onScreencastAdded(Test test, Screencast screencast) { } - @Override public String getReporterName() { return REPORTER_NAME; diff --git a/src/main/java/com/aventstack/extentreports/reporter/ExtentEmailReporter.java b/src/main/java/com/aventstack/extentreports/reporter/ExtentEmailReporter.java index c36489a..c785a06 100644 --- a/src/main/java/com/aventstack/extentreports/reporter/ExtentEmailReporter.java +++ b/src/main/java/com/aventstack/extentreports/reporter/ExtentEmailReporter.java @@ -6,26 +6,24 @@ import com.aventstack.extentreports.SourceProvider; /** - * The ExtentHtmlReporter creates a rich standalone HTML file. It allows several configuration options - * via the config() method. + * The ExtentHtmlReporter creates a rich standalone HTML file. It allows several + * configuration options via the config() method. */ -public class ExtentEmailReporter - extends BasicFileReporter - implements SourceProvider { - - private static final String REPORTER_NAME = "email"; - - public ExtentEmailReporter(String path) { - super(path); - } - - public ExtentEmailReporter(File file) { - super(file); - } - - @Override - public synchronized void flush(ReportAggregates reportAggregates) { - } +public class ExtentEmailReporter extends BasicFileReporter implements SourceProvider { + + private static final String REPORTER_NAME = "email"; + + public ExtentEmailReporter(String path) { + super(path); + } + + public ExtentEmailReporter(File file) { + super(file); + } + + @Override + public synchronized void flush(ReportAggregates reportAggregates) { + } @Override public String getReporterName() { diff --git a/src/main/java/com/aventstack/extentreports/reporter/ExtentHtmlReporter.java b/src/main/java/com/aventstack/extentreports/reporter/ExtentHtmlReporter.java index 8306918..11c7d40 100644 --- a/src/main/java/com/aventstack/extentreports/reporter/ExtentHtmlReporter.java +++ b/src/main/java/com/aventstack/extentreports/reporter/ExtentHtmlReporter.java @@ -12,53 +12,56 @@ import freemarker.template.TemplateException; /** - * The ExtentHtmlReporter creates a rich standalone HTML file. It allows several - * configuration options via the config() method. + * The ExtentSparkReporter creates a rich standalone spark file. It allows + * several configuration options via the config() method. */ public class ExtentHtmlReporter extends BasicFileReporter { - private static final Logger logger = Logger.getLogger(ExtentHtmlReporter.class.getName()); - private static final String REPORTER_NAME = "html"; + private static final Logger logger = Logger.getLogger(ExtentHtmlReporter.class.getName()); + private static final String REPORTER_NAME = "html"; private static final String TEMPLATE_NAME = "v3html/v3-html-index.ftl"; private static final String[] DEFAULT_CONFIG_FILE_PATH = new String[] { "html.properties", "src/main/resources/html.properties" }; - private ExtentHtmlReporterConfiguration userConfig = new ExtentHtmlReporterConfiguration(this); + private ExtentHtmlReporterConfiguration externalUserConfiguration = new ExtentHtmlReporterConfiguration(this); - public ExtentHtmlReporter(String path) { - super(path); - init(DEFAULT_CONFIG_FILE_PATH, config()); - } + public ExtentHtmlReporter(String path) { + super(path); + init(DEFAULT_CONFIG_FILE_PATH, config()); + } - public ExtentHtmlReporter(File file) { - super(file); - init(DEFAULT_CONFIG_FILE_PATH, config()); - } + public ExtentHtmlReporter(File file) { + super(file); + init(DEFAULT_CONFIG_FILE_PATH, config()); + } - public ExtentHtmlReporterConfiguration config() { - return userConfig; - } + public ExtentHtmlReporterConfiguration config() { + return externalUserConfiguration; + } - @Override - public synchronized void flush(ReportAggregates reportAggregates) { - super.flush(reportAggregates); + @Override + public synchronized void flush(ReportAggregates reportAggregates) { + super.flush(reportAggregates); + if (getTestList().isEmpty()) { + return; + } + if (enforceOfflineMode()) { + externalUserConfiguration.enableOfflineMode(true); + } - if (getTestList().isEmpty()) - return; + loadUserConfig(); - loadUserConfig(); + try { + Template template = getFreemarkerConfig().getTemplate(TEMPLATE_NAME); + processTemplate(template, new File(getFilePath())); + } catch (IOException | TemplateException e) { + logger.log(Level.SEVERE, "An exception occurred", e); + } + } - try { - Template template = getFreemarkerConfig().getTemplate(TEMPLATE_NAME); - processTemplate(template, new File(filePath)); - } catch (IOException | TemplateException e) { - logger.log(Level.SEVERE, "An exception occurred", e); - } - } + @Override + public String getReporterName() { + return REPORTER_NAME; + } - @Override - public String getReporterName() { - return REPORTER_NAME; - } - -} +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/reporter/ExtentKlovReporter.java b/src/main/java/com/aventstack/extentreports/reporter/ExtentKlovReporter.java index b48eb3d..95dbb03 100644 --- a/src/main/java/com/aventstack/extentreports/reporter/ExtentKlovReporter.java +++ b/src/main/java/com/aventstack/extentreports/reporter/ExtentKlovReporter.java @@ -20,11 +20,9 @@ import com.aventstack.extentreports.ReportAggregates; import com.aventstack.extentreports.ReportStatusStats; import com.aventstack.extentreports.Status; -import com.aventstack.extentreports.SystemAttributeContext; -import com.aventstack.extentreports.TestAttributeTestContextProvider; -import com.aventstack.extentreports.externalconfig.model.Config; import com.aventstack.extentreports.mediastorage.KlovMediaStorageHandler; import com.aventstack.extentreports.mediastorage.model.KlovMedia; +import com.aventstack.extentreports.model.Attribute; import com.aventstack.extentreports.model.Author; import com.aventstack.extentreports.model.BasicMongoReportElement; import com.aventstack.extentreports.model.Category; @@ -32,27 +30,28 @@ import com.aventstack.extentreports.model.ExceptionInfo; import com.aventstack.extentreports.model.Log; import com.aventstack.extentreports.model.ScreenCapture; -import com.aventstack.extentreports.model.Screencast; import com.aventstack.extentreports.model.SystemAttribute; import com.aventstack.extentreports.model.Test; -import com.aventstack.extentreports.model.TestAttribute; -import com.aventstack.extentreports.utils.IntUtils; +import com.aventstack.extentreports.model.context.SystemAttributeContext; +import com.aventstack.extentreports.model.context.TestAttributeTestContextStore; +import com.aventstack.extentreports.model.service.LogService; +import com.aventstack.extentreports.model.service.TestService; +import com.aventstack.extentreports.utils.IntUtil; import com.aventstack.extentreports.utils.MongoUtil; import com.mongodb.MongoClient; import com.mongodb.MongoClientOptions; import com.mongodb.MongoClientURI; -import com.mongodb.MongoCredential; import com.mongodb.ServerAddress; import com.mongodb.client.FindIterable; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; /** - * ExtentKlovReporter is a NoSQL database reporter (MongoDB), which updates information in - * the database which is then used by the ExtentX server to display in-depth analysis. + * ExtentKlovReporter is a NoSQL database reporter (MongoDB), which updates + * information in the database which is then used by the ExtentX server to + * display in-depth analysis. */ -public class ExtentKlovReporter - extends AbstractReporter { +public class ExtentKlovReporter extends ConfigurableReporter { private static final String DEFAULT_PROJECT_NAME_PROP = "klov.project.name"; private static final String DEFAULT_REPORT_NAME_PROP = "klov.report.name"; @@ -63,649 +62,575 @@ public class ExtentKlovReporter private static final String DEFAULT_KLOV_PORT_PROP = "klov.port"; private static final String REPORTER_NAME = "klov"; private static final String DB_NAME = "klov"; - private static final String DEFAULT_PROJECT_NAME = "Default"; - - private String url; - - private List testList; - private ReportStatusStats stats; - private SystemAttributeContext systemAttributeContext; - private TestAttributeTestContextProvider categoryContext; - private TestAttributeTestContextProvider authorContext; - private TestAttributeTestContextProvider deviceContext; - private Map categoryNameObjectIdCollection = new HashMap<>(); - private Map authorNameObjectIdCollection = new HashMap<>(); - private Map deviceNameObjectIdCollection = new HashMap<>(); - private Map exceptionNameObjectIdCollection = new HashMap<>(); - - private ObjectId reportId; - private String reportName; - private ObjectId projectId; - private String projectName; - - private MongoClient mongoClient; - - private MongoCollection projectCollection; - private MongoCollection reportCollection; - private MongoCollection testCollection; - private MongoCollection logCollection; - private MongoCollection exceptionCollection; - private MongoCollection mediaCollection; - private MongoCollection categoryCollection; - private MongoCollection authorCollection; - private MongoCollection deviceCollection; - private MongoCollection environmentCollection; - - static { - /* use mongodb reporting for only critical/severe events */ - Logger mongoLogger = Logger.getLogger("org.mongodb.driver"); - mongoLogger.setLevel(Level.SEVERE); - } - - /** - * Initializes the KlovReporter - */ - public ExtentKlovReporter() { } - - /** - * Initializes the KlovReporter with project and report names - * - * @param projectName Name of the project - * @param reportName Name of the report - */ - public ExtentKlovReporter(String projectName, String reportName) { - this.projectName = projectName; - this.reportName = reportName; - } - - /** - * Sets the project name - * - * @param projectName Name of the project - */ - public void setProjectName(String projectName) { - this.projectName = projectName; - } - - /** - * Sets the report name - * - * @param reportName Name of the report - */ - public void setReportName(String reportName) { - this.reportName = reportName; - } - - /** - * Initialize Mongo DB connection with host and default port: 27017 - * - * @param host host name - * @return a {@link ExtentKlovReporter} object - */ - public ExtentKlovReporter initMongoDbConnection(String host) { - mongoClient = new MongoClient(host, 27017); - return this; - } - - /** - * Initialize Mongo DB connection with host and {@link MongoClientOptions} - * - * @param host host name - * @param options {@link MongoClientOptions} options - * @return a {@link ExtentKlovReporter} object - */ - public ExtentKlovReporter initMongoDbConnection(String host, MongoClientOptions options) { - mongoClient = new MongoClient(host, options); - return this; - } - - /** - * Initialize Mongo DB connection with host and post - * - * @param host host name - * @param port port number - * @return a {@link ExtentKlovReporter} object - */ - public ExtentKlovReporter initMongoDbConnection(String host, int port) { - mongoClient = new MongoClient(host, port); - return this; - } - - /** - * Initialize Mongo DB connection with a {@link MongoClientURI} - * - * @param uri {@link MongoClientURI} uri - * @return a {@link ExtentKlovReporter} object - */ - public ExtentKlovReporter initMongoDbConnection(MongoClientURI uri) { - mongoClient = new MongoClient(uri); - return this; - } - - /** - * Initializes the Mongo DB connection with {@link ServerAddress} - * - * @param addr {@link ServerAddress} server address - * @return a {@link ExtentKlovReporter} object - */ - public ExtentKlovReporter initMongoDbConnection(ServerAddress addr) { - mongoClient = new MongoClient(addr); - return this; - } - - /** - * Initializes the Mongo DB connection with a list of {@link ServerAddress} - * addresses - * - * @param seeds A list of {@link ServerAddress} server addresses - * @return a {@link ExtentKlovReporter} object - */ - public ExtentKlovReporter initMongoDbConnection(List seeds) { - mongoClient = new MongoClient(seeds); - return this; - } - - /** - * Initializes the Mongo DB connection with a list of {@link ServerAddress} - * and {@link MongoCredential} - * - * @param seeds A list of {@link ServerAddress} server addresses - * @param credentialsList A list of {@link MongoCredential} credentials - * @return a {@link ExtentKlovReporter} object - */ - public ExtentKlovReporter initMongoDbConnection(List seeds, List credentialsList) { - mongoClient = new MongoClient(seeds, credentialsList); - return this; - } - - /** - * Initializes the Mongo DB connection with a list of {@link ServerAddress}, - * {@link MongoCredential} and {@link MongoClientOptions} - * - * @param seeds A list of {@link ServerAddress} server addresses - * @param credentialsList A list of {@link MongoCredential} credentials - * @param options {@link MongoClientOptions} options - * @return a {@link ExtentKlovReporter} object - */ - public ExtentKlovReporter initMongoDbConnection(List seeds, List credentialsList, MongoClientOptions options) { - mongoClient = new MongoClient(seeds, credentialsList, options); - return this; - } - - /** - * Initializes the Mongo DB connection with a list of {@link ServerAddress} - * and {@link MongoClientOptions} - * - * @param seeds A list of {@link ServerAddress} server addresses - * @param options {@link MongoClientOptions} options - * @return a {@link ExtentKlovReporter} object - */ - public ExtentKlovReporter initMongoDbConnection(List seeds, MongoClientOptions options) { - mongoClient = new MongoClient(seeds, options); - return this; - } - - /** - * Initializes the Mongo DB connection with {@link ServerAddress} and a list of - * {@link MongoCredential} credentials - * - * @param addr {@link ServerAddress} server address - * @param credentialsList A list of {@link MongoCredential} credentials - * @return a {@link ExtentKlovReporter} object - */ - public ExtentKlovReporter initMongoDbConnection(ServerAddress addr, List credentialsList) { - mongoClient = new MongoClient(addr, credentialsList); - return this; - } - - /** - * Initializes the Mongo DB connection with a list of {@link ServerAddress}, - * {@link MongoCredential} and {@link MongoClientOptions} - * - * @param addr A list of {@link ServerAddress} server addresses - * @param credentialsList A list of {@link MongoCredential} credentials - * @param options {@link MongoClientOptions} options - * @return a {@link ExtentKlovReporter} object - */ - public ExtentKlovReporter initMongoDbConnection(ServerAddress addr, List credentialsList, MongoClientOptions options) { - mongoClient = new MongoClient(addr, credentialsList, options); - return this; - } - - /** - * Initializes the Mongo DB connection with a {@link ServerAddress} and - * {@link MongoClientOptions} - * - * @param addr A list of {@link ServerAddress} server addresses - * @param options {@link MongoClientOptions} options - * @return a {@link ExtentKlovReporter} object - */ - public ExtentKlovReporter initMongoDbConnection(ServerAddress addr, MongoClientOptions options) { - mongoClient = new MongoClient(addr, options); - return this; - } - - /** - * Initializes the Mongo DB connection with a connection url - * - * @param url Url string - * @return a {@link ExtentKlovReporter} object - */ - public ExtentKlovReporter initKlovServerConnection(String url) { - this.url = url; - return this; - } - - public void loadInitializationParams(String propertiesPath) throws FileNotFoundException { - File f = new File(propertiesPath); - InputStream stream = new FileInputStream(f); - loadConfig(stream); - loadInitializationParams(); - } - - public void loadInitializationParams(Properties props) { - loadConfig(props); - loadInitializationParams(); - } - - private void loadInitializationParams() { - List configList = getConfigContext().getConfigList(); - - String mongoUri = getConfigValue(configList, DEFAULT_MONGODB_URI_PROP); - if (mongoUri == null || mongoUri.isEmpty()) { - String mongoHost = getConfigValue(configList, DEFAULT_MONGODB_HOST_PROP); - String mongoPort = getConfigValue(configList, DEFAULT_MONGODB_PORT_PROP); - int mongoPortInt = IntUtils.tryParseInt(mongoPort) == true ? Integer.valueOf(mongoPort) : -1; - if (mongoHost != null && mongoPortInt != -1) { - initMongoDbConnection(mongoHost, mongoPortInt); - } else if (mongoHost != null) { - initMongoDbConnection(mongoHost); - } - } else { - initMongoDbConnection(new MongoClientURI(mongoUri)); - } - - String projectName = System.getProperty(DEFAULT_PROJECT_NAME_PROP); - projectName = projectName == null || projectName.isEmpty() ? getConfigValue(configList, DEFAULT_PROJECT_NAME_PROP) : projectName; - this.projectName = projectName == null || projectName.isEmpty() ? this.projectName : projectName; - - String reportName = System.getProperty(DEFAULT_REPORT_NAME_PROP); - reportName = reportName == null || reportName.isEmpty() ? getConfigValue(configList, DEFAULT_REPORT_NAME_PROP) : reportName; - this.reportName = reportName == null || reportName.isEmpty() ? this.reportName : reportName; - - String klovHost = getConfigValue(configList, DEFAULT_KLOV_HOST_PROP); - String klovPort = getConfigValue(configList, DEFAULT_KLOV_PORT_PROP); + private static final String DEFAULT_PROJECT_NAME = "Default"; + + private String url; + private List testList; + private ReportStatusStats stats; + private SystemAttributeContext systemAttributeContext; + private TestAttributeTestContextStore categoryContext; + private TestAttributeTestContextStore authorContext; + private TestAttributeTestContextStore deviceContext; + private Map categoryNameObjectIdCollection = new HashMap<>(); + private Map authorNameObjectIdCollection = new HashMap<>(); + private Map deviceNameObjectIdCollection = new HashMap<>(); + private Map exceptionNameObjectIdCollection = new HashMap<>(); + private ObjectId reportId; + private String reportName; + private ObjectId projectId; + private String projectName; + private MongoClient mongoClient; + private MongoCollection projectCollection; + private MongoCollection reportCollection; + private MongoCollection testCollection; + private MongoCollection logCollection; + private MongoCollection exceptionCollection; + private MongoCollection mediaCollection; + private MongoCollection categoryCollection; + private MongoCollection authorCollection; + private MongoCollection deviceCollection; + private MongoCollection environmentCollection; + private KlovMediaStorageHandler mediaStorageHandler; + + static { + /* use mongodb reporting for only critical/severe events */ + Logger mongoLogger = Logger.getLogger("org.mongodb.driver"); + mongoLogger.setLevel(Level.SEVERE); + } + + /** + * Initializes the KlovReporter with the project name and default report name + * + *

+ * The reportName will be created using the current timestamp + * + * @param projectName Name of the project + * + */ + public ExtentKlovReporter(String projectName) { + this.projectName = projectName; + } + + /** + * Initializes the KlovReporter with project and report names + * + * @param projectName Name of the project + * @param reportName Name of the report + */ + public ExtentKlovReporter(String projectName, String reportName) { + this.projectName = projectName; + this.reportName = reportName; + } + + /** + * Sets the project name + * + * @param projectName Name of the project + * @return a {@link ExtentKlovReporter} object + */ + public ExtentKlovReporter setProjectName(String projectName) { + this.projectName = projectName; + return this; + } + + /** + * Sets the report name + * + * @param reportName Name of the report + * @return a {@link ExtentKlovReporter} object + */ + public ExtentKlovReporter setReportName(String reportName) { + this.reportName = reportName; + return this; + } + + /** + * Initialize Mongo DB connection with host and default port: 27017 + * + * @param host host name + * @return a {@link ExtentKlovReporter} object + */ + public ExtentKlovReporter initMongoDbConnection(String host) { + mongoClient = new MongoClient(host, 27017); + return this; + } + + /** + * Initialize Mongo DB connection with host and {@link MongoClientOptions} + * + * @param host host name + * @param options {@link MongoClientOptions} options + * @return a {@link ExtentKlovReporter} object + */ + public ExtentKlovReporter initMongoDbConnection(String host, MongoClientOptions options) { + mongoClient = new MongoClient(host, options); + return this; + } + + /** + * Initialize Mongo DB connection with host and post + * + * @param host host name + * @param port port number + * @return a {@link ExtentKlovReporter} object + */ + public ExtentKlovReporter initMongoDbConnection(String host, int port) { + mongoClient = new MongoClient(host, port); + return this; + } + + /** + * Initialize Mongo DB connection with a {@link MongoClientURI} + * + * @param uri {@link MongoClientURI} uri + * @return a {@link ExtentKlovReporter} object + */ + public ExtentKlovReporter initMongoDbConnection(MongoClientURI uri) { + mongoClient = new MongoClient(uri); + return this; + } + + /** + * Initializes the Mongo DB connection with {@link ServerAddress} + * + * @param addr {@link ServerAddress} server address + * @return a {@link ExtentKlovReporter} object + */ + public ExtentKlovReporter initMongoDbConnection(ServerAddress addr) { + mongoClient = new MongoClient(addr); + return this; + } + + /** + * Initializes the Mongo DB connection with a list of {@link ServerAddress} + * addresses + * + * @param seeds A list of {@link ServerAddress} server addresses + * @return a {@link ExtentKlovReporter} object + */ + public ExtentKlovReporter initMongoDbConnection(List seeds) { + mongoClient = new MongoClient(seeds); + return this; + } + + /** + * Initializes the Mongo DB connection with a list of {@link ServerAddress} and + * {@link MongoClientOptions} + * + * @param seeds A list of {@link ServerAddress} server addresses + * @param options {@link MongoClientOptions} options + * @return a {@link ExtentKlovReporter} object + */ + public ExtentKlovReporter initMongoDbConnection(List seeds, MongoClientOptions options) { + mongoClient = new MongoClient(seeds, options); + return this; + } + + /** + * Initializes the Mongo DB connection with a {@link ServerAddress} and + * {@link MongoClientOptions} + * + * @param addr A list of {@link ServerAddress} server addresses + * @param options {@link MongoClientOptions} options + * @return a {@link ExtentKlovReporter} object + */ + public ExtentKlovReporter initMongoDbConnection(ServerAddress addr, MongoClientOptions options) { + mongoClient = new MongoClient(addr, options); + return this; + } + + /** + * Initializes the Mongo DB connection with a connection url + * + * @param url Url string + * @return a {@link ExtentKlovReporter} object + */ + public ExtentKlovReporter initKlovServerConnection(String url) { + this.url = url; + return this; + } + + public void loadInitializationParams(String propertiesPath) throws FileNotFoundException { + File f = new File(propertiesPath); + InputStream stream = new FileInputStream(f); + loadConfig(stream); + loadInitializationParams(); + } + + public void loadInitializationParams(Properties props) { + loadConfig(props); + loadInitializationParams(); + } + + private void loadInitializationParams() { + String mongoUri = getConfigValue(DEFAULT_MONGODB_URI_PROP); + if (mongoUri == null || mongoUri.isEmpty()) { + String mongoHost = getConfigValue(DEFAULT_MONGODB_HOST_PROP); + String mongoPort = getConfigValue(DEFAULT_MONGODB_PORT_PROP); + int mongoPortInt = IntUtil.tryParseInt(mongoPort) == true ? Integer.valueOf(mongoPort) : -1; + if (mongoHost != null && mongoPortInt != -1) { + initMongoDbConnection(mongoHost, mongoPortInt); + } else if (mongoHost != null) { + initMongoDbConnection(mongoHost); + } + } else { + initMongoDbConnection(new MongoClientURI(mongoUri)); + } + + String projectName = System.getProperty(DEFAULT_PROJECT_NAME_PROP); + projectName = projectName == null || projectName.isEmpty() ? getConfigValue(DEFAULT_PROJECT_NAME_PROP) + : projectName; + this.projectName = projectName == null || projectName.isEmpty() ? this.projectName : projectName; + + String reportName = System.getProperty(DEFAULT_REPORT_NAME_PROP); + reportName = reportName == null || reportName.isEmpty() ? getConfigValue(DEFAULT_REPORT_NAME_PROP) : reportName; + this.reportName = reportName == null || reportName.isEmpty() ? this.reportName : reportName; + + String klovHost = getConfigValue(DEFAULT_KLOV_HOST_PROP); + String klovPort = getConfigValue(DEFAULT_KLOV_PORT_PROP); if (klovHost != null && klovPort != null) { String uri = klovHost + ":" + klovPort; initKlovServerConnection(uri); } else if (klovHost != null) { initKlovServerConnection(klovHost); - } else { } - } - - private String getConfigValue(List configList, String key) { - Config c = configList.stream() - .filter(x -> x.getKey().equalsIgnoreCase(key)) - .findFirst() - .get(); - if (c != null) - return String.valueOf(c.getValue()); - return null; - } - - @Override - public void start() { - MongoDatabase db = mongoClient.getDatabase(DB_NAME); - initCollections(db); - setupProject(); - } - - private void initCollections(MongoDatabase db) { - projectCollection = db.getCollection("project"); - reportCollection = db.getCollection("report"); - testCollection = db.getCollection("test"); - logCollection = db.getCollection("log"); - exceptionCollection = db.getCollection("exception"); - mediaCollection = db.getCollection("media"); - categoryCollection = db.getCollection("category"); - authorCollection = db.getCollection("author"); - deviceCollection = db.getCollection("device"); - environmentCollection = db.getCollection("environment"); - } - - private void setupProject() { - String projectName = this.projectName == null || this.projectName.isEmpty() - ? DEFAULT_PROJECT_NAME - : this.projectName; - - Document doc = new Document("name", projectName); - Document project = projectCollection.find(doc).first(); - - if (project != null) { - projectId = project.getObjectId("_id"); - } - else { - doc.append("createdAt", Calendar.getInstance().getTime()); - projectCollection.insertOne(doc); - projectId = MongoUtil.getId(doc); - } - - setupReport(projectName); - } - - private void setupReport(String projectName) { - String reportName = - this.reportName == null || this.reportName.isEmpty() - ? "Build " + Calendar.getInstance().getTimeInMillis() - : this.reportName; - - Document doc = new Document("name", reportName) - .append("startTime", getStartTime()) - .append("project", projectId) - .append("projectName", projectName); - - reportCollection.insertOne(doc); - reportId = MongoUtil.getId(doc); - } - - @Override - public void stop() { - mongoClient.close(); - } - - @Override - public synchronized void flush(ReportAggregates reportAggregates) { - setEndTime(Calendar.getInstance().getTime()); - this.testList = reportAggregates.getTestList(); - - if (testList == null || testList.isEmpty()) { - return; - } - - this.authorContext = reportAggregates.getAuthorContext(); - this.categoryContext = reportAggregates.getCategoryContext(); - this.deviceContext = reportAggregates.getDeviceContext(); - this.stats = reportAggregates.getReportStatusStats(); - this.systemAttributeContext = reportAggregates.getSystemAttributeContext(); - - Status buildStatus = reportAggregates.getStatus(); - - Document doc = new Document("endTime", getEndTime()) - .append("duration", getRunDuration()) - .append("status", String.valueOf(buildStatus)) - .append("parentLength", stats.getParentCount()) - .append("passParentLength", stats.getParentCountPass()) - .append("failParentLength", stats.getParentCountFail()) - .append("fatalParentLength", stats.getParentCountFatal()) - .append("errorParentLength", stats.getParentCountError()) - .append("warningParentLength", stats.getParentCountWarning()) - .append("skipParentLength", stats.getParentCountSkip()) - .append("exceptionsParentLength", stats.getChildCountExceptions()) - .append("childLength", stats.getChildCount()) - .append("passChildLength", stats.getChildCountPass()) - .append("failChildLength", stats.getChildCountFail()) - .append("fatalChildLength", stats.getChildCountFatal()) - .append("errorChildLength", stats.getChildCountError()) - .append("warningChildLength", stats.getChildCountWarning()) - .append("skipChildLength", stats.getChildCountSkip()) - .append("infoChildLength", stats.getChildCountInfo()) - .append("exceptionsChildLength", stats.getChildCountExceptions()) - .append("grandChildLength", stats.getGrandChildCount()) - .append("passGrandChildLength", stats.getGrandChildCountPass()) - .append("failGrandChildLength", stats.getGrandChildCountFail()) - .append("fatalGrandChildLength", stats.getGrandChildCountFatal()) - .append("errorGrandChildLength", stats.getGrandChildCountError()) - .append("warningGrandChildLength", stats.getGrandChildCountWarning()) - .append("skipGrandChildLength", stats.getGrandChildCountSkip()) - .append("exceptionsGrandChildLength", stats.getGrandChildCountExceptions()) - .append("analysisStrategy", String.valueOf(getAnalysisStrategy())); - - reportCollection.updateOne( - new Document("_id", reportId), - new Document("$set", doc)); - - insertUpdateSystemAttribute(); - } - - public List getCollectionValues(Map collection) { - if (collection == null || collection.isEmpty()) - return null; - return collection.entrySet() - .stream() - .map(Map.Entry::getValue) - .collect(Collectors.toList()); - } - - private void insertUpdateSystemAttribute() { - List systemAttrList = systemAttributeContext.getSystemAttributeList(); - Document doc; - - for (SystemAttribute attr : systemAttrList) { - doc = new Document("project", projectId) - .append("report", reportId) - .append("name", attr.getName()); - - Document envSingle = environmentCollection.find(doc).first(); - - if (envSingle == null) { - doc.append("value", attr.getValue()); - environmentCollection.insertOne(doc); - } else { - ObjectId id = envSingle.getObjectId("_id"); - doc = new Document("_id", id) - .append("value", attr.getValue()); - environmentCollection.updateOne( - new Document("_id", id), - new Document("$set", doc)); - } - } - } - - @Override - public void onTestStarted(Test test) { - onTestStartedHelper(test); - } - - @Override - public synchronized void onNodeStarted(Test node) { - onTestStartedHelper(node); - } - - private void onTestStartedHelper(Test test) { - Document doc = new Document("project", projectId) - .append("report", reportId) - .append("reportName", reportName) - .append("level", test.getLevel()) - .append("name", test.getName()) - .append("status", test.getStatus().toString()) - .append("description", test.getDescription()) - .append("startTime", test.getStartTime()) - .append("endTime", test.getEndTime()) - .append("bdd", test.isBehaviorDrivenType()) - .append("leaf", test.getNodeContext().size()==0) - .append("childNodesLength", test.getNodeContext().size()); - - if (test.isBehaviorDrivenType()) { - doc.append("bddType", test.getBehaviorDrivenType().getSimpleName()); - } - - if (test.getParent() != null) { - doc.append("parent", test.getParent().getObjectId()) - .append("parentName", test.getParent().getName()); - updateTestChildrenCount(test.getParent()); - updateTestDesc(test.getParent()); - } - - testCollection.insertOne(doc); - ObjectId testId = MongoUtil.getId(doc); - test.setObjectId(testId); - } - - private void updateTestDesc(Test test) { - Document doc = new Document("description", test.getDescription()); - testCollection.updateOne( - new Document("_id", test.getObjectId()), - new Document("$set", doc)); - } - - private void updateTestChildrenCount(Test test) { - Document doc = new Document("childNodesLength", test.getNodeContext().size()); - testCollection.updateOne( - new Document("_id", test.getObjectId()), - new Document("$set", doc)); - } - - @Override - public synchronized void onLogAdded(Test test, Log log) { - Document doc = new Document("test", test.getObjectId()) - .append("project", projectId) - .append("report", reportId) - .append("testName", test.getName()) - .append("sequence", log.getSequence()) - .append("status", log.getStatus().toString()) - .append("timestamp", log.getTimestamp()) - .append("details", log.getDetails()); - - if (log.hasScreenCapture() && log.getScreenCaptureContext().getFirst().isBase64()) { - doc.append("details", log.getDetails() + log.getScreenCaptureContext().getFirst().getSource()); - } - - logCollection.insertOne(doc); - - ObjectId logId = MongoUtil.getId(doc); - log.setObjectId(logId); - - // check for exceptions.. - if (test.hasException()) { - if (exceptionNameObjectIdCollection == null) - exceptionNameObjectIdCollection = new HashMap<>(); - - ExceptionInfo ex = test.getExceptionInfoList().get(0); - - ObjectId exceptionId; - doc = new Document("report", reportId) - .append("project", projectId) - .append("name", ex.getExceptionName()); - - FindIterable iterable = exceptionCollection.find(doc); - Document docException = iterable.first(); - - // check if a matching exception name is available in 'Exception' collection (MongoDB) - // if a matching exception name is found, associate with this exception's ObjectId - if (!exceptionNameObjectIdCollection.containsKey(ex.getExceptionName())) { - if (docException != null) { - exceptionNameObjectIdCollection.put(ex.getExceptionName(), docException.getObjectId("_id")); - } else { - doc = new Document("project", projectId) - .append("report", reportId) - .append("name", ex.getExceptionName()) - .append("stacktrace", ex.getStackTrace()) - .append("testCount", 0); - - exceptionCollection.insertOne(doc); - - exceptionId = MongoUtil.getId(doc); - docException = exceptionCollection.find(new Document("_id", exceptionId)).first(); - - exceptionNameObjectIdCollection.put(ex.getExceptionName(), exceptionId); - } - } - - Integer testCount = ((Integer) (docException.get("testCount"))) + 1; - doc = new Document("testCount", testCount); - - exceptionCollection.updateOne( - new Document("_id", docException.getObjectId("_id")), - new Document("$set", doc)); - - doc = new Document("exception", exceptionNameObjectIdCollection.get(ex.getExceptionName())); - - testCollection.updateOne( - new Document("_id", test.getObjectId()), - new Document("$set", doc)); - updateTestDesc(test); - } - - endTestRecursive(test); - } - - private void endTestRecursive(Test test) { - Document doc = new Document("status", test.getStatus().toString()) - .append("endTime", test.getEndTime()) - .append("duration", test.getRunDurationMillis()) - .append("leaf", test.getNodeContext().size()==0) - .append("childNodesLength", test.getNodeContext().size()) - .append("categorized", test.hasCategory()) - .append("description", test.getDescription()); - - testCollection.updateOne( - new Document("_id", test.getObjectId()), - new Document("$set", doc)); - - if (test.getLevel() > 0) { - endTestRecursive(test.getParent()); - } - } - - public void assignAttribute(Test test, TestAttribute attribute, Map nameObjectIdCollection, - MongoCollection mongoCollection, TestAttributeTestContextProvider attributeContext) { - } - - @Override - public void onCategoryAssigned(Test test, Category category) { - assignAttribute(test, category, categoryNameObjectIdCollection, categoryCollection, categoryContext); - } - - @Override - public void onAuthorAssigned(Test test, Author author) { - assignAttribute(test, author, authorNameObjectIdCollection, authorCollection, authorContext); - } - - private KlovMediaStorageHandler mediaStorageHandler; - - @Override - public void onScreenCaptureAdded(Test test, ScreenCapture screenCapture) throws IOException { - saveScreenCapture(test, screenCapture); - } - - @Override - public void onScreenCaptureAdded(Log log, ScreenCapture screenCapture) throws IOException { - screenCapture.setLogObjectId(log.getObjectId()); - saveScreenCapture(log, screenCapture); - } - - private void saveScreenCapture(BasicMongoReportElement el, ScreenCapture screenCapture) throws IOException { - if (mediaStorageHandler == null) { - KlovMedia klovMedia = new KlovMedia(projectId, reportId, mediaCollection); - mediaStorageHandler = new KlovMediaStorageHandler(url, klovMedia); - } - mediaStorageHandler.saveScreenCapture(el, screenCapture); - } - - @Override - public void onScreencastAdded(Test test, Screencast screencast) throws IOException { } - - /** - * Returns the active Project ID - * - * @return A {@link ObjectId} object - */ - public ObjectId getProjectId() { - return projectId; - } - - /** - * Returns the active Report ID - * - * @return A {@link ObjectId} object - */ - public ObjectId getReportId() { - return reportId; - } + } + } + + private String getConfigValue(String key) { + return String.valueOf(getConfigurationStore().getConfig(key)); + } + + @Override + public void start() { + MongoDatabase db = mongoClient.getDatabase(DB_NAME); + initCollections(db); + setupProject(); + } + + private void initCollections(MongoDatabase db) { + projectCollection = db.getCollection("project"); + reportCollection = db.getCollection("report"); + testCollection = db.getCollection("test"); + logCollection = db.getCollection("log"); + exceptionCollection = db.getCollection("exception"); + mediaCollection = db.getCollection("media"); + categoryCollection = db.getCollection("category"); + authorCollection = db.getCollection("author"); + deviceCollection = db.getCollection("device"); + environmentCollection = db.getCollection("environment"); + } + + private void setupProject() { + String projectName = this.projectName == null || this.projectName.isEmpty() ? DEFAULT_PROJECT_NAME + : this.projectName; + + Document doc = new Document("name", projectName); + Document project = projectCollection.find(doc).first(); + + if (project != null) { + projectId = project.getObjectId("_id"); + } else { + doc.append("createdAt", Calendar.getInstance().getTime()); + projectCollection.insertOne(doc); + projectId = MongoUtil.getId(doc); + } + + setupReport(projectName); + } + + private void setupReport(String projectName) { + String reportName = this.reportName == null || this.reportName.isEmpty() + ? "Build " + Calendar.getInstance().getTimeInMillis() + : this.reportName; + + Document doc = new Document("name", reportName).append("startTime", getStartTime()).append("project", projectId) + .append("projectName", projectName); + + reportCollection.insertOne(doc); + reportId = MongoUtil.getId(doc); + } + + @Override + public void stop() { + mongoClient.close(); + } + + @Override + public synchronized void flush(ReportAggregates reportAggregates) { + setEndTime(Calendar.getInstance().getTime()); + this.testList = reportAggregates.getTestList(); + + if (testList == null || testList.isEmpty()) { + return; + } + + this.authorContext = reportAggregates.getAuthorContext(); + this.categoryContext = reportAggregates.getCategoryContext(); + this.deviceContext = reportAggregates.getDeviceContext(); + this.stats = reportAggregates.getReportStatusStats(); + this.systemAttributeContext = reportAggregates.getSystemAttributeContext(); + + Status buildStatus = reportAggregates.getStatus(); + + Document doc = new Document("endTime", getEndTime()).append("duration", getRunDuration()) + .append("status", String.valueOf(buildStatus)).append("parentLength", stats.getParentCount()) + .append("passParentLength", stats.getParentCountPass()) + .append("failParentLength", stats.getParentCountFail()) + .append("fatalParentLength", stats.getParentCountFatal()) + .append("errorParentLength", stats.getParentCountError()) + .append("warningParentLength", stats.getParentCountWarning()) + .append("skipParentLength", stats.getParentCountSkip()) + .append("exceptionsParentLength", stats.getParentCountExceptions()) + .append("childLength", stats.getChildCount()).append("passChildLength", stats.getChildCountPass()) + .append("failChildLength", stats.getChildCountFail()) + .append("fatalChildLength", stats.getChildCountFatal()) + .append("errorChildLength", stats.getChildCountError()) + .append("warningChildLength", stats.getChildCountWarning()) + .append("skipChildLength", stats.getChildCountSkip()) + .append("infoChildLength", stats.getChildCountInfo()) + .append("exceptionsChildLength", stats.getChildCountExceptions()) + .append("grandChildLength", stats.getGrandChildCount()) + .append("passGrandChildLength", stats.getGrandChildCountPass()) + .append("failGrandChildLength", stats.getGrandChildCountFail()) + .append("fatalGrandChildLength", stats.getGrandChildCountFatal()) + .append("errorGrandChildLength", stats.getGrandChildCountError()) + .append("warningGrandChildLength", stats.getGrandChildCountWarning()) + .append("skipGrandChildLength", stats.getGrandChildCountSkip()) + .append("exceptionsGrandChildLength", stats.getGrandChildCountExceptions()) + .append("analysisStrategy", String.valueOf(getAnalysisStrategy())); + + reportCollection.updateOne(new Document("_id", reportId), new Document("$set", doc)); + + insertUpdateSystemAttribute(); + } + + public List getCollectionValues(Map collection) { + if (collection == null || collection.isEmpty()) + return null; + return collection.entrySet().stream().map(Map.Entry::getValue).collect(Collectors.toList()); + } + + private void insertUpdateSystemAttribute() { + List systemAttrList = systemAttributeContext.getSystemAttributeList(); + Document doc; + + for (SystemAttribute attr : systemAttrList) { + doc = new Document("project", projectId) + .append("report", reportId) + .append("name", attr.getName()); + + Document envSingle = environmentCollection.find(doc).first(); + + if (envSingle == null) { + doc.append("value", attr.getValue()); + environmentCollection.insertOne(doc); + } else { + ObjectId id = envSingle.getObjectId("_id"); + doc = new Document("_id", id).append("value", attr.getValue()); + environmentCollection.updateOne(new Document("_id", id), new Document("$set", doc)); + } + } + } + + @Override + public void onTestStarted(Test test) { + onTestStartedHelper(test); + } @Override - public void onTestRemoved(Test test) { } + public synchronized void onNodeStarted(Test node) { + onTestStartedHelper(node); + } + + private void onTestStartedHelper(Test test) { + Document doc = new Document("project", projectId) + .append("report", reportId) + .append("reportName", reportName) + .append("level", test.getLevel()) + .append("name", test.getName()) + .append("status", test.getStatus().toString()) + .append("description", test.getDescription()) + .append("startTime", test.getStartTime()) + .append("endTime", test.getEndTime()) + .append("bdd", test.isBehaviorDrivenType()) + .append("leaf", test.getNodeContext().isEmpty()) + .append("childNodesLength", test.getNodeContext().size()); + + if (test.isBehaviorDrivenType()) { + doc.append("bddType", test.getBehaviorDrivenTypeName()); + } + + if (test.getParent() != null) { + doc.append("parent", test.getParent().getObjectId()) + .append("parentName", test.getParent().getName()); + updateTestChildrenCount(test.getParent()); + updateTestDesc(test.getParent()); + } + + testCollection.insertOne(doc); + ObjectId testId = MongoUtil.getId(doc); + test.setObjectId(testId); + } + + private void updateTestDesc(Test test) { + Document doc = new Document("description", test.getDescription()); + testCollection.updateOne(new Document("_id", test.getObjectId()), new Document("$set", doc)); + } + + private void updateTestChildrenCount(Test test) { + Document doc = new Document("childNodesLength", test.getNodeContext().size()); + testCollection.updateOne(new Document("_id", test.getObjectId()), new Document("$set", doc)); + } + + @Override + public synchronized void onLogAdded(Test test, Log log) { + Document doc = new Document("test", test.getObjectId()) + .append("project", projectId) + .append("report", reportId) + .append("testName", test.getName()) + .append("sequence", log.getSequence()) + .append("status", log.getStatus().toString()) + .append("timestamp", log.getTimestamp()) + .append("details", log.getDetails()); + + if (log.getExceptionInfo() != null) { + doc.append("exception", log.getExceptionInfo().getExceptionName()).append("stacktrace", + log.getExceptionInfo().getStackTrace()); + } + + if (LogService.logHasScreenCapture(log) && log.getScreenCaptureContext().getFirst().isBase64()) { + doc.append("details", log.getDetails() + log.getScreenCaptureContext().getFirst().getSource()); + } + + logCollection.insertOne(doc); + + ObjectId logId = MongoUtil.getId(doc); + log.setObjectId(logId); + + // check for exceptions.. + if (TestService.testHasException(test)) { + if (exceptionNameObjectIdCollection == null) + exceptionNameObjectIdCollection = new HashMap<>(); + + ExceptionInfo ex = test.getExceptionInfoContext().get(0); + + ObjectId exceptionId; + doc = new Document("report", reportId).append("project", projectId).append("name", ex.getExceptionName()); + + FindIterable iterable = exceptionCollection.find(doc); + Document docException = iterable.first(); + + // check if a matching exception name is available in 'Exception' collection + // (MongoDB) + // if a matching exception name is found, associate with this exception's + // ObjectId + if (!exceptionNameObjectIdCollection.containsKey(ex.getExceptionName())) { + if (docException != null) { + exceptionNameObjectIdCollection.put(ex.getExceptionName(), docException.getObjectId("_id")); + } else { + doc = new Document("project", projectId) + .append("report", reportId) + .append("name", ex.getExceptionName()) + .append("stacktrace", ex.getStackTrace()) + .append("testCount", 0); + + exceptionCollection.insertOne(doc); + + exceptionId = MongoUtil.getId(doc); + docException = exceptionCollection.find(new Document("_id", exceptionId)).first(); + + exceptionNameObjectIdCollection.put(ex.getExceptionName(), exceptionId); + } + } + + Integer testCount = ((Integer) (docException.get("testCount"))) + 1; + doc = new Document("testCount", testCount); + + exceptionCollection.updateOne(new Document("_id", docException.getObjectId("_id")), + new Document("$set", doc)); + + doc = new Document("exception", exceptionNameObjectIdCollection.get(ex.getExceptionName())); + + testCollection.updateOne(new Document("_id", test.getObjectId()), new Document("$set", doc)); + updateTestDesc(test); + } + + endTestRecursive(test); + } + + private void endTestRecursive(Test test) { + Document doc = new Document("status", test.getStatus().toString()).append("endTime", test.getEndTime()) + .append("duration", TestService.getRunDurationMillis(test)) + .append("leaf", test.getNodeContext().isEmpty()) + .append("childNodesLength", test.getNodeContext().size()) + .append("categorized", TestService.testHasCategory(test)) + .append("description", test.getDescription()); + + testCollection.updateOne(new Document("_id", test.getObjectId()), new Document("$set", doc)); + + if (test.getLevel() > 0) { + endTestRecursive(test.getParent()); + } + } + + public void assignAttribute(Test test, Attribute attribute, + Map nameObjectIdCollection, MongoCollection mongoCollection, + TestAttributeTestContextStore attributeContext) { + } + + @Override + public void onCategoryAssigned(Test test, Category category) { + assignAttribute(test, category, categoryNameObjectIdCollection, categoryCollection, categoryContext); + } + + @Override + public void onAuthorAssigned(Test test, Author author) { + assignAttribute(test, author, authorNameObjectIdCollection, authorCollection, authorContext); + } + + @Override + public void onScreenCaptureAdded(Test test, ScreenCapture screenCapture) throws IOException { + screenCapture.getBsonId().put("testId", test.getObjectId()); + saveScreenCapture(test, screenCapture); + } + + @Override + public void onScreenCaptureAdded(Log log, ScreenCapture screenCapture) throws IOException { + screenCapture.getBsonId().put("logId", log.getObjectId()); + screenCapture.getBsonId().put("testId", log.getTest().getObjectId()); + saveScreenCapture(log, screenCapture); + } + + private void saveScreenCapture(BasicMongoReportElement el, ScreenCapture screenCapture) throws IOException { + if (mediaStorageHandler == null) { + KlovMedia klovMedia = new KlovMedia(projectId, reportId, mediaCollection); + mediaStorageHandler = new KlovMediaStorageHandler(url, klovMedia); + } + mediaStorageHandler.saveScreenCapture(el, screenCapture); + } + + /** + * Returns the active Project ID + * + * @return A {@link ObjectId} object + */ + public ObjectId getProjectId() { + return projectId; + } + + /** + * Returns the active Report ID + * + * @return A {@link ObjectId} object + */ + public ObjectId getReportId() { + return reportId; + } + + @Override + public void onTestRemoved(Test test) { + } @Override public void onDeviceAssigned(Test test, Device device) { @@ -716,5 +641,5 @@ public void onDeviceAssigned(Test test, Device device) { public String getReporterName() { return REPORTER_NAME; } - -} + +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/reporter/ExtentLoggerReporter.java b/src/main/java/com/aventstack/extentreports/reporter/ExtentLoggerReporter.java index 681b59a..27accad 100644 --- a/src/main/java/com/aventstack/extentreports/reporter/ExtentLoggerReporter.java +++ b/src/main/java/com/aventstack/extentreports/reporter/ExtentLoggerReporter.java @@ -6,7 +6,7 @@ import java.util.logging.Logger; import com.aventstack.extentreports.ReportAggregates; -import com.aventstack.extentreports.reporter.configuration.ExtentLoggerFormatterConfiguration; +import com.aventstack.extentreports.reporter.configuration.ExtentLoggerReporterConfiguration; import freemarker.template.Template; import freemarker.template.TemplateException; @@ -26,7 +26,7 @@ public class ExtentLoggerReporter extends BasicFileReporter { private static final String[] DEFAULT_CONFIG_FILE_PATH = new String[] { "logger.properties", "src/main/resources/logger.properties" }; - private ExtentLoggerFormatterConfiguration userConfig = new ExtentLoggerFormatterConfiguration(this); + private ExtentLoggerReporterConfiguration userConfig = new ExtentLoggerReporterConfiguration(this); public ExtentLoggerReporter(String path) { super(path); @@ -38,7 +38,7 @@ public ExtentLoggerReporter(File file) { init(DEFAULT_CONFIG_FILE_PATH, config()); } - public ExtentLoggerFormatterConfiguration config() { + public ExtentLoggerReporterConfiguration config() { return userConfig; } @@ -56,18 +56,18 @@ public synchronized void flush(ReportAggregates reportAggregates) { try { Template template = getFreemarkerConfig().getTemplate(TEMPLATE_NAME); - processTemplate(template, new File(destination + "index.html")); - if (String.valueOf(configContext.getValue("enableDashboard")).equalsIgnoreCase("true")) { + processTemplate(template, new File(getDestinationPath() + "index.html")); + if (String.valueOf(getConfigurationStore().getConfig("enableDashboard")).equalsIgnoreCase("true")) { template = getFreemarkerConfig().getTemplate(DASHBOARD_TEMPLATE_NAME); - processTemplate(template, new File(destination + "dashboard.html")); + processTemplate(template, new File(getDestinationPath() + "dashboard.html")); } - if (!getCategoryContextInfo().getTestAttributeTestContextList().isEmpty()) { + if (!getCategoryContextInfo().getTestAttributeTestContext().isEmpty()) { template = getFreemarkerConfig().getTemplate(CATEGORY_TEMPLATE_NAME); - processTemplate(template, new File(destination + "tag.html")); + processTemplate(template, new File(getDestinationPath() + "tag.html")); } - if (!getExceptionContextInfo().getExceptionTestContextList().isEmpty()) { + if (!getExceptionContextInfo().getExceptionTestContext().isEmpty()) { template = getFreemarkerConfig().getTemplate(EXCEPTION_TEMPLATE_NAME); - processTemplate(template, new File(destination + "exception.html")); + processTemplate(template, new File(getDestinationPath() + "exception.html")); } } catch (IOException | TemplateException e) { logger.log(Level.SEVERE, "An exception occurred", e); diff --git a/src/main/java/com/aventstack/extentreports/reporter/ExtentReporter.java b/src/main/java/com/aventstack/extentreports/reporter/ExtentReporter.java new file mode 100644 index 0000000..c867d04 --- /dev/null +++ b/src/main/java/com/aventstack/extentreports/reporter/ExtentReporter.java @@ -0,0 +1,38 @@ +package com.aventstack.extentreports.reporter; + +import com.aventstack.extentreports.IAnalysisStrategyMethod; +import com.aventstack.extentreports.ReportAggregates; +import com.aventstack.extentreports.ReportAggregatesListener; +import com.aventstack.extentreports.TestListener; + +/** + * Primary interface implemented by each reporter. This interface implements + * {@link TestListener} and {@link ReportAggregatesListener} interface to + * provide additional functionality to each reporter. + */ +public interface ExtentReporter extends TestListener, IAnalysisStrategyMethod { + + /** + * Starts passing run information to the reporter + */ + void start(); + + /** + * Stops the reporter. Ensures no information is passed to the reporter. + */ + void stop(); + + /** + * Write to or update the target source (file, database) + * + * @param reportAggregates a {@link ReportAggregates} object + */ + void flush(ReportAggregates reportAggregates); + + /** + * Get the reporter name + * + * @return reporter name + */ + String getReporterName(); +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/reporter/ExtentSparkReporter.java b/src/main/java/com/aventstack/extentreports/reporter/ExtentSparkReporter.java index 5dd9d43..5ff5f7f 100644 --- a/src/main/java/com/aventstack/extentreports/reporter/ExtentSparkReporter.java +++ b/src/main/java/com/aventstack/extentreports/reporter/ExtentSparkReporter.java @@ -7,71 +7,96 @@ import com.aventstack.extentreports.ReportAggregates; import com.aventstack.extentreports.reporter.configuration.ExtentSparkReporterConfiguration; +import com.aventstack.extentreports.reporter.configuration.ViewStyle; import freemarker.template.Template; import freemarker.template.TemplateException; /** - * The ExtentSparkReporter creates a rich standalone spark file. It allows several - * configuration options via the config() method. + * The ExtentSparkReporter creates a rich standalone spark file. It allows + * several configuration options via the config() method. */ public class ExtentSparkReporter extends BasicFileReporter { - private static final Logger logger = Logger.getLogger(ExtentSparkReporter.class.getName()); - private static final String REPORTER_NAME = "spark"; - private static final String TEST_TEMPLATE_NAME = REPORTER_NAME + "/test.ftl"; - private static final String TAG_TEMPLATE_NAME = REPORTER_NAME + "/tag.ftl"; - private static final String EXCEPTION_TEMPLATE_NAME = REPORTER_NAME + "/exception.ftl"; - private static final String DASHBOARD_TEMPLATE_NAME = REPORTER_NAME + "/dashboard.ftl"; - private static final String[] DEFAULT_CONFIG_FILE_PATH = new String[] { "spark.properties", - "src/main/resources/spark.properties" }; - - private ExtentSparkReporterConfiguration userConfig = new ExtentSparkReporterConfiguration(this); - - public ExtentSparkReporter(String path) { - super(path); - init(DEFAULT_CONFIG_FILE_PATH, config()); - } - - public ExtentSparkReporter(File file) { - super(file); - init(DEFAULT_CONFIG_FILE_PATH, config()); - } - - public ExtentSparkReporterConfiguration config() { - return userConfig; - } - - @Override - public synchronized void flush(ReportAggregates reportAggregates) { - super.flush(reportAggregates); - - if (getTestList().isEmpty()) - return; - - loadUserConfig(); - - try { - Template template = getFreemarkerConfig().getTemplate(TEST_TEMPLATE_NAME); - processTemplate(template, new File(destination + "index.html")); - if (!getCategoryContextInfo().getTestAttributeTestContextList().isEmpty()) { - template = getFreemarkerConfig().getTemplate(TAG_TEMPLATE_NAME); - processTemplate(template, new File(destination + "tag.html")); - } - if (!getExceptionContextInfo().getExceptionTestContextList().isEmpty()) { - template = getFreemarkerConfig().getTemplate(EXCEPTION_TEMPLATE_NAME); - processTemplate(template, new File(destination + "exception.html")); - } - template = getFreemarkerConfig().getTemplate(DASHBOARD_TEMPLATE_NAME); - processTemplate(template, new File(destination + "dashboard.html")); - } catch (IOException | TemplateException e) { - logger.log(Level.SEVERE, "An exception occurred", e); - } - } - - @Override - public String getReporterName() { - return REPORTER_NAME; - } - -} + private static final Logger logger = Logger.getLogger(ExtentSparkReporter.class.getName()); + private static final String REPORTER_NAME = "spark"; + private static final String SPA_TEMPLATE_NAME = REPORTER_NAME + "/spark.spa.ftl"; + private static final String TEST_TEMPLATE_NAME = REPORTER_NAME + "/test.ftl"; + private static final String TAG_TEMPLATE_NAME = REPORTER_NAME + "/tag.ftl"; + private static final String EXCEPTION_TEMPLATE_NAME = REPORTER_NAME + "/exception.ftl"; + private static final String DASHBOARD_TEMPLATE_NAME = REPORTER_NAME + "/dashboard.ftl"; + private static final String[] DEFAULT_CONFIG_FILE_PATH = new String[] { "spark.properties", + "src/main/resources/spark.properties" }; + + private ExtentSparkReporterConfiguration externalUserConfiguration = new ExtentSparkReporterConfiguration(this); + private ViewStyle viewStyle = ViewStyle.SPA; + + public ExtentSparkReporter(String path) { + super(path); + init(DEFAULT_CONFIG_FILE_PATH, config()); + } + + public ExtentSparkReporter(File file) { + super(file); + init(DEFAULT_CONFIG_FILE_PATH, config()); + } + + public ExtentSparkReporter(String path, ViewStyle viewStyle) { + this(path); + setViewStyle(viewStyle); + } + + public ExtentSparkReporter(File file, ViewStyle viewStyle) { + this(file); + setViewStyle(viewStyle); + } + + public ExtentSparkReporterConfiguration config() { + return externalUserConfiguration; + } + + private void setViewStyle(ViewStyle viewStyle) { + this.viewStyle = viewStyle; + } + + @Override + public synchronized void flush(ReportAggregates reportAggregates) { + super.flush(reportAggregates); + if (getTestList().isEmpty()) { + return; + } + if (enforceOfflineMode()) { + externalUserConfiguration.enableOfflineMode(true); + } + + loadUserConfig(); + + try { + if (viewStyle == ViewStyle.SPA) { + Template template = getFreemarkerConfig().getTemplate(SPA_TEMPLATE_NAME); + processTemplate(template, new File(getDestinationPath() + "index.html")); + return; + } + Template template = getFreemarkerConfig().getTemplate(TEST_TEMPLATE_NAME); + processTemplate(template, new File(getDestinationPath() + "index.html")); + if (!getCategoryContextInfo().getTestAttributeTestContext().isEmpty()) { + template = getFreemarkerConfig().getTemplate(TAG_TEMPLATE_NAME); + processTemplate(template, new File(getDestinationPath() + "tag.html")); + } + if (!getExceptionContextInfo().getExceptionTestContext().isEmpty()) { + template = getFreemarkerConfig().getTemplate(EXCEPTION_TEMPLATE_NAME); + processTemplate(template, new File(getDestinationPath() + "exception.html")); + } + template = getFreemarkerConfig().getTemplate(DASHBOARD_TEMPLATE_NAME); + processTemplate(template, new File(getDestinationPath() + "dashboard.html")); + } catch (IOException | TemplateException e) { + logger.log(Level.SEVERE, "An exception occurred", e); + } + } + + @Override + public String getReporterName() { + return REPORTER_NAME; + } + +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/reporter/JsonFormatter.java b/src/main/java/com/aventstack/extentreports/reporter/JsonFormatter.java new file mode 100644 index 0000000..1e4b062 --- /dev/null +++ b/src/main/java/com/aventstack/extentreports/reporter/JsonFormatter.java @@ -0,0 +1,46 @@ +package com.aventstack.extentreports.reporter; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.List; + +import com.aventstack.extentreports.ReportAggregates; +import com.aventstack.extentreports.model.Test; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +public class JsonFormatter extends BasicFileReporter { + + public JsonFormatter(String path) { + super(path); + } + + public JsonFormatter(File file) { + super(file); + } + + @Override + public void start() { + + } + + @Override + public synchronized void flush(ReportAggregates reportAggregates) { + super.flush(reportAggregates); + GsonBuilder builder = new GsonBuilder(); + Gson gson = builder.create(); + try (FileWriter writer = new FileWriter(getFilePath())) { + List list = reportAggregates.getTestList(); + gson.toJson(list, writer); + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Override + public String getReporterName() { + return "JSON"; + } + +} diff --git a/src/main/java/com/aventstack/extentreports/reporter/ReportAppendable.java b/src/main/java/com/aventstack/extentreports/reporter/ReportAppendable.java index 335c699..ecb10da 100644 --- a/src/main/java/com/aventstack/extentreports/reporter/ReportAppendable.java +++ b/src/main/java/com/aventstack/extentreports/reporter/ReportAppendable.java @@ -2,6 +2,6 @@ public interface ReportAppendable { - void setAppendExisting(Boolean b); + void setAppendExisting(Boolean b); -} +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/reporter/TestListener.java b/src/main/java/com/aventstack/extentreports/reporter/TestListener.java new file mode 100644 index 0000000..6916f46 --- /dev/null +++ b/src/main/java/com/aventstack/extentreports/reporter/TestListener.java @@ -0,0 +1,96 @@ +package com.aventstack.extentreports.reporter; + +import java.io.IOException; + +import com.aventstack.extentreports.model.Author; +import com.aventstack.extentreports.model.Category; +import com.aventstack.extentreports.model.Device; +import com.aventstack.extentreports.model.Log; +import com.aventstack.extentreports.model.ScreenCapture; +import com.aventstack.extentreports.model.Test; + +/** + * Listener methods invoked when an event occurs in the report: + * + *

    + *
  • A test or node is started
  • + *
  • A category or author is added
  • + *
  • A media object is added etc.
  • + *
+ */ +public interface TestListener { + + /** + * Invoked when a test is started using createTest() + * + * @param test {@link com.aventstack.extentreports.model.Test} object + */ + void onTestStarted(Test test); + + /** + * Invoked when a test is removed using removeTest() + * + * @param test {@link com.aventstack.extentreports.model.Test} object + */ + void onTestRemoved(Test test); + + /** + * Invoked when a node is started using createNode() + * + * @param node {@link com.aventstack.extentreports.model.Test} object + */ + void onNodeStarted(Test node); + + /** + * Invoked each time a log is added to any test/node + * + * @param test {@link com.aventstack.extentreports.model.Test} object + * @param log {@link com.aventstack.extentreports.model.Log} object + */ + void onLogCreated(Test test, Log log); + + /** + * Invoked each time a category is assigned to any test/node + * + * @param test {@link com.aventstack.extentreports.model.Test} object + * @param category {@link com.aventstack.extentreports.model.Category} object + */ + void onCategoryAssigned(Test test, Category category); + + /** + * Invoked each time an author is assigned to any test/node + * + * @param test {@link com.aventstack.extentreports.model.Test} object + * @param author {@link com.aventstack.extentreports.model.Author} object + */ + void onAuthorAssigned(Test test, Author author); + + /** + * Invoked each time a device is assigned to any test/node + * + * @param test {@link com.aventstack.extentreports.model.Test} object + * @param device {@link com.aventstack.extentreports.model.Device} object + */ + void onDeviceAssigned(Test test, Device device); + + /** + * Invoked each time a screencapture is added to test + * + * @param test {@link com.aventstack.extentreports.model.Test} object + * @param screenCapture {@link com.aventstack.extentreports.model.ScreenCapture} + * object + * @throws IOException Exception thrown if the media object is not found + */ + void onScreenCaptureCreated(Test test, ScreenCapture screenCapture) throws IOException; + + /** + * Invoked each time a screencapture is added to log + * + * @param log {@link com.aventstack.extentreports.model.Log} object + * @param screenCapture {@link com.aventstack.extentreports.model.ScreenCapture} + * object + * @throws IOException Exception thrown if the media object is not found + */ + void onScreenCaptureCreated(Log log, ScreenCapture screenCapture) throws IOException; + +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/reporter/configuration/BasicConfiguration.java b/src/main/java/com/aventstack/extentreports/reporter/configuration/BasicConfiguration.java index 7a3bdfc..cd1a10a 100644 --- a/src/main/java/com/aventstack/extentreports/reporter/configuration/BasicConfiguration.java +++ b/src/main/java/com/aventstack/extentreports/reporter/configuration/BasicConfiguration.java @@ -2,74 +2,48 @@ import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; import java.util.List; -import java.util.Map; +import java.util.Optional; import com.aventstack.extentreports.Status; +import com.aventstack.extentreports.configuration.ConfigurationStore; import com.aventstack.extentreports.reporter.AbstractReporter; public abstract class BasicConfiguration { + private ConfigurationStore store = new ConfigurationStore(); private AbstractReporter reporter; - - protected List levels; - protected String reportName; - protected String timeStampFormat; - protected Map usedConfigs = new HashMap<>(); + private List levels; - protected BasicConfiguration() { } - - protected BasicConfiguration(AbstractReporter reporter) { - this.reporter = reporter; - } - - protected AbstractReporter getReporter() { - return reporter; - } - - public Map getConfigMap() { - return usedConfigs; - } + protected BasicConfiguration(AbstractReporter reporter) { + this.reporter = reporter; + } - public void setLevel(Status... level) { - if (levels == null) - levels = new ArrayList<>(); + protected AbstractReporter getReporter() { + return reporter; + } - Arrays.stream(level).forEach(levels::add); - } + public ConfigurationStore getConfigurationStore() { + return store; + } - public List getLevel() { - return levels; - } + public void setLevel(Status... level) { + if (levels == null) { + levels = new ArrayList<>(); + } + Arrays.stream(level).forEach(levels::add); + } - /** - * Gets the timestamp format - * - * @return The time stamp format - */ - public String getTimeStampFormat() { - return usedConfigs.get("timeStampFormat"); - } + public List getLevel() { + return levels; + } - /** - * Sets the timestamp format - * - * @param timeStampFormat The desired time stamp format - * See http://freemarker.org/docs/ref_builtins_date.html#ref_builtin_string_for_date - */ - public void setTimeStampFormat(String timeStampFormat) { - usedConfigs.put("timeStampFormat", timeStampFormat); - this.timeStampFormat = timeStampFormat; - } + public String getReportName() { + return (String) Optional.ofNullable(getConfigurationStore().getConfig("reportName")).orElse(null); + } - public void setReportName(String reportName) { - usedConfigs.put("reportName", reportName); - this.reportName = reportName; - } + public void setReportName(String reportName) { + store.storeConfig("reportName", reportName); + } - public String getReportName() { - return reportName; - } - -} +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/reporter/configuration/BasicFileConfiguration.java b/src/main/java/com/aventstack/extentreports/reporter/configuration/BasicFileConfiguration.java index d54268d..75432b2 100644 --- a/src/main/java/com/aventstack/extentreports/reporter/configuration/BasicFileConfiguration.java +++ b/src/main/java/com/aventstack/extentreports/reporter/configuration/BasicFileConfiguration.java @@ -1,70 +1,88 @@ package com.aventstack.extentreports.reporter.configuration; +import java.util.Optional; + import com.aventstack.extentreports.reporter.AbstractReporter; /** - * Common configuration for file reporters: + * Common configuration for file based reporters * - *
    - *
  • {@link com.aventstack.extentreports.reporter.ExtentHtmlReporter}
  • - *
*/ -public class BasicFileConfiguration - extends BasicConfiguration { +public abstract class BasicFileConfiguration extends BasicConfiguration { + + protected BasicFileConfiguration(AbstractReporter reporter) { + super(reporter); + } + + /** + * Gets the timestamp format + * + * @return The time stamp format + */ + public String getTimeStampFormat() { + return (String) Optional.ofNullable(getConfigurationStore().getConfig("timeStampFormat")).orElse(null); + } + + /** + * Sets the timestamp format + * + * @param timeStampFormat The desired time stamp format See + * http://freemarker.org/docs/ref_builtins_date.html#ref_builtin_string_for_date + */ + public void setTimeStampFormat(String timeStampFormat) { + getConfigurationStore().storeConfig("timeStampFormat", timeStampFormat); + } + + /** + * Sets file encoding, eg: UTF-8 + * + * @param encoding Encoding + */ + public void setEncoding(String encoding) { + getConfigurationStore().storeConfig("encoding", encoding); + } + + public String getEncoding() { + return (String) Optional.ofNullable(getConfigurationStore().getConfig("encoding")).orElse(null); + } + + /** + * Sets the document title denoted by the title tag + * + * @param documentTitle Title + */ + public void setDocumentTitle(String documentTitle) { + getConfigurationStore().storeConfig("documentTitle", documentTitle); + } + + public String getDocumentTitle() { + return (String) Optional.ofNullable(getConfigurationStore().getConfig("documentTitle")).orElse(null); + } + + /** + * Sets CSS to be used to customize the look and feel of your report + * + * @param css CSS + */ + public void setCSS(String css) { + getConfigurationStore().storeConfig("css", css); + } + + public String getCSS() { + return (String) Optional.ofNullable(getConfigurationStore().getConfig("css")).orElse(null); + } - private String encoding; - private String docTitle; - private String css; - private String js; - - protected BasicFileConfiguration() { } - - protected BasicFileConfiguration(AbstractReporter reporter) { - super(reporter); - } - - /** - * Sets file encoding, eg: UTF-8 - * - * @param encoding Encoding - */ - public void setEncoding(String encoding) { - usedConfigs.put("encoding", encoding); - this.encoding = encoding; - } - public String getEncoding() { return encoding; } + /** + * Adds custom JavaScript + * + * @param js JavaScript + */ + public void setJS(String js) { + getConfigurationStore().storeConfig("js", js); + } - /** - * Sets the document title denoted by the title tag - * - * @param docTitle Title - */ - public void setDocumentTitle(String docTitle) { - usedConfigs.put("documentTitle", docTitle); - this.docTitle = docTitle; - } - public String getDocumentTitle() { return docTitle; } - - /** - * Sets CSS to be used to customize the look and feel of your report - * - * @param css CSS - */ - public void setCSS(String css) { - usedConfigs.put("styles", css); - this.css = css; - } - public String getCSS() { return css; } - - /** - * Adds custom JavaScript - * - * @param js JavaScript - */ - public void setJS(String js) { - usedConfigs.put("scripts", js); - this.js = js; - } - public String getJS() { return js; } + public String getJS() { + return (String) Optional.ofNullable(getConfigurationStore().getConfig("js")).orElse(null); + } -} +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/reporter/configuration/ExtentHtmlReporterConfiguration.java b/src/main/java/com/aventstack/extentreports/reporter/configuration/ExtentHtmlReporterConfiguration.java index 9391cfc..b7f5915 100644 --- a/src/main/java/com/aventstack/extentreports/reporter/configuration/ExtentHtmlReporterConfiguration.java +++ b/src/main/java/com/aventstack/extentreports/reporter/configuration/ExtentHtmlReporterConfiguration.java @@ -1,15 +1,90 @@ package com.aventstack.extentreports.reporter.configuration; +import java.io.File; +import java.util.stream.Stream; + +import com.aventstack.extentreports.ExtentReports; +import com.aventstack.extentreports.offline.OfflineResxDelegate; import com.aventstack.extentreports.reporter.ExtentHtmlReporter; +import com.aventstack.extentreports.reporter.ExtentSparkReporter; +import com.aventstack.extentreports.utils.FileUtil; /** - * Defines configuration settings for the HTML reporter + * Defines configuration settings for the Spark reporter */ -public class ExtentHtmlReporterConfiguration - extends RichViewReporterConfiguration { +public class ExtentHtmlReporterConfiguration extends RichViewReporterConfiguration { - public ExtentHtmlReporterConfiguration(ExtentHtmlReporter reporter) { + public ExtentHtmlReporterConfiguration(ExtentHtmlReporter reporter) { super(reporter); } -} + /** + * Creates the HTML report, saving all resources (css, js, fonts) in the same + * location, so the report can be viewed without an internet connection + * + * @param offline Setting to enable an offline accessible report + */ + public void enableOfflineMode(Boolean offline) { + getConfigurationStore().storeConfig("enableOfflineMode", String.valueOf(offline)); + getConfigurationStore().storeConfig("offlineDirectory", getReporter().getReporterName() + "/"); + if (offline) { + File f = getTargetDirectory(((ExtentSparkReporter) getReporter()).getFileFile()); + String s = "/"; + String resourcePackagePath = ExtentReports.class.getPackage().getName().replace(".", s); + resourcePackagePath += s + "offline" + s; + String[] resx = combine(getJSFiles(), getCSSFiles(), getIconFiles(), getImgFiles()); + OfflineResxDelegate.saveOfflineResources(resourcePackagePath, resx, f.getAbsolutePath()); + } + } + + private File getTargetDirectory(File f) { + String dir; + if (FileUtil.isDirectory(f)) { + dir = f.getAbsolutePath().replace("\\", "/"); + } else { + dir = f.getAbsolutePath().replace("\\", "/"); + dir = new File(dir).getParent(); + } + dir += "/" + getReporter().getReporterName(); + return new File(dir); + } + + private String[] combine(String[]... array) { + String[] result = new String[] {}; + for (String[] arr : array) { + result = Stream.of(result, arr).flatMap(Stream::of).toArray(String[]::new); + } + return result; + } + + private String[] getJSFiles() { + String commonsPath = "commons/js/"; + String reporterPath = getReporter().getReporterName() + "/js/"; + String[] files = { reporterPath + "spark-script.js", commonsPath + "jsontree.js" }; + return files; + } + + private String[] getCSSFiles() { + String stylesPath = "css/"; + String reporterPath = getReporter().getReporterName() + "/" + stylesPath; + String[] files = { reporterPath + "spark-style.css" }; + return files; + } + + private String[] getIconFiles() { + String path = "commons/css/icons/"; + String iconDirPath = "fontawesome/"; + String[] files = { path + "font-awesome.min.css", path + iconDirPath + "fontawesome-webfont.eot", + path + iconDirPath + "fontawesome-webfont.svg", path + iconDirPath + "fontawesome-webfont.ttf", + path + iconDirPath + "fontawesome-webfont.woff", path + iconDirPath + "fontawesome-webfont.woff2", + path + iconDirPath + "FontAwesome.otf" }; + return files; + } + + private String[] getImgFiles() { + String path = "commons/img/"; + String[] files = { path + "logo.png" }; + return files; + } + +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/reporter/configuration/ExtentLoggerFormatterConfiguration.java b/src/main/java/com/aventstack/extentreports/reporter/configuration/ExtentLoggerFormatterConfiguration.java deleted file mode 100644 index b6e0fa5..0000000 --- a/src/main/java/com/aventstack/extentreports/reporter/configuration/ExtentLoggerFormatterConfiguration.java +++ /dev/null @@ -1,107 +0,0 @@ -package com.aventstack.extentreports.reporter.configuration; - -import java.io.File; -import java.util.stream.Stream; - -import com.aventstack.extentreports.ExtentReports; -import com.aventstack.extentreports.reporter.AbstractReporter; -import com.aventstack.extentreports.reporter.ExtentLoggerReporter; -import com.aventstack.extentreports.resource.OfflineResxDelegate; -import com.aventstack.extentreports.utils.FileUtil; - -/** - * Defines configuration settings for the HTML reporter - */ -public class ExtentLoggerFormatterConfiguration - extends RichViewReporterConfiguration { - - public ExtentLoggerFormatterConfiguration(AbstractReporter reporter) { - super(reporter); - } - - /** - * Creates the HTML report, saving all resources (css, js, fonts) in the same location, so the - * report can be viewed without an internet connection - * - * @param offline Setting to enable an offline accessible report - */ - public void enableOfflineMode(Boolean offline) { - usedConfigs.put("enableOfflineMode", String.valueOf(offline)); - usedConfigs.put("offlineDirectory", getReporter().getReporterName() + "/"); - if (offline) { - File f = getTargetDirectory(((ExtentLoggerReporter)getReporter()).getFileFile()); - String s = "/"; - String resourcePackagePath = ExtentReports.class.getPackage().getName().replace(".", s); - resourcePackagePath += s + "offline" + s; - String[] resx = combine(getJSFiles(), - getCSSFiles(), - getIconFiles(), - getImgFiles()); - OfflineResxDelegate.saveOfflineResources(resourcePackagePath, resx, f.getAbsolutePath()); - } - } - - private File getTargetDirectory(File f) { - String dir; - if (FileUtil.isDirectory(f)) { - dir = f.getAbsolutePath().replace("\\", "/"); - } else { - dir = f.getAbsolutePath().replace("\\", "/"); - dir = new File(dir).getParent(); - } - dir += "/" + getReporter().getReporterName(); - return new File(dir); - } - - private String[] combine(String[]... array) { - String[] result = new String[] {}; - for (String[] arr : array) { - result = Stream.of(result, arr).flatMap(Stream::of).toArray(String[]::new); - } - return result; - } - - private String[] getJSFiles() { - String commonsPath = "commons/js/"; - String reporterPath = getReporter().getReporterName() + "/js/"; - String[] files = { - commonsPath + "attr.js", - commonsPath + "dashboard.js", - reporterPath + "logger-scripts.js" - }; - return files; - } - - private String[] getCSSFiles() { - String stylesPath = "css/"; - String reporterPath = getReporter().getReporterName() + "/" + stylesPath + "/"; - String[] files = { - reporterPath + "logger-style.css", - }; - return files; - } - - private String[] getIconFiles() { - String path = "commons/css/icons/"; - String iconDirPath = "fontawesome/"; - String[] files = { - path + "font-awesome.min.css", - path + iconDirPath + "fontawesome-webfont.eot", - path + iconDirPath + "fontawesome-webfont.svg", - path + iconDirPath + "fontawesome-webfont.ttf", - path + iconDirPath + "fontawesome-webfont.woff", - path + iconDirPath + "fontawesome-webfont.woff2", - path + iconDirPath + "FontAwesome.otf", - }; - return files; - } - - private String[] getImgFiles() { - String path = "commons/img/"; - String[] files = { - path + "logo.png" - }; - return files; - } - -} diff --git a/src/main/java/com/aventstack/extentreports/reporter/configuration/ExtentLoggerReporterConfiguration.java b/src/main/java/com/aventstack/extentreports/reporter/configuration/ExtentLoggerReporterConfiguration.java new file mode 100644 index 0000000..781bcca --- /dev/null +++ b/src/main/java/com/aventstack/extentreports/reporter/configuration/ExtentLoggerReporterConfiguration.java @@ -0,0 +1,90 @@ +package com.aventstack.extentreports.reporter.configuration; + +import java.io.File; +import java.util.stream.Stream; + +import com.aventstack.extentreports.ExtentReports; +import com.aventstack.extentreports.offline.OfflineResxDelegate; +import com.aventstack.extentreports.reporter.AbstractReporter; +import com.aventstack.extentreports.reporter.ExtentLoggerReporter; +import com.aventstack.extentreports.utils.FileUtil; + +/** + * Defines configuration settings for the HTML reporter + */ +public class ExtentLoggerReporterConfiguration extends RichViewReporterConfiguration { + + public ExtentLoggerReporterConfiguration(AbstractReporter reporter) { + super(reporter); + } + + /** + * Creates the HTML report, saving all resources (css, js, fonts) in the same + * location, so the report can be viewed without an internet connection + * + * @param offline Setting to enable an offline accessible report + */ + public void enableOfflineMode(Boolean offline) { + getConfigurationStore().storeConfig("enableOfflineMode", String.valueOf(offline)); + getConfigurationStore().storeConfig("offlineDirectory", getReporter().getReporterName() + "/"); + if (offline) { + File f = getTargetDirectory(((ExtentLoggerReporter) getReporter()).getFileFile()); + String s = "/"; + String resourcePackagePath = ExtentReports.class.getPackage().getName().replace(".", s); + resourcePackagePath += s + "offline" + s; + String[] resx = combine(getJSFiles(), getCSSFiles(), getIconFiles(), getImgFiles()); + OfflineResxDelegate.saveOfflineResources(resourcePackagePath, resx, f.getAbsolutePath()); + } + } + + private File getTargetDirectory(File f) { + String dir; + if (FileUtil.isDirectory(f)) { + dir = f.getAbsolutePath().replace("\\", "/"); + } else { + dir = f.getAbsolutePath().replace("\\", "/"); + dir = new File(dir).getParent(); + } + dir += "/" + getReporter().getReporterName(); + return new File(dir); + } + + private String[] combine(String[]... array) { + String[] result = new String[] {}; + for (String[] arr : array) { + result = Stream.of(result, arr).flatMap(Stream::of).toArray(String[]::new); + } + return result; + } + + private String[] getJSFiles() { + String commonsPath = "commons/js/"; + String reporterPath = getReporter().getReporterName() + "/js/"; + String[] files = { commonsPath + "attr.js", commonsPath + "dashboard.js", reporterPath + "logger-scripts.js" }; + return files; + } + + private String[] getCSSFiles() { + String stylesPath = "css/"; + String reporterPath = getReporter().getReporterName() + "/" + stylesPath + "/"; + String[] files = { reporterPath + "logger-style.css", }; + return files; + } + + private String[] getIconFiles() { + String path = "commons/css/icons/"; + String iconDirPath = "fontawesome/"; + String[] files = { path + "font-awesome.min.css", path + iconDirPath + "fontawesome-webfont.eot", + path + iconDirPath + "fontawesome-webfont.svg", path + iconDirPath + "fontawesome-webfont.ttf", + path + iconDirPath + "fontawesome-webfont.woff", path + iconDirPath + "fontawesome-webfont.woff2", + path + iconDirPath + "FontAwesome.otf", }; + return files; + } + + private String[] getImgFiles() { + String path = "commons/img/"; + String[] files = { path + "logo.png" }; + return files; + } + +} diff --git a/src/main/java/com/aventstack/extentreports/reporter/configuration/ExtentSparkReporterConfiguration.java b/src/main/java/com/aventstack/extentreports/reporter/configuration/ExtentSparkReporterConfiguration.java index af9da95..2ba9185 100644 --- a/src/main/java/com/aventstack/extentreports/reporter/configuration/ExtentSparkReporterConfiguration.java +++ b/src/main/java/com/aventstack/extentreports/reporter/configuration/ExtentSparkReporterConfiguration.java @@ -1,15 +1,89 @@ package com.aventstack.extentreports.reporter.configuration; +import java.io.File; +import java.util.stream.Stream; + +import com.aventstack.extentreports.ExtentReports; +import com.aventstack.extentreports.offline.OfflineResxDelegate; import com.aventstack.extentreports.reporter.ExtentSparkReporter; +import com.aventstack.extentreports.utils.FileUtil; /** * Defines configuration settings for the Spark reporter */ -public class ExtentSparkReporterConfiguration - extends RichViewReporterConfiguration { +public class ExtentSparkReporterConfiguration extends RichViewReporterConfiguration { - public ExtentSparkReporterConfiguration(ExtentSparkReporter reporter) { + public ExtentSparkReporterConfiguration(ExtentSparkReporter reporter) { super(reporter); } -} + /** + * Creates the HTML report, saving all resources (css, js, fonts) in the same + * location, so the report can be viewed without an internet connection + * + * @param offline Setting to enable an offline accessible report + */ + public void enableOfflineMode(Boolean offline) { + getConfigurationStore().storeConfig("enableOfflineMode", String.valueOf(offline)); + getConfigurationStore().storeConfig("offlineDirectory", getReporter().getReporterName() + "/"); + if (offline) { + File f = getTargetDirectory(((ExtentSparkReporter) getReporter()).getFileFile()); + String s = "/"; + String resourcePackagePath = ExtentReports.class.getPackage().getName().replace(".", s); + resourcePackagePath += s + "offline" + s; + String[] resx = combine(getJSFiles(), getCSSFiles(), getIconFiles(), getImgFiles()); + OfflineResxDelegate.saveOfflineResources(resourcePackagePath, resx, f.getAbsolutePath()); + } + } + + private File getTargetDirectory(File f) { + String dir; + if (FileUtil.isDirectory(f)) { + dir = f.getAbsolutePath().replace("\\", "/"); + } else { + dir = f.getAbsolutePath().replace("\\", "/"); + dir = new File(dir).getParent(); + } + dir += "/" + getReporter().getReporterName(); + return new File(dir); + } + + private String[] combine(String[]... array) { + String[] result = new String[] {}; + for (String[] arr : array) { + result = Stream.of(result, arr).flatMap(Stream::of).toArray(String[]::new); + } + return result; + } + + private String[] getJSFiles() { + String commonsPath = "commons/js/"; + String reporterPath = getReporter().getReporterName() + "/js/"; + String[] files = { reporterPath + "spark-script.js", commonsPath + "jsontree.js" }; + return files; + } + + private String[] getCSSFiles() { + String stylesPath = "css/"; + String reporterPath = getReporter().getReporterName() + "/" + stylesPath; + String[] files = { reporterPath + "spark-style.css" }; + return files; + } + + private String[] getIconFiles() { + String path = "commons/css/icons/"; + String iconDirPath = "fontawesome/"; + String[] files = { path + "font-awesome.min.css", path + iconDirPath + "fontawesome-webfont.eot", + path + iconDirPath + "fontawesome-webfont.svg", path + iconDirPath + "fontawesome-webfont.ttf", + path + iconDirPath + "fontawesome-webfont.woff", path + iconDirPath + "fontawesome-webfont.woff2", + path + iconDirPath + "FontAwesome.otf" }; + return files; + } + + private String[] getImgFiles() { + String path = "commons/img/"; + String[] files = { path + "logo.png" }; + return files; + } + +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/reporter/configuration/IReporterConfiguration.java b/src/main/java/com/aventstack/extentreports/reporter/configuration/IReporterConfiguration.java index f7fef8b..9cac8d2 100644 --- a/src/main/java/com/aventstack/extentreports/reporter/configuration/IReporterConfiguration.java +++ b/src/main/java/com/aventstack/extentreports/reporter/configuration/IReporterConfiguration.java @@ -1,3 +1,5 @@ package com.aventstack.extentreports.reporter.configuration; -public interface IReporterConfiguration { } +public interface IReporterConfiguration { + +} diff --git a/src/main/java/com/aventstack/extentreports/reporter/configuration/Protocol.java b/src/main/java/com/aventstack/extentreports/reporter/configuration/Protocol.java index 225e39f..6818afa 100644 --- a/src/main/java/com/aventstack/extentreports/reporter/configuration/Protocol.java +++ b/src/main/java/com/aventstack/extentreports/reporter/configuration/Protocol.java @@ -1,9 +1,8 @@ package com.aventstack.extentreports.reporter.configuration; /** - * Protocol used to download CDN css/js resources for HTML reports + * Protocol used to download CDN css/js resources for HTML reports */ public enum Protocol { - HTTP, - HTTPS -} + HTTP, HTTPS +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/reporter/configuration/ResourceCDN.java b/src/main/java/com/aventstack/extentreports/reporter/configuration/ResourceCDN.java deleted file mode 100644 index e9de0bd..0000000 --- a/src/main/java/com/aventstack/extentreports/reporter/configuration/ResourceCDN.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.aventstack.extentreports.reporter.configuration; - -/** - * Allows selecting a CDN/resource loader for your FileReporter - * - * Note: Some hosts do not allow loading resources via HTTPS protocol: - * - *
    - *
  • ExtentReports
  • - *
- * - */ -public enum ResourceCDN { - GITHUB, - EXTENTREPORTS -} diff --git a/src/main/java/com/aventstack/extentreports/reporter/configuration/RichViewReporterConfiguration.java b/src/main/java/com/aventstack/extentreports/reporter/configuration/RichViewReporterConfiguration.java index d627d10..f1c468b 100644 --- a/src/main/java/com/aventstack/extentreports/reporter/configuration/RichViewReporterConfiguration.java +++ b/src/main/java/com/aventstack/extentreports/reporter/configuration/RichViewReporterConfiguration.java @@ -6,91 +6,56 @@ * Contains configuration for rich reporters such as Avent, Tabular, Cards etc. * */ -public abstract class RichViewReporterConfiguration - extends BasicFileConfiguration - implements IReporterConfiguration { - - private Protocol protocol; - private Theme theme; - +public abstract class RichViewReporterConfiguration extends BasicFileConfiguration implements IReporterConfiguration { + protected RichViewReporterConfiguration(AbstractReporter reporter) { super(reporter); } - - /** - * Sets the protocol of accessing CSS/JS resources from CDN - * - *

- * Default protocol value: HTTPS - *

- * - * @param protocol Protocol, HTTPS or HTTP - */ - public void setProtocol(Protocol protocol) { - usedConfigs.put("protocol", String.valueOf(protocol).toLowerCase()); - this.protocol = protocol; - } - - public Protocol getProtocol() { - return protocol; - } - - /** - * Sets the {@link Theme} of the report - * - * @param theme {@link Theme} - */ - public void setTheme(Theme theme) { - usedConfigs.put("theme", String.valueOf(theme).toLowerCase()); - this.theme = theme; - } - - public Theme getTheme() { - return theme; - } - - /** - * Enable or disable the Timeline section in the Dashboard view - * - * @param v Setting to enable or disable the Timeline section in the Dashboard - * view - */ - public void enableTimeline(boolean v) { - usedConfigs.put("enableTimeline", String.valueOf(v)); - } - + /** - * Setting to automatically store screen shots relative to the path. This method - * also sets the new relative path as a link from the report. Example: - * - *
-	 * /
-	 *   Report.html
-	 *   Report.0
-	 *     - 1.png
-	 *     - 2.png
-	 *   Report.1
-	 *     - 1.png
-	 *     - 2.png
-	 * 
+ * Sets the protocol of accessing CSS/JS resources from CDN * *

- * Report.0 directory will contain media from the 1st run. Report.1 directory - * will contain media from the 2nd run. + * Default protocol value: HTTPS *

* - * @param v Setting to enable this feature + * @param protocol Protocol, HTTPS or HTTP */ - public void setAutoCreateRelativePathMedia(boolean v) { - usedConfigs.put("autoCreateRelativePathMedia", String.valueOf(v)); + public void setProtocol(Protocol protocol) { + getConfigurationStore().storeConfig("protocol", String.valueOf(protocol).toLowerCase()); + } + + public Protocol getProtocol() { + if (getConfigurationStore().containsConfig("protocol")) { + return (Protocol) getConfigurationStore().getConfig("protocol"); + } + return null; } - + /** - * Allows selecting a CDN/resource loader for your FileReporter + * Sets the {@link Theme} of the report * - * @param resourceCDN the {@link ResourceCDN} + * @param theme {@link Theme} + */ + public void setTheme(Theme theme) { + getConfigurationStore().storeConfig("theme", String.valueOf(theme).toLowerCase()); + } + + public Theme getTheme() { + if (getConfigurationStore().containsConfig("theme")) { + return Theme.valueOf(getConfigurationStore().getConfig("theme").toString()); + } + return null; + } + + /** + * Enable or disable the Timeline section in the Dashboard view + * + * @param v Setting to enable or disable the Timeline section in the Dashboard + * view */ - public void setResourceCDN(ResourceCDN resourceCDN) { - usedConfigs.put("resourceCDN", String.valueOf(resourceCDN).toLowerCase()); - } -} + public void enableTimeline(boolean v) { + getConfigurationStore().storeConfig("enableTimeline", String.valueOf(v).toLowerCase()); + } + +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/reporter/configuration/Theme.java b/src/main/java/com/aventstack/extentreports/reporter/configuration/Theme.java index c3e1bdc..7f0a8dc 100644 --- a/src/main/java/com/aventstack/extentreports/reporter/configuration/Theme.java +++ b/src/main/java/com/aventstack/extentreports/reporter/configuration/Theme.java @@ -1,9 +1,8 @@ package com.aventstack.extentreports.reporter.configuration; /** - * Available themes for the HTML reporter + * Available themes for the HTML reporter */ public enum Theme { - STANDARD, - DARK -} + STANDARD, DARK +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/reporter/configuration/ViewStyle.java b/src/main/java/com/aventstack/extentreports/reporter/configuration/ViewStyle.java new file mode 100644 index 0000000..914608e --- /dev/null +++ b/src/main/java/com/aventstack/extentreports/reporter/configuration/ViewStyle.java @@ -0,0 +1,5 @@ +package com.aventstack.extentreports.reporter.configuration; + +public enum ViewStyle { + DEFAULT, SPA +} diff --git a/src/main/java/com/aventstack/extentreports/templating/FreemarkerTemplate.java b/src/main/java/com/aventstack/extentreports/templating/FreemarkerTemplate.java new file mode 100644 index 0000000..7ce39e2 --- /dev/null +++ b/src/main/java/com/aventstack/extentreports/templating/FreemarkerTemplate.java @@ -0,0 +1,59 @@ +package com.aventstack.extentreports.templating; + +import java.io.File; +import java.io.IOException; +import java.io.StringWriter; +import java.util.Map; + +import com.aventstack.extentreports.io.FileWriterBuffered; + +import freemarker.core.ParseException; +import freemarker.template.Configuration; +import freemarker.template.MalformedTemplateNameException; +import freemarker.template.Template; +import freemarker.template.TemplateException; +import freemarker.template.TemplateNotFoundException; + +public class FreemarkerTemplate { + + private TemplateConfig config = new TemplateConfig(); + private Configuration freemarkerConfiguration; + + public FreemarkerTemplate(Configuration freemarkerConfiguration) { + this.freemarkerConfiguration = freemarkerConfiguration; + } + + public FreemarkerTemplate(Class clazz, String encoding) { + freemarkerConfiguration = config.getFreemarkerConfig(clazz, encoding); + } + + public FreemarkerTemplate(Class clazz, String basePackagePath, String encoding) { + freemarkerConfiguration = config.getFreemarkerConfig(clazz, basePackagePath, encoding); + } + + public Template createTemplate(String templatePath) + throws TemplateNotFoundException, MalformedTemplateNameException, ParseException, IOException { + return freemarkerConfiguration.getTemplate(templatePath); + } + + public String getSource(Template template, Map templateMap) throws TemplateException, IOException { + String source = processTemplate(template, templateMap); + return source; + } + + public void writeTemplate(Template template, Map templateMap, File outputFile) + throws TemplateException, IOException { + String source = getSource(template, templateMap); + FileWriterBuffered.getInstance().write(outputFile, source); + } + + private String processTemplate(Template template, Map templateMap) + throws TemplateException, IOException { + StringWriter out = new StringWriter(); + template.process(templateMap, out); + String source = out.toString(); + out.close(); + return source; + } + +} diff --git a/src/main/java/com/aventstack/extentreports/templating/TemplateConfig.java b/src/main/java/com/aventstack/extentreports/templating/TemplateConfig.java new file mode 100644 index 0000000..508bc00 --- /dev/null +++ b/src/main/java/com/aventstack/extentreports/templating/TemplateConfig.java @@ -0,0 +1,18 @@ +package com.aventstack.extentreports.templating; + +import freemarker.template.Configuration; + +public class TemplateConfig { + + public Configuration getFreemarkerConfig(Class clazz, String basePackagePath, String encoding) { + Configuration cfg = new Configuration(Configuration.VERSION_2_3_29); + cfg.setClassForTemplateLoading(clazz, basePackagePath); + cfg.setDefaultEncoding(encoding); + return cfg; + } + + public Configuration getFreemarkerConfig(Class clazz, String encoding) { + return getFreemarkerConfig(clazz, "/", encoding); + } + +} diff --git a/src/main/java/com/aventstack/extentreports/utils/DateUtil.java b/src/main/java/com/aventstack/extentreports/utils/DateUtil.java deleted file mode 100644 index 27c90c1..0000000 --- a/src/main/java/com/aventstack/extentreports/utils/DateUtil.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.aventstack.extentreports.utils; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.logging.Level; -import java.util.logging.Logger; - -public class DateUtil { - - private static final Logger logger = Logger.getLogger(DateUtil.class.getName()); - - private DateUtil() { } - - public static Date parse(String dt, String format) { - DateFormat df = new SimpleDateFormat(format); - - try { - return df.parse(dt); - } catch (Exception e) { - logger.log(Level.SEVERE, "", e); - return null; - } - } - -} diff --git a/src/main/java/com/aventstack/extentreports/utils/ExceptionUtil.java b/src/main/java/com/aventstack/extentreports/utils/ExceptionUtil.java index b4d7803..81c03eb 100644 --- a/src/main/java/com/aventstack/extentreports/utils/ExceptionUtil.java +++ b/src/main/java/com/aventstack/extentreports/utils/ExceptionUtil.java @@ -6,27 +6,28 @@ import java.util.regex.Pattern; public class ExceptionUtil { - - private ExceptionUtil() { } - - public static String getStackTrace(Throwable t) { - if (t == null) - return null; - - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - t.printStackTrace(pw); - return sw.toString(); - } - - public static String getExceptionHeadline(Throwable t) { - Pattern pattern = Pattern.compile("([\\w\\.]+)(:.*)?"); - String stackTrace = getStackTrace(t); - Matcher matcher = pattern.matcher(stackTrace); - - if (matcher.find()) - return matcher.group(1); - - return null; - } -} + + private ExceptionUtil() { + } + + public static String getStackTrace(Throwable t) { + if (t == null) + return null; + + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + t.printStackTrace(pw); + return sw.toString(); + } + + public static String getExceptionHeadline(Throwable t) { + Pattern pattern = Pattern.compile("([\\w\\.]+)(:.*)?"); + String stackTrace = getStackTrace(t); + Matcher matcher = pattern.matcher(stackTrace); + + if (matcher.find()) + return matcher.group(1); + + return null; + } +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/utils/FileUtil.java b/src/main/java/com/aventstack/extentreports/utils/FileUtil.java index 44790ef..32a1a62 100644 --- a/src/main/java/com/aventstack/extentreports/utils/FileUtil.java +++ b/src/main/java/com/aventstack/extentreports/utils/FileUtil.java @@ -6,71 +6,72 @@ import java.util.Arrays; public class FileUtil { - - private FileUtil() { } - - public static String getFileName(File f) { - if (f == null || !f.exists()) - return ""; - return f.getName(); - } - - public static String getFileName(String path) { - return getFileName(new File(path)); - } - - public static String getFileNameWithoutExtension(File f) { - String name = f.getName(); - int i = name.lastIndexOf('.'); - if (i > 0) - return name.substring(0, i); - - return name; - } - - public static String getFileNameWithoutExtension(String filePath) { - return getFileNameWithoutExtension(new File(filePath)); - } - - public static String getExtension(File f) { - String name = f.getName(); - int i = name.lastIndexOf('.'); - if (i > 0) - return name.substring(i + 1); - return ""; - } - - public static String getExtension(String filePath) { - return getExtension(new File(filePath)); - } - - public static Boolean isDirectory(String filePath) { - return isDirectory(new File(filePath)); - } - - public static Boolean isDirectory(File file) { - Path path = file.toPath(); - return Files.isDirectory(path); - } - - public static void createDirectory(String path) { - new File(path).mkdirs(); - } - - public static void createDirectory(String[] path) { - Arrays.asList(path).forEach(FileUtil::createDirectory); - } - - public static Boolean fileExists(String path) { - File f = new File(path); - return f.exists() && !f.isDirectory(); - } - - public static long getFileSize(String path) { - if (path == null) - return 0; - File f = new File(path); - return f.exists() ? f.length() : 0; - } - -} + + private FileUtil() { + } + + public static String getFileName(File f) { + if (f == null || !f.exists()) + return ""; + return f.getName(); + } + + public static String getFileName(String path) { + return getFileName(new File(path)); + } + + public static String getFileNameWithoutExtension(File f) { + String name = f.getName(); + int i = name.lastIndexOf('.'); + if (i > 0) + return name.substring(0, i); + + return name; + } + + public static String getFileNameWithoutExtension(String filePath) { + return getFileNameWithoutExtension(new File(filePath)); + } + + public static String getExtension(File f) { + String name = f.getName(); + int i = name.lastIndexOf('.'); + if (i > 0) + return name.substring(i + 1); + return ""; + } + + public static String getExtension(String filePath) { + return getExtension(new File(filePath)); + } + + public static Boolean isDirectory(String filePath) { + return isDirectory(new File(filePath)); + } + + public static Boolean isDirectory(File file) { + Path path = file.toPath(); + return Files.isDirectory(path); + } + + public static void createDirectory(String path) { + new File(path).mkdirs(); + } + + public static void createDirectory(String[] path) { + Arrays.asList(path).forEach(FileUtil::createDirectory); + } + + public static Boolean fileExists(String path) { + File f = new File(path); + return f.exists() && !f.isDirectory(); + } + + public static long getFileSize(String path) { + if (path == null) + return 0; + File f = new File(path); + return f.exists() ? f.length() : 0; + } + +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/utils/IntUtils.java b/src/main/java/com/aventstack/extentreports/utils/IntUtil.java similarity index 84% rename from src/main/java/com/aventstack/extentreports/utils/IntUtils.java rename to src/main/java/com/aventstack/extentreports/utils/IntUtil.java index 200cd7e..4ec796b 100644 --- a/src/main/java/com/aventstack/extentreports/utils/IntUtils.java +++ b/src/main/java/com/aventstack/extentreports/utils/IntUtil.java @@ -1,8 +1,8 @@ package com.aventstack.extentreports.utils; -public class IntUtils { +public class IntUtil { - private IntUtils() { + private IntUtil() { } public static boolean tryParseInt(String value) { @@ -14,4 +14,4 @@ public static boolean tryParseInt(String value) { } } -} +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/utils/MongoUtil.java b/src/main/java/com/aventstack/extentreports/utils/MongoUtil.java index 1810e9e..085b7dc 100644 --- a/src/main/java/com/aventstack/extentreports/utils/MongoUtil.java +++ b/src/main/java/com/aventstack/extentreports/utils/MongoUtil.java @@ -4,11 +4,12 @@ import org.bson.types.ObjectId; public class MongoUtil { - - private MongoUtil() { } - - public static ObjectId getId(Document doc) { - return (ObjectId) doc.get("_id"); - } - -} + + private MongoUtil() { + } + + public static ObjectId getId(Document doc) { + return (ObjectId) doc.get("_id"); + } + +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/utils/Reader.java b/src/main/java/com/aventstack/extentreports/utils/Reader.java deleted file mode 100644 index 9bff617..0000000 --- a/src/main/java/com/aventstack/extentreports/utils/Reader.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.aventstack.extentreports.utils; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.util.logging.Level; -import java.util.logging.Logger; - -public class Reader { - - final static Logger logger = Logger.getLogger(Reader.class.getName()); - - private Reader() { } - - public static String readAllText(String filePath) { - File file = new File(filePath); - - if (file.exists()) { - byte[] data; - - try (FileInputStream fis = new FileInputStream(file)) { - data = new byte[(int)file.length()]; - fis.read(data); - - return new String(data, "UTF-8"); - } - catch (IOException e) { - logger.log(Level.SEVERE, filePath, e); - } - } - - return null; - } - - public static String readAllText(File file) { - return readAllText(file.getAbsolutePath()); - } -} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/utils/ResourceUtil.java b/src/main/java/com/aventstack/extentreports/utils/ResourceUtil.java deleted file mode 100644 index c8aeebe..0000000 --- a/src/main/java/com/aventstack/extentreports/utils/ResourceUtil.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.aventstack.extentreports.utils; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; - -public class ResourceUtil { - - public static void moveResource(String resourcePath, String copyPath) { - if (copyPath != null) - copyPath = copyPath.replace("\\", "/"); - if (resourcePath != null) - resourcePath = resourcePath.replace("\\", "/"); - - try { - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - InputStream in = classLoader.getResourceAsStream(resourcePath); - - FileOutputStream out = new FileOutputStream(copyPath); - - byte[] b = new byte[1024]; - int noOfBytes = 0; - - while( (noOfBytes = in.read(b)) != -1 ) { - out.write(b, 0, noOfBytes); - } - - in.close(); - out.close(); - } - catch (FileNotFoundException e) { - e.printStackTrace(); - } - catch (IOException e) { - e.printStackTrace(); - } - } - - public static void moveBinaryFile(String resourcePath, String copyPath) { - URI uri = new File(resourcePath).toURI(); - Path path = Paths.get(uri); - try { - Files.copy(path, new File(copyPath).toPath(), StandardCopyOption.REPLACE_EXISTING); - } catch (IOException e) { - e.printStackTrace(); - } - } - -} diff --git a/src/main/java/com/aventstack/extentreports/utils/StringUtil.java b/src/main/java/com/aventstack/extentreports/utils/StringUtil.java index 1f2d125..8edf83b 100644 --- a/src/main/java/com/aventstack/extentreports/utils/StringUtil.java +++ b/src/main/java/com/aventstack/extentreports/utils/StringUtil.java @@ -1,14 +1,15 @@ package com.aventstack.extentreports.utils; public class StringUtil { - - private StringUtil() { } - - public static String capitalize(String s) { - return Character.toLowerCase(s.charAt(0)) + s.substring(1); - } - - public static boolean isNotNullOrEmpty (String str) { + + private StringUtil() { + } + + public static String capitalize(String s) { + return Character.toLowerCase(s.charAt(0)) + s.substring(1); + } + + public static boolean isNotNullOrEmpty(String str) { return str != null && !str.trim().isEmpty(); - } -} + } +} \ No newline at end of file diff --git a/src/main/java/com/aventstack/extentreports/utils/Writer.java b/src/main/java/com/aventstack/extentreports/utils/Writer.java deleted file mode 100644 index ac0844d..0000000 --- a/src/main/java/com/aventstack/extentreports/utils/Writer.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.aventstack.extentreports.utils; - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.util.logging.Level; -import java.util.logging.Logger; - -public class Writer { - - private static class WriterInstance { - static final Writer INSTANCE = new Writer(); - - private WriterInstance() { } - } - - static final Logger logger = Logger.getLogger(Writer.class.getName()); - - private Writer() { } - - public synchronized void write(final File f, String text) { - try (BufferedWriter writer = new BufferedWriter(new FileWriter(f))) { - writer.write(text); - } - catch (Exception e) { - logger.log(Level.SEVERE, f.getPath(), e); - } - } - - public static Writer getInstance() { - return WriterInstance.INSTANCE; - } - -} \ No newline at end of file diff --git a/src/main/resources/com/aventstack/extentreports/markup/codeblock.ftl b/src/main/resources/com/aventstack/extentreports/markup/codeblock.ftl new file mode 100644 index 0000000..a0e209c --- /dev/null +++ b/src/main/resources/com/aventstack/extentreports/markup/codeblock.ftl @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/src/main/resources/com/aventstack/extentreports/markup/codeblock.json.ftl b/src/main/resources/com/aventstack/extentreports/markup/codeblock.json.ftl new file mode 100644 index 0000000..36074fa --- /dev/null +++ b/src/main/resources/com/aventstack/extentreports/markup/codeblock.json.ftl @@ -0,0 +1,9 @@ + \ No newline at end of file diff --git a/src/main/resources/com/aventstack/extentreports/offline/commons/js/jsontree.js b/src/main/resources/com/aventstack/extentreports/offline/commons/js/jsontree.js new file mode 100644 index 0000000..a539d1b --- /dev/null +++ b/src/main/resources/com/aventstack/extentreports/offline/commons/js/jsontree.js @@ -0,0 +1,2 @@ +/*! json-tree - v0.2.2 - 2017-09-25, MIT LICENSE */ +var JSONTree=function(){var n={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"},t=0,r=0;this.create=function(n,t){return r+=1,N(u(n,0,!1),{class:"jstValue"})};var e=function(t){return t.replace(/[&<>'"]/g,function(t){return n[t]})},s=function(){return r+"_"+t++},u=function(n,t,r){if(null===n)return f(r?t:0);switch(typeof n){case"boolean":return l(n,r?t:0);case"number":return i(n,r?t:0);case"string":return o(n,r?t:0);default:return n instanceof Array?a(n,t,r):c(n,t,r)}},c=function(n,t,r){var e=s(),u=Object.keys(n).map(function(r){return j(r,n[r],t+1,!0)}).join(m()),c=[g("{",r?t:0,e),N(u,{id:e}),p("}",t)].join("\n");return N(c,{})},a=function(n,t,r){var e=s(),c=n.map(function(n){return u(n,t+1,!0)}).join(m());return[g("[",r?t:0,e),N(c,{id:e}),p("]",t)].join("\n")},o=function(n,t){var r=e(JSON.stringify(n));return N(v(r,t),{class:"jstStr"})},i=function(n,t){return N(v(n,t),{class:"jstNum"})},l=function(n,t){return N(v(n,t),{class:"jstBool"})},f=function(n){return N(v("null",n),{class:"jstNull"})},j=function(n,t,r){var s=v(e(JSON.stringify(n))+": ",r),c=N(u(t,r,!1),{});return N(s+c,{class:"jstProperty"})},m=function(){return N(",\n",{class:"jstComma"})},N=function(n,t){return d("span",t,n)},d=function(n,t,r){return"<"+n+Object.keys(t).map(function(n){return" "+n+'="'+t[n]+'"'}).join("")+">"+r+""},g=function(n,t,r){return N(v(n,t),{class:"jstBracket"})+N("",{class:"jstFold",onclick:"JSONTree.toggle('"+r+"')"})};this.toggle=function(n){var t=document.getElementById(n),r=t.parentNode,e=t.previousElementSibling;""===t.className?(t.className="jstHiddenBlock",r.className="jstFolded",e.className="jstExpand"):(t.className="",r.className="",e.className="jstFold")};var p=function(n,t){return N(v(n,t),{})},v=function(n,t){return Array(2*t+1).join(" ")+n};return this}(); diff --git a/src/main/resources/com/aventstack/extentreports/offline/spark/css/spark-style.css b/src/main/resources/com/aventstack/extentreports/offline/spark/css/spark-style.css new file mode 100644 index 0000000..5ab7ae0 --- /dev/null +++ b/src/main/resources/com/aventstack/extentreports/offline/spark/css/spark-style.css @@ -0,0 +1,506 @@ +@import url("https://fonts.googleapis.com/css?family=Roboto:400,500"); + +/*! + * 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 */ + +/* perfect-scrollbar v0.6.16 */ +.ps-container{-ms-touch-action:auto;touch-action:auto;overflow:hidden !important;-ms-overflow-style:none}@supports (-ms-overflow-style: none){.ps-container{overflow:auto !important}}@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none){.ps-container{overflow:auto !important}}.ps-container.ps-active-x>.ps-scrollbar-x-rail,.ps-container.ps-active-y>.ps-scrollbar-y-rail{display:block;background-color:transparent}.ps-container.ps-in-scrolling.ps-x>.ps-scrollbar-x-rail{background-color:#eee;opacity:.9}.ps-container.ps-in-scrolling.ps-x>.ps-scrollbar-x-rail>.ps-scrollbar-x{background-color:#999;height:11px}.ps-container.ps-in-scrolling.ps-y>.ps-scrollbar-y-rail{background-color:#eee;opacity:.9}.ps-container.ps-in-scrolling.ps-y>.ps-scrollbar-y-rail>.ps-scrollbar-y{background-color:#999;width:11px}.ps-container>.ps-scrollbar-x-rail{display:none;position:absolute;opacity:0;-webkit-transition:background-color .2s linear, opacity .2s linear;-o-transition:background-color .2s linear, opacity .2s linear;-moz-transition:background-color .2s linear, opacity .2s linear;transition:background-color .2s linear, opacity .2s linear;bottom:0px;height:15px}.ps-container>.ps-scrollbar-x-rail>.ps-scrollbar-x{position:absolute;background-color:#aaa;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, -webkit-border-radius .2s ease-in-out;transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, -webkit-border-radius .2s ease-in-out;-o-transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out;-moz-transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out, -moz-border-radius .2s ease-in-out;transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out;transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out, -webkit-border-radius .2s ease-in-out, -moz-border-radius .2s ease-in-out;bottom:2px;height:6px}.ps-container>.ps-scrollbar-x-rail:hover>.ps-scrollbar-x,.ps-container>.ps-scrollbar-x-rail:active>.ps-scrollbar-x{height:11px}.ps-container>.ps-scrollbar-y-rail{display:none;position:absolute;opacity:0;-webkit-transition:background-color .2s linear, opacity .2s linear;-o-transition:background-color .2s linear, opacity .2s linear;-moz-transition:background-color .2s linear, opacity .2s linear;transition:background-color .2s linear, opacity .2s linear;right:0;width:15px}.ps-container>.ps-scrollbar-y-rail>.ps-scrollbar-y{position:absolute;background-color:#aaa;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, -webkit-border-radius .2s ease-in-out;transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, -webkit-border-radius .2s ease-in-out;-o-transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out;-moz-transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out, -moz-border-radius .2s ease-in-out;transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out;transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out, -webkit-border-radius .2s ease-in-out, -moz-border-radius .2s ease-in-out;right:2px;width:6px}.ps-container>.ps-scrollbar-y-rail:hover>.ps-scrollbar-y,.ps-container>.ps-scrollbar-y-rail:active>.ps-scrollbar-y{width:11px}.ps-container:hover.ps-in-scrolling.ps-x>.ps-scrollbar-x-rail{background-color:#eee;opacity:.9}.ps-container:hover.ps-in-scrolling.ps-x>.ps-scrollbar-x-rail>.ps-scrollbar-x{background-color:#999;height:11px}.ps-container:hover.ps-in-scrolling.ps-y>.ps-scrollbar-y-rail{background-color:#eee;opacity:.9}.ps-container:hover.ps-in-scrolling.ps-y>.ps-scrollbar-y-rail>.ps-scrollbar-y{background-color:#999;width:11px}.ps-container:hover>.ps-scrollbar-x-rail,.ps-container:hover>.ps-scrollbar-y-rail{opacity:.6}.ps-container:hover>.ps-scrollbar-x-rail:hover{background-color:#eee;opacity:.9}.ps-container:hover>.ps-scrollbar-x-rail:hover>.ps-scrollbar-x{background-color:#999}.ps-container:hover>.ps-scrollbar-y-rail:hover{background-color:#eee;opacity:.9}.ps-container:hover>.ps-scrollbar-y-rail:hover>.ps-scrollbar-y{background-color:#999} + +@charset "UTF-8"; + +/*! + * animate.css -http://daneden.me/animate + * Version - 3.7.0 + * Licensed under the MIT license - http://opensource.org/licenses/MIT + * + * Copyright (c) 2018 Daniel Eden + */ + +@-webkit-keyframes bounce{0%,20%,53%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);-webkit-transform:translateZ(0);animation-timing-function:cubic-bezier(.215,.61,.355,1);transform:translateZ(0)}40%,43%{-webkit-animation-timing-function:cubic-bezier(.755,.05,.855,.06);-webkit-transform:translate3d(0,-30px,0);animation-timing-function:cubic-bezier(.755,.05,.855,.06);transform:translate3d(0,-30px,0)}70%{-webkit-animation-timing-function:cubic-bezier(.755,.05,.855,.06);-webkit-transform:translate3d(0,-15px,0);animation-timing-function:cubic-bezier(.755,.05,.855,.06);transform:translate3d(0,-15px,0)}90%{-webkit-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0)}}@keyframes bounce{0%,20%,53%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);-webkit-transform:translateZ(0);animation-timing-function:cubic-bezier(.215,.61,.355,1);transform:translateZ(0)}40%,43%{-webkit-animation-timing-function:cubic-bezier(.755,.05,.855,.06);-webkit-transform:translate3d(0,-30px,0);animation-timing-function:cubic-bezier(.755,.05,.855,.06);transform:translate3d(0,-30px,0)}70%{-webkit-animation-timing-function:cubic-bezier(.755,.05,.855,.06);-webkit-transform:translate3d(0,-15px,0);animation-timing-function:cubic-bezier(.755,.05,.855,.06);transform:translate3d(0,-15px,0)}90%{-webkit-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0)}}.bounce{-webkit-animation-name:bounce;-webkit-transform-origin:center bottom;animation-name:bounce;transform-origin:center bottom}@-webkit-keyframes flash{0%,50%,to{opacity:1}25%,75%{opacity:0}}@keyframes flash{0%,50%,to{opacity:1}25%,75%{opacity:0}}.flash{-webkit-animation-name:flash;animation-name:flash}@-webkit-keyframes pulse{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}50%{-webkit-transform:scale3d(1.05,1.05,1.05);transform:scale3d(1.05,1.05,1.05)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}@keyframes pulse{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}50%{-webkit-transform:scale3d(1.05,1.05,1.05);transform:scale3d(1.05,1.05,1.05)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}.pulse{-webkit-animation-name:pulse;animation-name:pulse}@-webkit-keyframes rubberBand{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}30%{-webkit-transform:scale3d(1.25,.75,1);transform:scale3d(1.25,.75,1)}40%{-webkit-transform:scale3d(.75,1.25,1);transform:scale3d(.75,1.25,1)}50%{-webkit-transform:scale3d(1.15,.85,1);transform:scale3d(1.15,.85,1)}65%{-webkit-transform:scale3d(.95,1.05,1);transform:scale3d(.95,1.05,1)}75%{-webkit-transform:scale3d(1.05,.95,1);transform:scale3d(1.05,.95,1)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}@keyframes rubberBand{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}30%{-webkit-transform:scale3d(1.25,.75,1);transform:scale3d(1.25,.75,1)}40%{-webkit-transform:scale3d(.75,1.25,1);transform:scale3d(.75,1.25,1)}50%{-webkit-transform:scale3d(1.15,.85,1);transform:scale3d(1.15,.85,1)}65%{-webkit-transform:scale3d(.95,1.05,1);transform:scale3d(.95,1.05,1)}75%{-webkit-transform:scale3d(1.05,.95,1);transform:scale3d(1.05,.95,1)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}.rubberBand{-webkit-animation-name:rubberBand;animation-name:rubberBand}@-webkit-keyframes shake{0%,to{-webkit-transform:translateZ(0);transform:translateZ(0)}10%,30%,50%,70%,90%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}20%,40%,60%,80%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}}@keyframes shake{0%,to{-webkit-transform:translateZ(0);transform:translateZ(0)}10%,30%,50%,70%,90%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}20%,40%,60%,80%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}}.shake{-webkit-animation-name:shake;animation-name:shake}@-webkit-keyframes headShake{0%{-webkit-transform:translateX(0);transform:translateX(0)}6.5%{-webkit-transform:translateX(-6px) rotateY(-9deg);transform:translateX(-6px) rotateY(-9deg)}18.5%{-webkit-transform:translateX(5px) rotateY(7deg);transform:translateX(5px) rotateY(7deg)}31.5%{-webkit-transform:translateX(-3px) rotateY(-5deg);transform:translateX(-3px) rotateY(-5deg)}43.5%{-webkit-transform:translateX(2px) rotateY(3deg);transform:translateX(2px) rotateY(3deg)}50%{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes headShake{0%{-webkit-transform:translateX(0);transform:translateX(0)}6.5%{-webkit-transform:translateX(-6px) rotateY(-9deg);transform:translateX(-6px) rotateY(-9deg)}18.5%{-webkit-transform:translateX(5px) rotateY(7deg);transform:translateX(5px) rotateY(7deg)}31.5%{-webkit-transform:translateX(-3px) rotateY(-5deg);transform:translateX(-3px) rotateY(-5deg)}43.5%{-webkit-transform:translateX(2px) rotateY(3deg);transform:translateX(2px) rotateY(3deg)}50%{-webkit-transform:translateX(0);transform:translateX(0)}}.headShake{-webkit-animation-name:headShake;-webkit-animation-timing-function:ease-in-out;animation-name:headShake;animation-timing-function:ease-in-out}@-webkit-keyframes swing{20%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}40%{-webkit-transform:rotate(-10deg);transform:rotate(-10deg)}60%{-webkit-transform:rotate(5deg);transform:rotate(5deg)}80%{-webkit-transform:rotate(-5deg);transform:rotate(-5deg)}to{-webkit-transform:rotate(0deg);transform:rotate(0deg)}}@keyframes swing{20%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}40%{-webkit-transform:rotate(-10deg);transform:rotate(-10deg)}60%{-webkit-transform:rotate(5deg);transform:rotate(5deg)}80%{-webkit-transform:rotate(-5deg);transform:rotate(-5deg)}to{-webkit-transform:rotate(0deg);transform:rotate(0deg)}}.swing{-webkit-animation-name:swing;-webkit-transform-origin:top center;animation-name:swing;transform-origin:top center}@-webkit-keyframes tada{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}10%,20%{-webkit-transform:scale3d(.9,.9,.9) rotate(-3deg);transform:scale3d(.9,.9,.9) rotate(-3deg)}30%,50%,70%,90%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate(3deg);transform:scale3d(1.1,1.1,1.1) rotate(3deg)}40%,60%,80%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate(-3deg);transform:scale3d(1.1,1.1,1.1) rotate(-3deg)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}@keyframes tada{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}10%,20%{-webkit-transform:scale3d(.9,.9,.9) rotate(-3deg);transform:scale3d(.9,.9,.9) rotate(-3deg)}30%,50%,70%,90%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate(3deg);transform:scale3d(1.1,1.1,1.1) rotate(3deg)}40%,60%,80%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate(-3deg);transform:scale3d(1.1,1.1,1.1) rotate(-3deg)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}.tada{-webkit-animation-name:tada;animation-name:tada}@-webkit-keyframes wobble{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}15%{-webkit-transform:translate3d(-25%,0,0) rotate(-5deg);transform:translate3d(-25%,0,0) rotate(-5deg)}30%{-webkit-transform:translate3d(20%,0,0) rotate(3deg);transform:translate3d(20%,0,0) rotate(3deg)}45%{-webkit-transform:translate3d(-15%,0,0) rotate(-3deg);transform:translate3d(-15%,0,0) rotate(-3deg)}60%{-webkit-transform:translate3d(10%,0,0) rotate(2deg);transform:translate3d(10%,0,0) rotate(2deg)}75%{-webkit-transform:translate3d(-5%,0,0) rotate(-1deg);transform:translate3d(-5%,0,0) rotate(-1deg)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes wobble{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}15%{-webkit-transform:translate3d(-25%,0,0) rotate(-5deg);transform:translate3d(-25%,0,0) rotate(-5deg)}30%{-webkit-transform:translate3d(20%,0,0) rotate(3deg);transform:translate3d(20%,0,0) rotate(3deg)}45%{-webkit-transform:translate3d(-15%,0,0) rotate(-3deg);transform:translate3d(-15%,0,0) rotate(-3deg)}60%{-webkit-transform:translate3d(10%,0,0) rotate(2deg);transform:translate3d(10%,0,0) rotate(2deg)}75%{-webkit-transform:translate3d(-5%,0,0) rotate(-1deg);transform:translate3d(-5%,0,0) rotate(-1deg)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.wobble{-webkit-animation-name:wobble;animation-name:wobble}@-webkit-keyframes jello{0%,11.1%,to{-webkit-transform:translateZ(0);transform:translateZ(0)}22.2%{-webkit-transform:skewX(-12.5deg) skewY(-12.5deg);transform:skewX(-12.5deg) skewY(-12.5deg)}33.3%{-webkit-transform:skewX(6.25deg) skewY(6.25deg);transform:skewX(6.25deg) skewY(6.25deg)}44.4%{-webkit-transform:skewX(-3.125deg) skewY(-3.125deg);transform:skewX(-3.125deg) skewY(-3.125deg)}55.5%{-webkit-transform:skewX(1.5625deg) skewY(1.5625deg);transform:skewX(1.5625deg) skewY(1.5625deg)}66.6%{-webkit-transform:skewX(-.78125deg) skewY(-.78125deg);transform:skewX(-.78125deg) skewY(-.78125deg)}77.7%{-webkit-transform:skewX(.390625deg) skewY(.390625deg);transform:skewX(.390625deg) skewY(.390625deg)}88.8%{-webkit-transform:skewX(-.1953125deg) skewY(-.1953125deg);transform:skewX(-.1953125deg) skewY(-.1953125deg)}}@keyframes jello{0%,11.1%,to{-webkit-transform:translateZ(0);transform:translateZ(0)}22.2%{-webkit-transform:skewX(-12.5deg) skewY(-12.5deg);transform:skewX(-12.5deg) skewY(-12.5deg)}33.3%{-webkit-transform:skewX(6.25deg) skewY(6.25deg);transform:skewX(6.25deg) skewY(6.25deg)}44.4%{-webkit-transform:skewX(-3.125deg) skewY(-3.125deg);transform:skewX(-3.125deg) skewY(-3.125deg)}55.5%{-webkit-transform:skewX(1.5625deg) skewY(1.5625deg);transform:skewX(1.5625deg) skewY(1.5625deg)}66.6%{-webkit-transform:skewX(-.78125deg) skewY(-.78125deg);transform:skewX(-.78125deg) skewY(-.78125deg)}77.7%{-webkit-transform:skewX(.390625deg) skewY(.390625deg);transform:skewX(.390625deg) skewY(.390625deg)}88.8%{-webkit-transform:skewX(-.1953125deg) skewY(-.1953125deg);transform:skewX(-.1953125deg) skewY(-.1953125deg)}}.jello{-webkit-animation-name:jello;-webkit-transform-origin:center;animation-name:jello;transform-origin:center}@-webkit-keyframes heartBeat{0%{-webkit-transform:scale(1);transform:scale(1)}14%{-webkit-transform:scale(1.3);transform:scale(1.3)}28%{-webkit-transform:scale(1);transform:scale(1)}42%{-webkit-transform:scale(1.3);transform:scale(1.3)}70%{-webkit-transform:scale(1);transform:scale(1)}}@keyframes heartBeat{0%{-webkit-transform:scale(1);transform:scale(1)}14%{-webkit-transform:scale(1.3);transform:scale(1.3)}28%{-webkit-transform:scale(1);transform:scale(1)}42%{-webkit-transform:scale(1.3);transform:scale(1.3)}70%{-webkit-transform:scale(1);transform:scale(1)}}.heartBeat{-webkit-animation-duration:1.3s;-webkit-animation-name:heartBeat;-webkit-animation-timing-function:ease-in-out;animation-duration:1.3s;animation-name:heartBeat;animation-timing-function:ease-in-out}@-webkit-keyframes bounceIn{0%,20%,40%,60%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:scale3d(.3,.3,.3);opacity:0;transform:scale3d(.3,.3,.3)}20%{-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}40%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}60%{-webkit-transform:scale3d(1.03,1.03,1.03);opacity:1;transform:scale3d(1.03,1.03,1.03)}80%{-webkit-transform:scale3d(.97,.97,.97);transform:scale3d(.97,.97,.97)}to{-webkit-transform:scaleX(1);opacity:1;transform:scaleX(1)}}@keyframes bounceIn{0%,20%,40%,60%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:scale3d(.3,.3,.3);opacity:0;transform:scale3d(.3,.3,.3)}20%{-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}40%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}60%{-webkit-transform:scale3d(1.03,1.03,1.03);opacity:1;transform:scale3d(1.03,1.03,1.03)}80%{-webkit-transform:scale3d(.97,.97,.97);transform:scale3d(.97,.97,.97)}to{-webkit-transform:scaleX(1);opacity:1;transform:scaleX(1)}}.bounceIn{-webkit-animation-duration:.75s;-webkit-animation-name:bounceIn;animation-duration:.75s;animation-name:bounceIn}@-webkit-keyframes bounceInDown{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:translate3d(0,-3000px,0);opacity:0;transform:translate3d(0,-3000px,0)}60%{-webkit-transform:translate3d(0,25px,0);opacity:1;transform:translate3d(0,25px,0)}75%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}90%{-webkit-transform:translate3d(0,5px,0);transform:translate3d(0,5px,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes bounceInDown{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:translate3d(0,-3000px,0);opacity:0;transform:translate3d(0,-3000px,0)}60%{-webkit-transform:translate3d(0,25px,0);opacity:1;transform:translate3d(0,25px,0)}75%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}90%{-webkit-transform:translate3d(0,5px,0);transform:translate3d(0,5px,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.bounceInDown{-webkit-animation-name:bounceInDown;animation-name:bounceInDown}@-webkit-keyframes bounceInLeft{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:translate3d(-3000px,0,0);opacity:0;transform:translate3d(-3000px,0,0)}60%{-webkit-transform:translate3d(25px,0,0);opacity:1;transform:translate3d(25px,0,0)}75%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}90%{-webkit-transform:translate3d(5px,0,0);transform:translate3d(5px,0,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes bounceInLeft{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:translate3d(-3000px,0,0);opacity:0;transform:translate3d(-3000px,0,0)}60%{-webkit-transform:translate3d(25px,0,0);opacity:1;transform:translate3d(25px,0,0)}75%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}90%{-webkit-transform:translate3d(5px,0,0);transform:translate3d(5px,0,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.bounceInLeft{-webkit-animation-name:bounceInLeft;animation-name:bounceInLeft}@-webkit-keyframes bounceInRight{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:translate3d(3000px,0,0);opacity:0;transform:translate3d(3000px,0,0)}60%{-webkit-transform:translate3d(-25px,0,0);opacity:1;transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes bounceInRight{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:translate3d(3000px,0,0);opacity:0;transform:translate3d(3000px,0,0)}60%{-webkit-transform:translate3d(-25px,0,0);opacity:1;transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.bounceInRight{-webkit-animation-name:bounceInRight;animation-name:bounceInRight}@-webkit-keyframes bounceInUp{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:translate3d(0,3000px,0);opacity:0;transform:translate3d(0,3000px,0)}60%{-webkit-transform:translate3d(0,-20px,0);opacity:1;transform:translate3d(0,-20px,0)}75%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}90%{-webkit-transform:translate3d(0,-5px,0);transform:translate3d(0,-5px,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes bounceInUp{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:translate3d(0,3000px,0);opacity:0;transform:translate3d(0,3000px,0)}60%{-webkit-transform:translate3d(0,-20px,0);opacity:1;transform:translate3d(0,-20px,0)}75%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}90%{-webkit-transform:translate3d(0,-5px,0);transform:translate3d(0,-5px,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.bounceInUp{-webkit-animation-name:bounceInUp;animation-name:bounceInUp}@-webkit-keyframes bounceOut{20%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}50%,55%{-webkit-transform:scale3d(1.1,1.1,1.1);opacity:1;transform:scale3d(1.1,1.1,1.1)}to{-webkit-transform:scale3d(.3,.3,.3);opacity:0;transform:scale3d(.3,.3,.3)}}@keyframes bounceOut{20%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}50%,55%{-webkit-transform:scale3d(1.1,1.1,1.1);opacity:1;transform:scale3d(1.1,1.1,1.1)}to{-webkit-transform:scale3d(.3,.3,.3);opacity:0;transform:scale3d(.3,.3,.3)}}.bounceOut{-webkit-animation-duration:.75s;-webkit-animation-name:bounceOut;animation-duration:.75s;animation-name:bounceOut}@-webkit-keyframes bounceOutDown{20%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}40%,45%{-webkit-transform:translate3d(0,-20px,0);opacity:1;transform:translate3d(0,-20px,0)}to{-webkit-transform:translate3d(0,2000px,0);opacity:0;transform:translate3d(0,2000px,0)}}@keyframes bounceOutDown{20%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}40%,45%{-webkit-transform:translate3d(0,-20px,0);opacity:1;transform:translate3d(0,-20px,0)}to{-webkit-transform:translate3d(0,2000px,0);opacity:0;transform:translate3d(0,2000px,0)}}.bounceOutDown{-webkit-animation-name:bounceOutDown;animation-name:bounceOutDown}@-webkit-keyframes bounceOutLeft{20%{-webkit-transform:translate3d(20px,0,0);opacity:1;transform:translate3d(20px,0,0)}to{-webkit-transform:translate3d(-2000px,0,0);opacity:0;transform:translate3d(-2000px,0,0)}}@keyframes bounceOutLeft{20%{-webkit-transform:translate3d(20px,0,0);opacity:1;transform:translate3d(20px,0,0)}to{-webkit-transform:translate3d(-2000px,0,0);opacity:0;transform:translate3d(-2000px,0,0)}}.bounceOutLeft{-webkit-animation-name:bounceOutLeft;animation-name:bounceOutLeft}@-webkit-keyframes bounceOutRight{20%{-webkit-transform:translate3d(-20px,0,0);opacity:1;transform:translate3d(-20px,0,0)}to{-webkit-transform:translate3d(2000px,0,0);opacity:0;transform:translate3d(2000px,0,0)}}@keyframes bounceOutRight{20%{-webkit-transform:translate3d(-20px,0,0);opacity:1;transform:translate3d(-20px,0,0)}to{-webkit-transform:translate3d(2000px,0,0);opacity:0;transform:translate3d(2000px,0,0)}}.bounceOutRight{-webkit-animation-name:bounceOutRight;animation-name:bounceOutRight}@-webkit-keyframes bounceOutUp{20%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}40%,45%{-webkit-transform:translate3d(0,20px,0);opacity:1;transform:translate3d(0,20px,0)}to{-webkit-transform:translate3d(0,-2000px,0);opacity:0;transform:translate3d(0,-2000px,0)}}@keyframes bounceOutUp{20%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}40%,45%{-webkit-transform:translate3d(0,20px,0);opacity:1;transform:translate3d(0,20px,0)}to{-webkit-transform:translate3d(0,-2000px,0);opacity:0;transform:translate3d(0,-2000px,0)}}.bounceOutUp{-webkit-animation-name:bounceOutUp;animation-name:bounceOutUp}@-webkit-keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.fadeIn{-webkit-animation-name:fadeIn;animation-name:fadeIn}@-webkit-keyframes fadeInDown{0%{-webkit-transform:translate3d(0,-100%,0);opacity:0;transform:translate3d(0,-100%,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}@keyframes fadeInDown{0%{-webkit-transform:translate3d(0,-100%,0);opacity:0;transform:translate3d(0,-100%,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}.fadeInDown{-webkit-animation-name:fadeInDown;animation-name:fadeInDown}@-webkit-keyframes fadeInDownBig{0%{-webkit-transform:translate3d(0,-2000px,0);opacity:0;transform:translate3d(0,-2000px,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}@keyframes fadeInDownBig{0%{-webkit-transform:translate3d(0,-2000px,0);opacity:0;transform:translate3d(0,-2000px,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}.fadeInDownBig{-webkit-animation-name:fadeInDownBig;animation-name:fadeInDownBig}@-webkit-keyframes fadeInLeft{0%{-webkit-transform:translate3d(-100%,0,0);opacity:0;transform:translate3d(-100%,0,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}@keyframes fadeInLeft{0%{-webkit-transform:translate3d(-100%,0,0);opacity:0;transform:translate3d(-100%,0,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}.fadeInLeft{-webkit-animation-name:fadeInLeft;animation-name:fadeInLeft}@-webkit-keyframes fadeInLeftBig{0%{-webkit-transform:translate3d(-2000px,0,0);opacity:0;transform:translate3d(-2000px,0,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}@keyframes fadeInLeftBig{0%{-webkit-transform:translate3d(-2000px,0,0);opacity:0;transform:translate3d(-2000px,0,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}.fadeInLeftBig{-webkit-animation-name:fadeInLeftBig;animation-name:fadeInLeftBig}@-webkit-keyframes fadeInRight{0%{-webkit-transform:translate3d(100%,0,0);opacity:0;transform:translate3d(100%,0,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}@keyframes fadeInRight{0%{-webkit-transform:translate3d(100%,0,0);opacity:0;transform:translate3d(100%,0,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}.fadeInRight{-webkit-animation-name:fadeInRight;animation-name:fadeInRight}@-webkit-keyframes fadeInRightBig{0%{-webkit-transform:translate3d(2000px,0,0);opacity:0;transform:translate3d(2000px,0,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}@keyframes fadeInRightBig{0%{-webkit-transform:translate3d(2000px,0,0);opacity:0;transform:translate3d(2000px,0,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}.fadeInRightBig{-webkit-animation-name:fadeInRightBig;animation-name:fadeInRightBig}@-webkit-keyframes fadeInUp{0%{-webkit-transform:translate3d(0,100%,0);opacity:0;transform:translate3d(0,100%,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}@keyframes fadeInUp{0%{-webkit-transform:translate3d(0,100%,0);opacity:0;transform:translate3d(0,100%,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}.fadeInUp{-webkit-animation-name:fadeInUp;animation-name:fadeInUp}@-webkit-keyframes fadeInUpBig{0%{-webkit-transform:translate3d(0,2000px,0);opacity:0;transform:translate3d(0,2000px,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}@keyframes fadeInUpBig{0%{-webkit-transform:translate3d(0,2000px,0);opacity:0;transform:translate3d(0,2000px,0)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}.fadeInUpBig{-webkit-animation-name:fadeInUpBig;animation-name:fadeInUpBig}@-webkit-keyframes fadeOut{0%{opacity:1}to{opacity:0}}@keyframes fadeOut{0%{opacity:1}to{opacity:0}}.fadeOut{-webkit-animation-name:fadeOut;animation-name:fadeOut}@-webkit-keyframes fadeOutDown{0%{opacity:1}to{-webkit-transform:translate3d(0,100%,0);opacity:0;transform:translate3d(0,100%,0)}}@keyframes fadeOutDown{0%{opacity:1}to{-webkit-transform:translate3d(0,100%,0);opacity:0;transform:translate3d(0,100%,0)}}.fadeOutDown{-webkit-animation-name:fadeOutDown;animation-name:fadeOutDown}@-webkit-keyframes fadeOutDownBig{0%{opacity:1}to{-webkit-transform:translate3d(0,2000px,0);opacity:0;transform:translate3d(0,2000px,0)}}@keyframes fadeOutDownBig{0%{opacity:1}to{-webkit-transform:translate3d(0,2000px,0);opacity:0;transform:translate3d(0,2000px,0)}}.fadeOutDownBig{-webkit-animation-name:fadeOutDownBig;animation-name:fadeOutDownBig}@-webkit-keyframes fadeOutLeft{0%{opacity:1}to{-webkit-transform:translate3d(-100%,0,0);opacity:0;transform:translate3d(-100%,0,0)}}@keyframes fadeOutLeft{0%{opacity:1}to{-webkit-transform:translate3d(-100%,0,0);opacity:0;transform:translate3d(-100%,0,0)}}.fadeOutLeft{-webkit-animation-name:fadeOutLeft;animation-name:fadeOutLeft}@-webkit-keyframes fadeOutLeftBig{0%{opacity:1}to{-webkit-transform:translate3d(-2000px,0,0);opacity:0;transform:translate3d(-2000px,0,0)}}@keyframes fadeOutLeftBig{0%{opacity:1}to{-webkit-transform:translate3d(-2000px,0,0);opacity:0;transform:translate3d(-2000px,0,0)}}.fadeOutLeftBig{-webkit-animation-name:fadeOutLeftBig;animation-name:fadeOutLeftBig}@-webkit-keyframes fadeOutRight{0%{opacity:1}to{-webkit-transform:translate3d(100%,0,0);opacity:0;transform:translate3d(100%,0,0)}}@keyframes fadeOutRight{0%{opacity:1}to{-webkit-transform:translate3d(100%,0,0);opacity:0;transform:translate3d(100%,0,0)}}.fadeOutRight{-webkit-animation-name:fadeOutRight;animation-name:fadeOutRight}@-webkit-keyframes fadeOutRightBig{0%{opacity:1}to{-webkit-transform:translate3d(2000px,0,0);opacity:0;transform:translate3d(2000px,0,0)}}@keyframes fadeOutRightBig{0%{opacity:1}to{-webkit-transform:translate3d(2000px,0,0);opacity:0;transform:translate3d(2000px,0,0)}}.fadeOutRightBig{-webkit-animation-name:fadeOutRightBig;animation-name:fadeOutRightBig}@-webkit-keyframes fadeOutUp{0%{opacity:1}to{-webkit-transform:translate3d(0,-100%,0);opacity:0;transform:translate3d(0,-100%,0)}}@keyframes fadeOutUp{0%{opacity:1}to{-webkit-transform:translate3d(0,-100%,0);opacity:0;transform:translate3d(0,-100%,0)}}.fadeOutUp{-webkit-animation-name:fadeOutUp;animation-name:fadeOutUp}@-webkit-keyframes fadeOutUpBig{0%{opacity:1}to{-webkit-transform:translate3d(0,-2000px,0);opacity:0;transform:translate3d(0,-2000px,0)}}@keyframes fadeOutUpBig{0%{opacity:1}to{-webkit-transform:translate3d(0,-2000px,0);opacity:0;transform:translate3d(0,-2000px,0)}}.fadeOutUpBig{-webkit-animation-name:fadeOutUpBig;animation-name:fadeOutUpBig}@-webkit-keyframes flip{0%{-webkit-animation-timing-function:ease-out;-webkit-transform:perspective(400px) scaleX(1) translateZ(0) rotateY(-1turn);animation-timing-function:ease-out;transform:perspective(400px) scaleX(1) translateZ(0) rotateY(-1turn)}40%{-webkit-animation-timing-function:ease-out;-webkit-transform:perspective(400px) scaleX(1) translateZ(150px) rotateY(-190deg);animation-timing-function:ease-out;transform:perspective(400px) scaleX(1) translateZ(150px) rotateY(-190deg)}50%{-webkit-animation-timing-function:ease-in;-webkit-transform:perspective(400px) scaleX(1) translateZ(150px) rotateY(-170deg);animation-timing-function:ease-in;transform:perspective(400px) scaleX(1) translateZ(150px) rotateY(-170deg)}80%{-webkit-animation-timing-function:ease-in;-webkit-transform:perspective(400px) scale3d(.95,.95,.95) translateZ(0) rotateY(0deg);animation-timing-function:ease-in;transform:perspective(400px) scale3d(.95,.95,.95) translateZ(0) rotateY(0deg)}to{-webkit-animation-timing-function:ease-in;-webkit-transform:perspective(400px) scaleX(1) translateZ(0) rotateY(0deg);animation-timing-function:ease-in;transform:perspective(400px) scaleX(1) translateZ(0) rotateY(0deg)}}@keyframes flip{0%{-webkit-animation-timing-function:ease-out;-webkit-transform:perspective(400px) scaleX(1) translateZ(0) rotateY(-1turn);animation-timing-function:ease-out;transform:perspective(400px) scaleX(1) translateZ(0) rotateY(-1turn)}40%{-webkit-animation-timing-function:ease-out;-webkit-transform:perspective(400px) scaleX(1) translateZ(150px) rotateY(-190deg);animation-timing-function:ease-out;transform:perspective(400px) scaleX(1) translateZ(150px) rotateY(-190deg)}50%{-webkit-animation-timing-function:ease-in;-webkit-transform:perspective(400px) scaleX(1) translateZ(150px) rotateY(-170deg);animation-timing-function:ease-in;transform:perspective(400px) scaleX(1) translateZ(150px) rotateY(-170deg)}80%{-webkit-animation-timing-function:ease-in;-webkit-transform:perspective(400px) scale3d(.95,.95,.95) translateZ(0) rotateY(0deg);animation-timing-function:ease-in;transform:perspective(400px) scale3d(.95,.95,.95) translateZ(0) rotateY(0deg)}to{-webkit-animation-timing-function:ease-in;-webkit-transform:perspective(400px) scaleX(1) translateZ(0) rotateY(0deg);animation-timing-function:ease-in;transform:perspective(400px) scaleX(1) translateZ(0) rotateY(0deg)}}.animated.flip{-webkit-animation-name:flip;-webkit-backface-visibility:visible;animation-name:flip;backface-visibility:visible}@-webkit-keyframes flipInX{0%{-webkit-animation-timing-function:ease-in;-webkit-transform:perspective(400px) rotateX(90deg);animation-timing-function:ease-in;opacity:0;transform:perspective(400px) rotateX(90deg)}40%{-webkit-animation-timing-function:ease-in;-webkit-transform:perspective(400px) rotateX(-20deg);animation-timing-function:ease-in;transform:perspective(400px) rotateX(-20deg)}60%{-webkit-transform:perspective(400px) rotateX(10deg);opacity:1;transform:perspective(400px) rotateX(10deg)}80%{-webkit-transform:perspective(400px) rotateX(-5deg);transform:perspective(400px) rotateX(-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}@keyframes flipInX{0%{-webkit-animation-timing-function:ease-in;-webkit-transform:perspective(400px) rotateX(90deg);animation-timing-function:ease-in;opacity:0;transform:perspective(400px) rotateX(90deg)}40%{-webkit-animation-timing-function:ease-in;-webkit-transform:perspective(400px) rotateX(-20deg);animation-timing-function:ease-in;transform:perspective(400px) rotateX(-20deg)}60%{-webkit-transform:perspective(400px) rotateX(10deg);opacity:1;transform:perspective(400px) rotateX(10deg)}80%{-webkit-transform:perspective(400px) rotateX(-5deg);transform:perspective(400px) rotateX(-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}.flipInX{-webkit-animation-name:flipInX;-webkit-backface-visibility:visible!important;animation-name:flipInX;backface-visibility:visible!important}@-webkit-keyframes flipInY{0%{-webkit-animation-timing-function:ease-in;-webkit-transform:perspective(400px) rotateY(90deg);animation-timing-function:ease-in;opacity:0;transform:perspective(400px) rotateY(90deg)}40%{-webkit-animation-timing-function:ease-in;-webkit-transform:perspective(400px) rotateY(-20deg);animation-timing-function:ease-in;transform:perspective(400px) rotateY(-20deg)}60%{-webkit-transform:perspective(400px) rotateY(10deg);opacity:1;transform:perspective(400px) rotateY(10deg)}80%{-webkit-transform:perspective(400px) rotateY(-5deg);transform:perspective(400px) rotateY(-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}@keyframes flipInY{0%{-webkit-animation-timing-function:ease-in;-webkit-transform:perspective(400px) rotateY(90deg);animation-timing-function:ease-in;opacity:0;transform:perspective(400px) rotateY(90deg)}40%{-webkit-animation-timing-function:ease-in;-webkit-transform:perspective(400px) rotateY(-20deg);animation-timing-function:ease-in;transform:perspective(400px) rotateY(-20deg)}60%{-webkit-transform:perspective(400px) rotateY(10deg);opacity:1;transform:perspective(400px) rotateY(10deg)}80%{-webkit-transform:perspective(400px) rotateY(-5deg);transform:perspective(400px) rotateY(-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}.flipInY{-webkit-animation-name:flipInY;-webkit-backface-visibility:visible!important;animation-name:flipInY;backface-visibility:visible!important}@-webkit-keyframes flipOutX{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotateX(-20deg);opacity:1;transform:perspective(400px) rotateX(-20deg)}to{-webkit-transform:perspective(400px) rotateX(90deg);opacity:0;transform:perspective(400px) rotateX(90deg)}}@keyframes flipOutX{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotateX(-20deg);opacity:1;transform:perspective(400px) rotateX(-20deg)}to{-webkit-transform:perspective(400px) rotateX(90deg);opacity:0;transform:perspective(400px) rotateX(90deg)}}.flipOutX{-webkit-animation-duration:.75s;-webkit-animation-name:flipOutX;-webkit-backface-visibility:visible!important;animation-duration:.75s;animation-name:flipOutX;backface-visibility:visible!important}@-webkit-keyframes flipOutY{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotateY(-15deg);opacity:1;transform:perspective(400px) rotateY(-15deg)}to{-webkit-transform:perspective(400px) rotateY(90deg);opacity:0;transform:perspective(400px) rotateY(90deg)}}@keyframes flipOutY{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotateY(-15deg);opacity:1;transform:perspective(400px) rotateY(-15deg)}to{-webkit-transform:perspective(400px) rotateY(90deg);opacity:0;transform:perspective(400px) rotateY(90deg)}}.flipOutY{-webkit-animation-duration:.75s;-webkit-animation-name:flipOutY;-webkit-backface-visibility:visible!important;animation-duration:.75s;animation-name:flipOutY;backface-visibility:visible!important}@-webkit-keyframes lightSpeedIn{0%{-webkit-transform:translate3d(100%,0,0) skewX(-30deg);opacity:0;transform:translate3d(100%,0,0) skewX(-30deg)}60%{-webkit-transform:skewX(20deg);opacity:1;transform:skewX(20deg)}80%{-webkit-transform:skewX(-5deg);transform:skewX(-5deg)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes lightSpeedIn{0%{-webkit-transform:translate3d(100%,0,0) skewX(-30deg);opacity:0;transform:translate3d(100%,0,0) skewX(-30deg)}60%{-webkit-transform:skewX(20deg);opacity:1;transform:skewX(20deg)}80%{-webkit-transform:skewX(-5deg);transform:skewX(-5deg)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.lightSpeedIn{-webkit-animation-name:lightSpeedIn;-webkit-animation-timing-function:ease-out;animation-name:lightSpeedIn;animation-timing-function:ease-out}@-webkit-keyframes lightSpeedOut{0%{opacity:1}to{-webkit-transform:translate3d(100%,0,0) skewX(30deg);opacity:0;transform:translate3d(100%,0,0) skewX(30deg)}}@keyframes lightSpeedOut{0%{opacity:1}to{-webkit-transform:translate3d(100%,0,0) skewX(30deg);opacity:0;transform:translate3d(100%,0,0) skewX(30deg)}}.lightSpeedOut{-webkit-animation-name:lightSpeedOut;-webkit-animation-timing-function:ease-in;animation-name:lightSpeedOut;animation-timing-function:ease-in}@-webkit-keyframes rotateIn{0%{-webkit-transform:rotate(-200deg);-webkit-transform-origin:center;opacity:0;transform:rotate(-200deg);transform-origin:center}to{-webkit-transform:translateZ(0);-webkit-transform-origin:center;opacity:1;transform:translateZ(0);transform-origin:center}}@keyframes rotateIn{0%{-webkit-transform:rotate(-200deg);-webkit-transform-origin:center;opacity:0;transform:rotate(-200deg);transform-origin:center}to{-webkit-transform:translateZ(0);-webkit-transform-origin:center;opacity:1;transform:translateZ(0);transform-origin:center}}.rotateIn{-webkit-animation-name:rotateIn;animation-name:rotateIn}@-webkit-keyframes rotateInDownLeft{0%{-webkit-transform:rotate(-45deg);-webkit-transform-origin:left bottom;opacity:0;transform:rotate(-45deg);transform-origin:left bottom}to{-webkit-transform:translateZ(0);-webkit-transform-origin:left bottom;opacity:1;transform:translateZ(0);transform-origin:left bottom}}@keyframes rotateInDownLeft{0%{-webkit-transform:rotate(-45deg);-webkit-transform-origin:left bottom;opacity:0;transform:rotate(-45deg);transform-origin:left bottom}to{-webkit-transform:translateZ(0);-webkit-transform-origin:left bottom;opacity:1;transform:translateZ(0);transform-origin:left bottom}}.rotateInDownLeft{-webkit-animation-name:rotateInDownLeft;animation-name:rotateInDownLeft}@-webkit-keyframes rotateInDownRight{0%{-webkit-transform:rotate(45deg);-webkit-transform-origin:right bottom;opacity:0;transform:rotate(45deg);transform-origin:right bottom}to{-webkit-transform:translateZ(0);-webkit-transform-origin:right bottom;opacity:1;transform:translateZ(0);transform-origin:right bottom}}@keyframes rotateInDownRight{0%{-webkit-transform:rotate(45deg);-webkit-transform-origin:right bottom;opacity:0;transform:rotate(45deg);transform-origin:right bottom}to{-webkit-transform:translateZ(0);-webkit-transform-origin:right bottom;opacity:1;transform:translateZ(0);transform-origin:right bottom}}.rotateInDownRight{-webkit-animation-name:rotateInDownRight;animation-name:rotateInDownRight}@-webkit-keyframes rotateInUpLeft{0%{-webkit-transform:rotate(45deg);-webkit-transform-origin:left bottom;opacity:0;transform:rotate(45deg);transform-origin:left bottom}to{-webkit-transform:translateZ(0);-webkit-transform-origin:left bottom;opacity:1;transform:translateZ(0);transform-origin:left bottom}}@keyframes rotateInUpLeft{0%{-webkit-transform:rotate(45deg);-webkit-transform-origin:left bottom;opacity:0;transform:rotate(45deg);transform-origin:left bottom}to{-webkit-transform:translateZ(0);-webkit-transform-origin:left bottom;opacity:1;transform:translateZ(0);transform-origin:left bottom}}.rotateInUpLeft{-webkit-animation-name:rotateInUpLeft;animation-name:rotateInUpLeft}@-webkit-keyframes rotateInUpRight{0%{-webkit-transform:rotate(-90deg);-webkit-transform-origin:right bottom;opacity:0;transform:rotate(-90deg);transform-origin:right bottom}to{-webkit-transform:translateZ(0);-webkit-transform-origin:right bottom;opacity:1;transform:translateZ(0);transform-origin:right bottom}}@keyframes rotateInUpRight{0%{-webkit-transform:rotate(-90deg);-webkit-transform-origin:right bottom;opacity:0;transform:rotate(-90deg);transform-origin:right bottom}to{-webkit-transform:translateZ(0);-webkit-transform-origin:right bottom;opacity:1;transform:translateZ(0);transform-origin:right bottom}}.rotateInUpRight{-webkit-animation-name:rotateInUpRight;animation-name:rotateInUpRight}@-webkit-keyframes rotateOut{0%{-webkit-transform-origin:center;opacity:1;transform-origin:center}to{-webkit-transform:rotate(200deg);-webkit-transform-origin:center;opacity:0;transform:rotate(200deg);transform-origin:center}}@keyframes rotateOut{0%{-webkit-transform-origin:center;opacity:1;transform-origin:center}to{-webkit-transform:rotate(200deg);-webkit-transform-origin:center;opacity:0;transform:rotate(200deg);transform-origin:center}}.rotateOut{-webkit-animation-name:rotateOut;animation-name:rotateOut}@-webkit-keyframes rotateOutDownLeft{0%{-webkit-transform-origin:left bottom;opacity:1;transform-origin:left bottom}to{-webkit-transform:rotate(45deg);-webkit-transform-origin:left bottom;opacity:0;transform:rotate(45deg);transform-origin:left bottom}}@keyframes rotateOutDownLeft{0%{-webkit-transform-origin:left bottom;opacity:1;transform-origin:left bottom}to{-webkit-transform:rotate(45deg);-webkit-transform-origin:left bottom;opacity:0;transform:rotate(45deg);transform-origin:left bottom}}.rotateOutDownLeft{-webkit-animation-name:rotateOutDownLeft;animation-name:rotateOutDownLeft}@-webkit-keyframes rotateOutDownRight{0%{-webkit-transform-origin:right bottom;opacity:1;transform-origin:right bottom}to{-webkit-transform:rotate(-45deg);-webkit-transform-origin:right bottom;opacity:0;transform:rotate(-45deg);transform-origin:right bottom}}@keyframes rotateOutDownRight{0%{-webkit-transform-origin:right bottom;opacity:1;transform-origin:right bottom}to{-webkit-transform:rotate(-45deg);-webkit-transform-origin:right bottom;opacity:0;transform:rotate(-45deg);transform-origin:right bottom}}.rotateOutDownRight{-webkit-animation-name:rotateOutDownRight;animation-name:rotateOutDownRight}@-webkit-keyframes rotateOutUpLeft{0%{-webkit-transform-origin:left bottom;opacity:1;transform-origin:left bottom}to{-webkit-transform:rotate(-45deg);-webkit-transform-origin:left bottom;opacity:0;transform:rotate(-45deg);transform-origin:left bottom}}@keyframes rotateOutUpLeft{0%{-webkit-transform-origin:left bottom;opacity:1;transform-origin:left bottom}to{-webkit-transform:rotate(-45deg);-webkit-transform-origin:left bottom;opacity:0;transform:rotate(-45deg);transform-origin:left bottom}}.rotateOutUpLeft{-webkit-animation-name:rotateOutUpLeft;animation-name:rotateOutUpLeft}@-webkit-keyframes rotateOutUpRight{0%{-webkit-transform-origin:right bottom;opacity:1;transform-origin:right bottom}to{-webkit-transform:rotate(90deg);-webkit-transform-origin:right bottom;opacity:0;transform:rotate(90deg);transform-origin:right bottom}}@keyframes rotateOutUpRight{0%{-webkit-transform-origin:right bottom;opacity:1;transform-origin:right bottom}to{-webkit-transform:rotate(90deg);-webkit-transform-origin:right bottom;opacity:0;transform:rotate(90deg);transform-origin:right bottom}}.rotateOutUpRight{-webkit-animation-name:rotateOutUpRight;animation-name:rotateOutUpRight}@-webkit-keyframes hinge{0%{-webkit-animation-timing-function:ease-in-out;-webkit-transform-origin:top left;animation-timing-function:ease-in-out;transform-origin:top left}20%,60%{-webkit-animation-timing-function:ease-in-out;-webkit-transform:rotate(80deg);-webkit-transform-origin:top left;animation-timing-function:ease-in-out;transform:rotate(80deg);transform-origin:top left}40%,80%{-webkit-animation-timing-function:ease-in-out;-webkit-transform:rotate(60deg);-webkit-transform-origin:top left;animation-timing-function:ease-in-out;opacity:1;transform:rotate(60deg);transform-origin:top left}to{-webkit-transform:translate3d(0,700px,0);opacity:0;transform:translate3d(0,700px,0)}}@keyframes hinge{0%{-webkit-animation-timing-function:ease-in-out;-webkit-transform-origin:top left;animation-timing-function:ease-in-out;transform-origin:top left}20%,60%{-webkit-animation-timing-function:ease-in-out;-webkit-transform:rotate(80deg);-webkit-transform-origin:top left;animation-timing-function:ease-in-out;transform:rotate(80deg);transform-origin:top left}40%,80%{-webkit-animation-timing-function:ease-in-out;-webkit-transform:rotate(60deg);-webkit-transform-origin:top left;animation-timing-function:ease-in-out;opacity:1;transform:rotate(60deg);transform-origin:top left}to{-webkit-transform:translate3d(0,700px,0);opacity:0;transform:translate3d(0,700px,0)}}.hinge{-webkit-animation-duration:2s;-webkit-animation-name:hinge;animation-duration:2s;animation-name:hinge}@-webkit-keyframes jackInTheBox{0%{-webkit-transform:scale(.1) rotate(30deg);-webkit-transform-origin:center bottom;opacity:0;transform:scale(.1) rotate(30deg);transform-origin:center bottom}50%{-webkit-transform:rotate(-10deg);transform:rotate(-10deg)}70%{-webkit-transform:rotate(3deg);transform:rotate(3deg)}to{-webkit-transform:scale(1);opacity:1;transform:scale(1)}}@keyframes jackInTheBox{0%{-webkit-transform:scale(.1) rotate(30deg);-webkit-transform-origin:center bottom;opacity:0;transform:scale(.1) rotate(30deg);transform-origin:center bottom}50%{-webkit-transform:rotate(-10deg);transform:rotate(-10deg)}70%{-webkit-transform:rotate(3deg);transform:rotate(3deg)}to{-webkit-transform:scale(1);opacity:1;transform:scale(1)}}.jackInTheBox{-webkit-animation-name:jackInTheBox;animation-name:jackInTheBox}@-webkit-keyframes rollIn{0%{-webkit-transform:translate3d(-100%,0,0) rotate(-120deg);opacity:0;transform:translate3d(-100%,0,0) rotate(-120deg)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}@keyframes rollIn{0%{-webkit-transform:translate3d(-100%,0,0) rotate(-120deg);opacity:0;transform:translate3d(-100%,0,0) rotate(-120deg)}to{-webkit-transform:translateZ(0);opacity:1;transform:translateZ(0)}}.rollIn{-webkit-animation-name:rollIn;animation-name:rollIn}@-webkit-keyframes rollOut{0%{opacity:1}to{-webkit-transform:translate3d(100%,0,0) rotate(120deg);opacity:0;transform:translate3d(100%,0,0) rotate(120deg)}}@keyframes rollOut{0%{opacity:1}to{-webkit-transform:translate3d(100%,0,0) rotate(120deg);opacity:0;transform:translate3d(100%,0,0) rotate(120deg)}}.rollOut{-webkit-animation-name:rollOut;animation-name:rollOut}@-webkit-keyframes zoomIn{0%{-webkit-transform:scale3d(.3,.3,.3);opacity:0;transform:scale3d(.3,.3,.3)}50%{opacity:1}}@keyframes zoomIn{0%{-webkit-transform:scale3d(.3,.3,.3);opacity:0;transform:scale3d(.3,.3,.3)}50%{opacity:1}}.zoomIn{-webkit-animation-name:zoomIn;animation-name:zoomIn}@-webkit-keyframes zoomInDown{0%{-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);animation-timing-function:cubic-bezier(.55,.055,.675,.19);opacity:0;transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0)}60%{-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);animation-timing-function:cubic-bezier(.175,.885,.32,1);opacity:1;transform:scale3d(.475,.475,.475) translate3d(0,60px,0)}}@keyframes zoomInDown{0%{-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);animation-timing-function:cubic-bezier(.55,.055,.675,.19);opacity:0;transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0)}60%{-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);animation-timing-function:cubic-bezier(.175,.885,.32,1);opacity:1;transform:scale3d(.475,.475,.475) translate3d(0,60px,0)}}.zoomInDown{-webkit-animation-name:zoomInDown;animation-name:zoomInDown}@-webkit-keyframes zoomInLeft{0%{-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);-webkit-transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);animation-timing-function:cubic-bezier(.55,.055,.675,.19);opacity:0;transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0)}60%{-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);-webkit-transform:scale3d(.475,.475,.475) translate3d(10px,0,0);animation-timing-function:cubic-bezier(.175,.885,.32,1);opacity:1;transform:scale3d(.475,.475,.475) translate3d(10px,0,0)}}@keyframes zoomInLeft{0%{-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);-webkit-transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);animation-timing-function:cubic-bezier(.55,.055,.675,.19);opacity:0;transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0)}60%{-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);-webkit-transform:scale3d(.475,.475,.475) translate3d(10px,0,0);animation-timing-function:cubic-bezier(.175,.885,.32,1);opacity:1;transform:scale3d(.475,.475,.475) translate3d(10px,0,0)}}.zoomInLeft{-webkit-animation-name:zoomInLeft;animation-name:zoomInLeft}@-webkit-keyframes zoomInRight{0%{-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);-webkit-transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);animation-timing-function:cubic-bezier(.55,.055,.675,.19);opacity:0;transform:scale3d(.1,.1,.1) translate3d(1000px,0,0)}60%{-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);-webkit-transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);animation-timing-function:cubic-bezier(.175,.885,.32,1);opacity:1;transform:scale3d(.475,.475,.475) translate3d(-10px,0,0)}}@keyframes zoomInRight{0%{-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);-webkit-transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);animation-timing-function:cubic-bezier(.55,.055,.675,.19);opacity:0;transform:scale3d(.1,.1,.1) translate3d(1000px,0,0)}60%{-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);-webkit-transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);animation-timing-function:cubic-bezier(.175,.885,.32,1);opacity:1;transform:scale3d(.475,.475,.475) translate3d(-10px,0,0)}}.zoomInRight{-webkit-animation-name:zoomInRight;animation-name:zoomInRight}@-webkit-keyframes zoomInUp{0%{-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);-webkit-transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);animation-timing-function:cubic-bezier(.55,.055,.675,.19);opacity:0;transform:scale3d(.1,.1,.1) translate3d(0,1000px,0)}60%{-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);animation-timing-function:cubic-bezier(.175,.885,.32,1);opacity:1;transform:scale3d(.475,.475,.475) translate3d(0,-60px,0)}}@keyframes zoomInUp{0%{-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);-webkit-transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);animation-timing-function:cubic-bezier(.55,.055,.675,.19);opacity:0;transform:scale3d(.1,.1,.1) translate3d(0,1000px,0)}60%{-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);animation-timing-function:cubic-bezier(.175,.885,.32,1);opacity:1;transform:scale3d(.475,.475,.475) translate3d(0,-60px,0)}}.zoomInUp{-webkit-animation-name:zoomInUp;animation-name:zoomInUp}@-webkit-keyframes zoomOut{0%{opacity:1}50%{-webkit-transform:scale3d(.3,.3,.3);opacity:0;transform:scale3d(.3,.3,.3)}to{opacity:0}}@keyframes zoomOut{0%{opacity:1}50%{-webkit-transform:scale3d(.3,.3,.3);opacity:0;transform:scale3d(.3,.3,.3)}to{opacity:0}}.zoomOut{-webkit-animation-name:zoomOut;animation-name:zoomOut}@-webkit-keyframes zoomOutDown{40%{-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);animation-timing-function:cubic-bezier(.55,.055,.675,.19);opacity:1;transform:scale3d(.475,.475,.475) translate3d(0,-60px,0)}to{-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);-webkit-transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);-webkit-transform-origin:center bottom;animation-timing-function:cubic-bezier(.175,.885,.32,1);opacity:0;transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);transform-origin:center bottom}}@keyframes zoomOutDown{40%{-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);animation-timing-function:cubic-bezier(.55,.055,.675,.19);opacity:1;transform:scale3d(.475,.475,.475) translate3d(0,-60px,0)}to{-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);-webkit-transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);-webkit-transform-origin:center bottom;animation-timing-function:cubic-bezier(.175,.885,.32,1);opacity:0;transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);transform-origin:center bottom}}.zoomOutDown{-webkit-animation-name:zoomOutDown;animation-name:zoomOutDown}@-webkit-keyframes zoomOutLeft{40%{-webkit-transform:scale3d(.475,.475,.475) translate3d(42px,0,0);opacity:1;transform:scale3d(.475,.475,.475) translate3d(42px,0,0)}to{-webkit-transform:scale(.1) translate3d(-2000px,0,0);-webkit-transform-origin:left center;opacity:0;transform:scale(.1) translate3d(-2000px,0,0);transform-origin:left center}}@keyframes zoomOutLeft{40%{-webkit-transform:scale3d(.475,.475,.475) translate3d(42px,0,0);opacity:1;transform:scale3d(.475,.475,.475) translate3d(42px,0,0)}to{-webkit-transform:scale(.1) translate3d(-2000px,0,0);-webkit-transform-origin:left center;opacity:0;transform:scale(.1) translate3d(-2000px,0,0);transform-origin:left center}}.zoomOutLeft{-webkit-animation-name:zoomOutLeft;animation-name:zoomOutLeft}@-webkit-keyframes zoomOutRight{40%{-webkit-transform:scale3d(.475,.475,.475) translate3d(-42px,0,0);opacity:1;transform:scale3d(.475,.475,.475) translate3d(-42px,0,0)}to{-webkit-transform:scale(.1) translate3d(2000px,0,0);-webkit-transform-origin:right center;opacity:0;transform:scale(.1) translate3d(2000px,0,0);transform-origin:right center}}@keyframes zoomOutRight{40%{-webkit-transform:scale3d(.475,.475,.475) translate3d(-42px,0,0);opacity:1;transform:scale3d(.475,.475,.475) translate3d(-42px,0,0)}to{-webkit-transform:scale(.1) translate3d(2000px,0,0);-webkit-transform-origin:right center;opacity:0;transform:scale(.1) translate3d(2000px,0,0);transform-origin:right center}}.zoomOutRight{-webkit-animation-name:zoomOutRight;animation-name:zoomOutRight}@-webkit-keyframes zoomOutUp{40%{-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);animation-timing-function:cubic-bezier(.55,.055,.675,.19);opacity:1;transform:scale3d(.475,.475,.475) translate3d(0,60px,0)}to{-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);-webkit-transform-origin:center bottom;animation-timing-function:cubic-bezier(.175,.885,.32,1);opacity:0;transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);transform-origin:center bottom}}@keyframes zoomOutUp{40%{-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);animation-timing-function:cubic-bezier(.55,.055,.675,.19);opacity:1;transform:scale3d(.475,.475,.475) translate3d(0,60px,0)}to{-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);-webkit-transform-origin:center bottom;animation-timing-function:cubic-bezier(.175,.885,.32,1);opacity:0;transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);transform-origin:center bottom}}.zoomOutUp{-webkit-animation-name:zoomOutUp;animation-name:zoomOutUp}@-webkit-keyframes slideInDown{0%{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes slideInDown{0%{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.slideInDown{-webkit-animation-name:slideInDown;animation-name:slideInDown}@-webkit-keyframes slideInLeft{0%{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes slideInLeft{0%{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.slideInLeft{-webkit-animation-name:slideInLeft;animation-name:slideInLeft}@-webkit-keyframes slideInRight{0%{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes slideInRight{0%{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.slideInRight{-webkit-animation-name:slideInRight;animation-name:slideInRight}@-webkit-keyframes slideInUp{0%{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes slideInUp{0%{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.slideInUp{-webkit-animation-name:slideInUp;animation-name:slideInUp}@-webkit-keyframes slideOutDown{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);visibility:hidden}}@keyframes slideOutDown{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);visibility:hidden}}.slideOutDown{-webkit-animation-name:slideOutDown;animation-name:slideOutDown}@-webkit-keyframes slideOutLeft{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0);visibility:hidden}}@keyframes slideOutLeft{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0);visibility:hidden}}.slideOutLeft{-webkit-animation-name:slideOutLeft;animation-name:slideOutLeft}@-webkit-keyframes slideOutRight{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);visibility:hidden}}@keyframes slideOutRight{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);visibility:hidden}}.slideOutRight{-webkit-animation-name:slideOutRight;animation-name:slideOutRight}@-webkit-keyframes slideOutUp{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0);visibility:hidden}}@keyframes slideOutUp{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0);visibility:hidden}}.slideOutUp{-webkit-animation-name:slideOutUp;animation-name:slideOutUp}.animated{-webkit-animation-duration:1s;-webkit-animation-fill-mode:both;animation-duration:1s;animation-fill-mode:both}.animated.infinite{-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.animated.delay-1s{-webkit-animation-delay:1s;animation-delay:1s}.animated.delay-2s{-webkit-animation-delay:2s;animation-delay:2s}.animated.delay-3s{-webkit-animation-delay:3s;animation-delay:3s}.animated.delay-4s{-webkit-animation-delay:4s;animation-delay:4s}.animated.delay-5s{-webkit-animation-delay:5s;animation-delay:5s}.animated.fast{-webkit-animation-duration:.8s;animation-duration:.8s}.animated.faster{-webkit-animation-duration:.5s;animation-duration:.5s}.animated.slow{-webkit-animation-duration:2s;animation-duration:2s}.animated.slower{-webkit-animation-duration:3s;animation-duration:3s}@media (prefers-reduced-motion){.animated{-webkit-animation:unset!important;-webkit-transition:none!important;animation:unset!important;transition:none!important}} + +/*! + * Materialize v1.0.0 (http://materializecss.com) + * Copyright 2014-2017 Materialize + * MIT License (https://raw.githubusercontent.com/Dogfalo/materialize/master/LICENSE) + */ +.red{background-color:#F44336!important}.red-text{color:#F44336!important}.red.lighten-5{background-color:#FFEBEE!important}.red-text.text-lighten-5{color:#FFEBEE!important}.red.lighten-4{background-color:#FFCDD2!important}.red-text.text-lighten-4{color:#FFCDD2!important}.red.lighten-3{background-color:#EF9A9A!important}.red-text.text-lighten-3{color:#EF9A9A!important}.red.lighten-2{background-color:#E57373!important}.red-text.text-lighten-2{color:#E57373!important}.red.lighten-1{background-color:#EF5350!important}.red-text.text-lighten-1{color:#EF5350!important}.red.darken-1{background-color:#E53935!important}.red-text.text-darken-1{color:#E53935!important}.red.darken-2{background-color:#D32F2F!important}.red-text.text-darken-2{color:#D32F2F!important}.red.darken-3{background-color:#C62828!important}.red-text.text-darken-3{color:#C62828!important}.red.darken-4{background-color:#B71C1C!important}.red-text.text-darken-4{color:#B71C1C!important}.red.accent-1{background-color:#FF8A80!important}.red-text.text-accent-1{color:#FF8A80!important}.red.accent-2{background-color:#FF5252!important}.red-text.text-accent-2{color:#FF5252!important}.red.accent-3{background-color:#FF1744!important}.red-text.text-accent-3{color:#FF1744!important}.red.accent-4{background-color:#D50000!important}.red-text.text-accent-4{color:#D50000!important}.pink{background-color:#e91e63!important}.pink-text{color:#e91e63!important}.pink.lighten-5{background-color:#fce4ec!important}.pink-text.text-lighten-5{color:#fce4ec!important}.pink.lighten-4{background-color:#f8bbd0!important}.pink-text.text-lighten-4{color:#f8bbd0!important}.pink.lighten-3{background-color:#f48fb1!important}.pink-text.text-lighten-3{color:#f48fb1!important}.pink.lighten-2{background-color:#f06292!important}.pink-text.text-lighten-2{color:#f06292!important}.pink.lighten-1{background-color:#ec407a!important}.pink-text.text-lighten-1{color:#ec407a!important}.pink.darken-1{background-color:#d81b60!important}.pink-text.text-darken-1{color:#d81b60!important}.pink.darken-2{background-color:#c2185b!important}.pink-text.text-darken-2{color:#c2185b!important}.pink.darken-3{background-color:#ad1457!important}.pink-text.text-darken-3{color:#ad1457!important}.pink.darken-4{background-color:#880e4f!important}.pink-text.text-darken-4{color:#880e4f!important}.pink.accent-1{background-color:#ff80ab!important}.pink-text.text-accent-1{color:#ff80ab!important}.pink.accent-2{background-color:#ff4081!important}.pink-text.text-accent-2{color:#ff4081!important}.pink.accent-3{background-color:#f50057!important}.pink-text.text-accent-3{color:#f50057!important}.pink.accent-4{background-color:#c51162!important}.pink-text.text-accent-4{color:#c51162!important}.purple{background-color:#9c27b0!important}.purple-text{color:#9c27b0!important}.purple.lighten-5{background-color:#f3e5f5!important}.purple-text.text-lighten-5{color:#f3e5f5!important}.purple.lighten-4{background-color:#e1bee7!important}.purple-text.text-lighten-4{color:#e1bee7!important}.purple.lighten-3{background-color:#ce93d8!important}.purple-text.text-lighten-3{color:#ce93d8!important}.purple.lighten-2{background-color:#ba68c8!important}.purple-text.text-lighten-2{color:#ba68c8!important}.purple.lighten-1{background-color:#ab47bc!important}.purple-text.text-lighten-1{color:#ab47bc!important}.purple.darken-1{background-color:#8e24aa!important}.purple-text.text-darken-1{color:#8e24aa!important}.purple.darken-2{background-color:#7b1fa2!important}.purple-text.text-darken-2{color:#7b1fa2!important}.purple.darken-3{background-color:#6a1b9a!important}.purple-text.text-darken-3{color:#6a1b9a!important}.purple.darken-4{background-color:#4a148c!important}.purple-text.text-darken-4{color:#4a148c!important}.purple.accent-1{background-color:#ea80fc!important}.purple-text.text-accent-1{color:#ea80fc!important}.purple.accent-2{background-color:#e040fb!important}.purple-text.text-accent-2{color:#e040fb!important}.purple.accent-3{background-color:#d500f9!important}.purple-text.text-accent-3{color:#d500f9!important}.purple.accent-4{background-color:#a0f!important}.purple-text.text-accent-4{color:#a0f!important}.deep-purple{background-color:#673ab7!important}.deep-purple-text{color:#673ab7!important}.deep-purple.lighten-5{background-color:#ede7f6!important}.deep-purple-text.text-lighten-5{color:#ede7f6!important}.deep-purple.lighten-4{background-color:#d1c4e9!important}.deep-purple-text.text-lighten-4{color:#d1c4e9!important}.deep-purple.lighten-3{background-color:#b39ddb!important}.deep-purple-text.text-lighten-3{color:#b39ddb!important}.deep-purple.lighten-2{background-color:#9575cd!important}.deep-purple-text.text-lighten-2{color:#9575cd!important}.deep-purple.lighten-1{background-color:#7e57c2!important}.deep-purple-text.text-lighten-1{color:#7e57c2!important}.deep-purple.darken-1{background-color:#5e35b1!important}.deep-purple-text.text-darken-1{color:#5e35b1!important}.deep-purple.darken-2{background-color:#512da8!important}.deep-purple-text.text-darken-2{color:#512da8!important}.deep-purple.darken-3{background-color:#4527a0!important}.deep-purple-text.text-darken-3{color:#4527a0!important}.deep-purple.darken-4{background-color:#311b92!important}.deep-purple-text.text-darken-4{color:#311b92!important}.deep-purple.accent-1{background-color:#b388ff!important}.deep-purple-text.text-accent-1{color:#b388ff!important}.deep-purple.accent-2{background-color:#7c4dff!important}.deep-purple-text.text-accent-2{color:#7c4dff!important}.deep-purple.accent-3{background-color:#651fff!important}.deep-purple-text.text-accent-3{color:#651fff!important}.deep-purple.accent-4{background-color:#6200ea!important}.deep-purple-text.text-accent-4{color:#6200ea!important}.indigo{background-color:#3f51b5!important}.indigo-text{color:#3f51b5!important}.indigo.lighten-5{background-color:#e8eaf6!important}.indigo-text.text-lighten-5{color:#e8eaf6!important}.indigo.lighten-4{background-color:#c5cae9!important}.indigo-text.text-lighten-4{color:#c5cae9!important}.indigo.lighten-3{background-color:#9fa8da!important}.indigo-text.text-lighten-3{color:#9fa8da!important}.indigo.lighten-2{background-color:#7986cb!important}.indigo-text.text-lighten-2{color:#7986cb!important}.indigo.lighten-1{background-color:#5c6bc0!important}.indigo-text.text-lighten-1{color:#5c6bc0!important}.indigo.darken-1{background-color:#3949ab!important}.indigo-text.text-darken-1{color:#3949ab!important}.indigo.darken-2{background-color:#303f9f!important}.indigo-text.text-darken-2{color:#303f9f!important}.indigo.darken-3{background-color:#283593!important}.indigo-text.text-darken-3{color:#283593!important}.indigo.darken-4{background-color:#1a237e!important}.indigo-text.text-darken-4{color:#1a237e!important}.indigo.accent-1{background-color:#8c9eff!important}.indigo-text.text-accent-1{color:#8c9eff!important}.indigo.accent-2{background-color:#536dfe!important}.indigo-text.text-accent-2{color:#536dfe!important}.indigo.accent-3{background-color:#3d5afe!important}.indigo-text.text-accent-3{color:#3d5afe!important}.indigo.accent-4{background-color:#304ffe!important}.indigo-text.text-accent-4{color:#304ffe!important}.blue{background-color:#2196F3!important}.blue-text{color:#2196F3!important}.blue.lighten-5{background-color:#E3F2FD!important}.blue-text.text-lighten-5{color:#E3F2FD!important}.blue.lighten-4{background-color:#BBDEFB!important}.blue-text.text-lighten-4{color:#BBDEFB!important}.blue.lighten-3{background-color:#90CAF9!important}.blue-text.text-lighten-3{color:#90CAF9!important}.blue.lighten-2{background-color:#64B5F6!important}.blue-text.text-lighten-2{color:#64B5F6!important}.blue.lighten-1{background-color:#42A5F5!important}.blue-text.text-lighten-1{color:#42A5F5!important}.blue.darken-1{background-color:#1E88E5!important}.blue-text.text-darken-1{color:#1E88E5!important}.blue.darken-2{background-color:#1976D2!important}.blue-text.text-darken-2{color:#1976D2!important}.blue.darken-3{background-color:#1565C0!important}.blue-text.text-darken-3{color:#1565C0!important}.blue.darken-4{background-color:#0D47A1!important}.blue-text.text-darken-4{color:#0D47A1!important}.blue.accent-1{background-color:#82B1FF!important}.blue-text.text-accent-1{color:#82B1FF!important}.blue.accent-2{background-color:#448AFF!important}.blue-text.text-accent-2{color:#448AFF!important}.blue.accent-3{background-color:#2979FF!important}.blue-text.text-accent-3{color:#2979FF!important}.blue.accent-4{background-color:#2962FF!important}.blue-text.text-accent-4{color:#2962FF!important}.light-blue{background-color:#03a9f4!important}.light-blue-text{color:#03a9f4!important}.light-blue.lighten-5{background-color:#e1f5fe!important}.light-blue-text.text-lighten-5{color:#e1f5fe!important}.light-blue.lighten-4{background-color:#b3e5fc!important}.light-blue-text.text-lighten-4{color:#b3e5fc!important}.light-blue.lighten-3{background-color:#81d4fa!important}.light-blue-text.text-lighten-3{color:#81d4fa!important}.light-blue.lighten-2{background-color:#4fc3f7!important}.light-blue-text.text-lighten-2{color:#4fc3f7!important}.light-blue.lighten-1{background-color:#29b6f6!important}.light-blue-text.text-lighten-1{color:#29b6f6!important}.light-blue.darken-1{background-color:#039be5!important}.light-blue-text.text-darken-1{color:#039be5!important}.light-blue.darken-2{background-color:#0288d1!important}.light-blue-text.text-darken-2{color:#0288d1!important}.light-blue.darken-3{background-color:#0277bd!important}.light-blue-text.text-darken-3{color:#0277bd!important}.light-blue.darken-4{background-color:#01579b!important}.light-blue-text.text-darken-4{color:#01579b!important}.light-blue.accent-1{background-color:#80d8ff!important}.light-blue-text.text-accent-1{color:#80d8ff!important}.light-blue.accent-2{background-color:#40c4ff!important}.light-blue-text.text-accent-2{color:#40c4ff!important}.light-blue.accent-3{background-color:#00b0ff!important}.light-blue-text.text-accent-3{color:#00b0ff!important}.light-blue.accent-4{background-color:#0091ea!important}.light-blue-text.text-accent-4{color:#0091ea!important}.cyan{background-color:#00bcd4!important}.cyan-text{color:#00bcd4!important}.cyan.lighten-5{background-color:#e0f7fa!important}.cyan-text.text-lighten-5{color:#e0f7fa!important}.cyan.lighten-4{background-color:#b2ebf2!important}.cyan-text.text-lighten-4{color:#b2ebf2!important}.cyan.lighten-3{background-color:#80deea!important}.cyan-text.text-lighten-3{color:#80deea!important}.cyan.lighten-2{background-color:#4dd0e1!important}.cyan-text.text-lighten-2{color:#4dd0e1!important}.cyan.lighten-1{background-color:#26c6da!important}.cyan-text.text-lighten-1{color:#26c6da!important}.cyan.darken-1{background-color:#00acc1!important}.cyan-text.text-darken-1{color:#00acc1!important}.cyan.darken-2{background-color:#0097a7!important}.cyan-text.text-darken-2{color:#0097a7!important}.cyan.darken-3{background-color:#00838f!important}.cyan-text.text-darken-3{color:#00838f!important}.cyan.darken-4{background-color:#006064!important}.cyan-text.text-darken-4{color:#006064!important}.cyan.accent-1{background-color:#84ffff!important}.cyan-text.text-accent-1{color:#84ffff!important}.cyan.accent-2{background-color:#18ffff!important}.cyan-text.text-accent-2{color:#18ffff!important}.cyan.accent-3{background-color:#00e5ff!important}.cyan-text.text-accent-3{color:#00e5ff!important}.cyan.accent-4{background-color:#00b8d4!important}.cyan-text.text-accent-4{color:#00b8d4!important}.teal{background-color:#009688!important}.teal-text{color:#009688!important}.teal.lighten-5{background-color:#e0f2f1!important}.teal-text.text-lighten-5{color:#e0f2f1!important}.teal.lighten-4{background-color:#b2dfdb!important}.teal-text.text-lighten-4{color:#b2dfdb!important}.teal.lighten-3{background-color:#80cbc4!important}.teal-text.text-lighten-3{color:#80cbc4!important}.teal.lighten-2{background-color:#4db6ac!important}.teal-text.text-lighten-2{color:#4db6ac!important}.teal.lighten-1{background-color:#26a69a!important}.teal-text.text-lighten-1{color:#26a69a!important}.teal.darken-1{background-color:#00897b!important}.teal-text.text-darken-1{color:#00897b!important}.teal.darken-2{background-color:#00796b!important}.teal-text.text-darken-2{color:#00796b!important}.teal.darken-3{background-color:#00695c!important}.teal-text.text-darken-3{color:#00695c!important}.teal.darken-4{background-color:#004d40!important}.teal-text.text-darken-4{color:#004d40!important}.teal.accent-1{background-color:#a7ffeb!important}.teal-text.text-accent-1{color:#a7ffeb!important}.teal.accent-2{background-color:#64ffda!important}.teal-text.text-accent-2{color:#64ffda!important}.teal.accent-3{background-color:#1de9b6!important}.teal-text.text-accent-3{color:#1de9b6!important}.teal.accent-4{background-color:#00bfa5!important}.teal-text.text-accent-4{color:#00bfa5!important}.green{background-color:#4CAF50!important}.green-text{color:#4CAF50!important}.green.lighten-5{background-color:#E8F5E9!important}.green-text.text-lighten-5{color:#E8F5E9!important}.green.lighten-4{background-color:#C8E6C9!important}.green-text.text-lighten-4{color:#C8E6C9!important}.green.lighten-3{background-color:#A5D6A7!important}.green-text.text-lighten-3{color:#A5D6A7!important}.green.lighten-2{background-color:#81C784!important}.green-text.text-lighten-2{color:#81C784!important}.green.lighten-1{background-color:#66BB6A!important}.green-text.text-lighten-1{color:#66BB6A!important}.green.darken-1{background-color:#43A047!important}.green-text.text-darken-1{color:#43A047!important}.green.darken-2{background-color:#388E3C!important}.green-text.text-darken-2{color:#388E3C!important}.green.darken-3{background-color:#2E7D32!important}.green-text.text-darken-3{color:#2E7D32!important}.green.darken-4{background-color:#1B5E20!important}.green-text.text-darken-4{color:#1B5E20!important}.green.accent-1{background-color:#B9F6CA!important}.green-text.text-accent-1{color:#B9F6CA!important}.green.accent-2{background-color:#69F0AE!important}.green-text.text-accent-2{color:#69F0AE!important}.green.accent-3{background-color:#00E676!important}.green-text.text-accent-3{color:#00E676!important}.green.accent-4{background-color:#00C853!important}.green-text.text-accent-4{color:#00C853!important}.light-green{background-color:#8bc34a!important}.light-green-text{color:#8bc34a!important}.light-green.lighten-5{background-color:#f1f8e9!important}.light-green-text.text-lighten-5{color:#f1f8e9!important}.light-green.lighten-4{background-color:#dcedc8!important}.light-green-text.text-lighten-4{color:#dcedc8!important}.light-green.lighten-3{background-color:#c5e1a5!important}.light-green-text.text-lighten-3{color:#c5e1a5!important}.light-green.lighten-2{background-color:#aed581!important}.light-green-text.text-lighten-2{color:#aed581!important}.light-green.lighten-1{background-color:#9ccc65!important}.light-green-text.text-lighten-1{color:#9ccc65!important}.light-green.darken-1{background-color:#7cb342!important}.light-green-text.text-darken-1{color:#7cb342!important}.light-green.darken-2{background-color:#689f38!important}.light-green-text.text-darken-2{color:#689f38!important}.light-green.darken-3{background-color:#558b2f!important}.light-green-text.text-darken-3{color:#558b2f!important}.light-green.darken-4{background-color:#33691e!important}.light-green-text.text-darken-4{color:#33691e!important}.light-green.accent-1{background-color:#ccff90!important}.light-green-text.text-accent-1{color:#ccff90!important}.light-green.accent-2{background-color:#b2ff59!important}.light-green-text.text-accent-2{color:#b2ff59!important}.light-green.accent-3{background-color:#76ff03!important}.light-green-text.text-accent-3{color:#76ff03!important}.light-green.accent-4{background-color:#64dd17!important}.light-green-text.text-accent-4{color:#64dd17!important}.lime{background-color:#cddc39!important}.lime-text{color:#cddc39!important}.lime.lighten-5{background-color:#f9fbe7!important}.lime-text.text-lighten-5{color:#f9fbe7!important}.lime.lighten-4{background-color:#f0f4c3!important}.lime-text.text-lighten-4{color:#f0f4c3!important}.lime.lighten-3{background-color:#e6ee9c!important}.lime-text.text-lighten-3{color:#e6ee9c!important}.lime.lighten-2{background-color:#dce775!important}.lime-text.text-lighten-2{color:#dce775!important}.lime.lighten-1{background-color:#d4e157!important}.lime-text.text-lighten-1{color:#d4e157!important}.lime.darken-1{background-color:#c0ca33!important}.lime-text.text-darken-1{color:#c0ca33!important}.lime.darken-2{background-color:#afb42b!important}.lime-text.text-darken-2{color:#afb42b!important}.lime.darken-3{background-color:#9e9d24!important}.lime-text.text-darken-3{color:#9e9d24!important}.lime.darken-4{background-color:#827717!important}.lime-text.text-darken-4{color:#827717!important}.lime.accent-1{background-color:#f4ff81!important}.lime-text.text-accent-1{color:#f4ff81!important}.lime.accent-2{background-color:#eeff41!important}.lime-text.text-accent-2{color:#eeff41!important}.lime.accent-3{background-color:#c6ff00!important}.lime-text.text-accent-3{color:#c6ff00!important}.lime.accent-4{background-color:#aeea00!important}.lime-text.text-accent-4{color:#aeea00!important}.yellow{background-color:#ffeb3b!important}.yellow-text{color:#ffeb3b!important}.yellow.lighten-5{background-color:#fffde7!important}.yellow-text.text-lighten-5{color:#fffde7!important}.yellow.lighten-4{background-color:#fff9c4!important}.yellow-text.text-lighten-4{color:#fff9c4!important}.yellow.lighten-3{background-color:#fff59d!important}.yellow-text.text-lighten-3{color:#fff59d!important}.yellow.lighten-2{background-color:#fff176!important}.yellow-text.text-lighten-2{color:#fff176!important}.yellow.lighten-1{background-color:#ffee58!important}.yellow-text.text-lighten-1{color:#ffee58!important}.yellow.darken-1{background-color:#fdd835!important}.yellow-text.text-darken-1{color:#fdd835!important}.yellow.darken-2{background-color:#fbc02d!important}.yellow-text.text-darken-2{color:#fbc02d!important}.yellow.darken-3{background-color:#f9a825!important}.yellow-text.text-darken-3{color:#f9a825!important}.yellow.darken-4{background-color:#f57f17!important}.yellow-text.text-darken-4{color:#f57f17!important}.yellow.accent-1{background-color:#ffff8d!important}.yellow-text.text-accent-1{color:#ffff8d!important}.yellow.accent-2{background-color:#ff0!important}.yellow-text.text-accent-2{color:#ff0!important}.yellow.accent-3{background-color:#ffea00!important}.yellow-text.text-accent-3{color:#ffea00!important}.yellow.accent-4{background-color:#ffd600!important}.yellow-text.text-accent-4{color:#ffd600!important}.amber{background-color:#ffc107!important}.amber-text{color:#ffc107!important}.amber.lighten-5{background-color:#fff8e1!important}.amber-text.text-lighten-5{color:#fff8e1!important}.amber.lighten-4{background-color:#ffecb3!important}.amber-text.text-lighten-4{color:#ffecb3!important}.amber.lighten-3{background-color:#ffe082!important}.amber-text.text-lighten-3{color:#ffe082!important}.amber.lighten-2{background-color:#ffd54f!important}.amber-text.text-lighten-2{color:#ffd54f!important}.amber.lighten-1{background-color:#ffca28!important}.amber-text.text-lighten-1{color:#ffca28!important}.amber.darken-1{background-color:#ffb300!important}.amber-text.text-darken-1{color:#ffb300!important}.amber.darken-2{background-color:#ffa000!important}.amber-text.text-darken-2{color:#ffa000!important}.amber.darken-3{background-color:#ff8f00!important}.amber-text.text-darken-3{color:#ff8f00!important}.amber.darken-4{background-color:#ff6f00!important}.amber-text.text-darken-4{color:#ff6f00!important}.amber.accent-1{background-color:#ffe57f!important}.amber-text.text-accent-1{color:#ffe57f!important}.amber.accent-2{background-color:#ffd740!important}.amber-text.text-accent-2{color:#ffd740!important}.amber.accent-3{background-color:#ffc400!important}.amber-text.text-accent-3{color:#ffc400!important}.amber.accent-4{background-color:#ffab00!important}.amber-text.text-accent-4{color:#ffab00!important}.orange{background-color:#ff9800!important}.orange-text{color:#ff9800!important}.orange.lighten-5{background-color:#fff3e0!important}.orange-text.text-lighten-5{color:#fff3e0!important}.orange.lighten-4{background-color:#ffe0b2!important}.orange-text.text-lighten-4{color:#ffe0b2!important}.orange.lighten-3{background-color:#ffcc80!important}.orange-text.text-lighten-3{color:#ffcc80!important}.orange.lighten-2{background-color:#ffb74d!important}.orange-text.text-lighten-2{color:#ffb74d!important}.orange.lighten-1{background-color:#ffa726!important}.orange-text.text-lighten-1{color:#ffa726!important}.orange.darken-1{background-color:#fb8c00!important}.orange-text.text-darken-1{color:#fb8c00!important}.orange.darken-2{background-color:#f57c00!important}.orange-text.text-darken-2{color:#f57c00!important}.orange.darken-3{background-color:#ef6c00!important}.orange-text.text-darken-3{color:#ef6c00!important}.orange.darken-4{background-color:#e65100!important}.orange-text.text-darken-4{color:#e65100!important}.orange.accent-1{background-color:#ffd180!important}.orange-text.text-accent-1{color:#ffd180!important}.orange.accent-2{background-color:#ffab40!important}.orange-text.text-accent-2{color:#ffab40!important}.orange.accent-3{background-color:#ff9100!important}.orange-text.text-accent-3{color:#ff9100!important}.orange.accent-4{background-color:#ff6d00!important}.orange-text.text-accent-4{color:#ff6d00!important}.deep-orange{background-color:#ff5722!important}.deep-orange-text{color:#ff5722!important}.deep-orange.lighten-5{background-color:#fbe9e7!important}.deep-orange-text.text-lighten-5{color:#fbe9e7!important}.deep-orange.lighten-4{background-color:#ffccbc!important}.deep-orange-text.text-lighten-4{color:#ffccbc!important}.deep-orange.lighten-3{background-color:#ffab91!important}.deep-orange-text.text-lighten-3{color:#ffab91!important}.deep-orange.lighten-2{background-color:#ff8a65!important}.deep-orange-text.text-lighten-2{color:#ff8a65!important}.deep-orange.lighten-1{background-color:#ff7043!important}.deep-orange-text.text-lighten-1{color:#ff7043!important}.deep-orange.darken-1{background-color:#f4511e!important}.deep-orange-text.text-darken-1{color:#f4511e!important}.deep-orange.darken-2{background-color:#e64a19!important}.deep-orange-text.text-darken-2{color:#e64a19!important}.deep-orange.darken-3{background-color:#d84315!important}.deep-orange-text.text-darken-3{color:#d84315!important}.deep-orange.darken-4{background-color:#bf360c!important}.deep-orange-text.text-darken-4{color:#bf360c!important}.deep-orange.accent-1{background-color:#ff9e80!important}.deep-orange-text.text-accent-1{color:#ff9e80!important}.deep-orange.accent-2{background-color:#ff6e40!important}.deep-orange-text.text-accent-2{color:#ff6e40!important}.deep-orange.accent-3{background-color:#ff3d00!important}.deep-orange-text.text-accent-3{color:#ff3d00!important}.deep-orange.accent-4{background-color:#dd2c00!important}.deep-orange-text.text-accent-4{color:#dd2c00!important}.brown{background-color:#795548!important}.brown-text{color:#795548!important}.brown.lighten-5{background-color:#efebe9!important}.brown-text.text-lighten-5{color:#efebe9!important}.brown.lighten-4{background-color:#d7ccc8!important}.brown-text.text-lighten-4{color:#d7ccc8!important}.brown.lighten-3{background-color:#bcaaa4!important}.brown-text.text-lighten-3{color:#bcaaa4!important}.brown.lighten-2{background-color:#a1887f!important}.brown-text.text-lighten-2{color:#a1887f!important}.brown.lighten-1{background-color:#8d6e63!important}.brown-text.text-lighten-1{color:#8d6e63!important}.brown.darken-1{background-color:#6d4c41!important}.brown-text.text-darken-1{color:#6d4c41!important}.brown.darken-2{background-color:#5d4037!important}.brown-text.text-darken-2{color:#5d4037!important}.brown.darken-3{background-color:#4e342e!important}.brown-text.text-darken-3{color:#4e342e!important}.brown.darken-4{background-color:#3e2723!important}.brown-text.text-darken-4{color:#3e2723!important}.blue-grey{background-color:#607d8b!important}.blue-grey-text{color:#607d8b!important}.blue-grey.lighten-5{background-color:#eceff1!important}.blue-grey-text.text-lighten-5{color:#eceff1!important}.blue-grey.lighten-4{background-color:#cfd8dc!important}.blue-grey-text.text-lighten-4{color:#cfd8dc!important}.blue-grey.lighten-3{background-color:#b0bec5!important}.blue-grey-text.text-lighten-3{color:#b0bec5!important}.blue-grey.lighten-2{background-color:#90a4ae!important}.blue-grey-text.text-lighten-2{color:#90a4ae!important}.blue-grey.lighten-1{background-color:#78909c!important}.blue-grey-text.text-lighten-1{color:#78909c!important}.blue-grey.darken-1{background-color:#546e7a!important}.blue-grey-text.text-darken-1{color:#546e7a!important}.blue-grey.darken-2{background-color:#455a64!important}.blue-grey-text.text-darken-2{color:#455a64!important}.blue-grey.darken-3{background-color:#37474f!important}.blue-grey-text.text-darken-3{color:#37474f!important}.blue-grey.darken-4{background-color:#263238!important}.blue-grey-text.text-darken-4{color:#263238!important}.grey{background-color:#9e9e9e!important}.grey-text{color:#9e9e9e!important}.grey.lighten-5{background-color:#fafafa!important}.grey-text.text-lighten-5{color:#fafafa!important}.grey.lighten-4{background-color:#f5f5f5!important}.grey-text.text-lighten-4{color:#f5f5f5!important}.grey.lighten-3{background-color:#eee!important}.grey-text.text-lighten-3{color:#eee!important}.grey.lighten-2{background-color:#e0e0e0!important}.grey-text.text-lighten-2{color:#e0e0e0!important}.grey.lighten-1{background-color:#bdbdbd!important}.grey-text.text-lighten-1{color:#bdbdbd!important}.grey.darken-1{background-color:#757575!important}.grey-text.text-darken-1{color:#757575!important}.grey.darken-2{background-color:#616161!important}.grey-text.text-darken-2{color:#616161!important}.grey.darken-3{background-color:#424242!important}.grey-text.text-darken-3{color:#424242!important}.grey.darken-4{background-color:#212121!important}.grey-text.text-darken-4{color:#212121!important}.black{background-color:#000!important}.black-text{color:#000!important}.white{background-color:#FFF!important}.white-text{color:#FFF!important}.transparent{background-color:transparent!important}.transparent-text{color:transparent!important} + +body,p{color:#8a8a8a;font-family:Roboto,-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI","Helvetica Neue",Arial,sans-serif}.font-primary,body,p{font-family:Roboto,-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI","Helvetica Neue",Arial,sans-serif}label,ul{margin-bottom:0}dd,p{margin-bottom:10px}.m-h-0,.m-l-0{margin-left:0!important}.m-h-0,.m-r-0{margin-right:0!important}.p-t-0,.p-v-0{padding-top:0!important}.p-b-0,.p-v-0{padding-bottom:0!important}.p-h-0,.p-r-0{padding-right:0!important}.relative,blockquote{position:relative}.overflow-x-hidden,body{overflow-x:hidden}.header,.side-nav{transition:all .2s ease}.header .header-container:after,.side-nav .side-nav-inner .side-nav-menu:after{clear:both}.pointer,button{cursor:pointer}body,html,html a{-webkit-font-smoothing:antialiased}body{font-size:14px;background-color:#f7fbff;line-height:1.5}h1,h2,h3,h4,h5,h6{color:#515365;font-weight:400;line-height:1.5}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:300;color:#5c5f73}h1{font-size:28px}h2{font-size:24px}h3{font-size:22px}h4{font-size:19px}h5{font-size:17px}h6{font-size:12px}p{line-height:1.8}.lead{font-size:18px}a{color:#04a1f4}a:focus,a:hover{text-decoration:none;color:#0380c2}a:focus{outline:0}a.text-gray:focus,a.text-gray:hover{color:#515365!important}a.text-gray.active{color:#04a1f4!important}a.hover-opacity:hover{opacity:.8}:focus{outline:0}hr{border-top:1px solid #e9eaec;margin-top:2rem;margin-bottom:2rem}.text-link:focus,.text-link:hover{text-decoration:underline}.text-opacity{opacity:.85}.text-white{color:#fff!important}.text-dark{color:#515365!important}.text-gray{color:#8a8a8a!important}.text-secondary{color:#cacaca!important}.text-primary{color:#6569df!important}.text-success{color:#24d5d8!important}.text-info{color:#04a1f4!important}.text-warning{color:#fecd2f!important}.text-danger{color:#fd3259!important}.icon-gradient-primary{color:#6569df}.icon-gradient-primary:before{background:linear-gradient(120deg,#b603c1 0,#7a38e0 100%);background-clip:text;-webkit-background-clip:text;-webkit-text-fill-color:transparent}.icon-gradient-success{color:#24d5d8}.icon-gradient-success:before{background:linear-gradient(120deg,#1dccdf 0,#1de4bd 100%);background-clip:text;-webkit-background-clip:text;-webkit-text-fill-color:transparent}.icon-gradient-warning{color:#fecd2f}.icon-gradient-warning:before{background:linear-gradient(120deg,#f6d365 0,#fda085 100%);background-clip:text;-webkit-background-clip:text;-webkit-text-fill-color:transparent}.icon-gradient-danger{color:#fd3259}.icon-gradient-danger:before{background:linear-gradient(120deg,#f3301a 0,#f37138 100%);background-clip:text;-webkit-background-clip:text;-webkit-text-fill-color:transparent}.icon-gradient-info{color:#04a1f4}.blockquote-footer,.side-nav .side-nav-inner .side-nav-menu li.dropdown.open>a,.side-nav .side-nav-inner .side-nav-menu li.dropdown.open>a .icon-holder,dt{color:#515365}.icon-gradient-info:before{background:linear-gradient(120deg,#6a4ee1 0,#05bdd7 100%);background-clip:text;-webkit-background-clip:text;-webkit-text-fill-color:transparent}.bg-white{background-color:#fff!important}.bg-dark{background-color:#515365!important}.bg-gray{background-color:#fafafa!important}.bg-primary{background-color:#6569df!important}.bg-success{background-color:#24d5d8!important}.bg-info{background-color:#04a1f4!important}.bg-warning{background-color:#fecd2f!important}.bg-danger{background-color:#fd3259!important}.bg-gradient-primary{background:linear-gradient(120deg,#b603c1 0,#7a38e0 100%)!important}.bg-gradient-success{background:linear-gradient(120deg,#1dccdf 0,#1de4bd 100%)!important}.bg-gradient-info{background:linear-gradient(120deg,#6a4ee1 0,#05bdd7 100%)!important}.bg-gradient-warning{background:linear-gradient(120deg,#f6d365 0,#fda085 100%)!important}.bg-gradient-danger{background:linear-gradient(120deg,#f3301a 0,#f37138 100%)!important}.bg-facebook{background-color:#3B579D!important}.bg-twitter{background-color:#2CAAE1!important}.bg-google-plus{background-color:#dc473c!important}.bg-instagram{background-color:#40719b!important}.bg-dropbox{background-color:#007EE6!important}.bg-dribbble{background-color:#ea4c89!important}.bg-behance{background-color:#1869ff!important}.bg-html5{background-color:#f16528!important}.bg-wordpress{background-color:#0087be!important}.bg-tumblr{background-color:#36465d!important}.bg-skype{background-color:#00AAF1!important}.bg-youtube{background-color:#DE2825!important}.bg-vimeo{background-color:#1BB6EC!important}.bg-linkedin{background-color:#0177b5!important}.bg-pinterest{background-color:#c9181f!important}.img-fit-cover{width:100%;height:100%;object-fit:cover}.bg{background-repeat:no-repeat;background-size:cover;background-position:center center}.container-fluid.container-fixed-lg{max-width:1700px}.container-fluid.container-fixed-md{max-width:1400px}.container-fluid.container-fixed-sm{max-width:1280px}button,input,textarea{outline:0}blockquote{border-left:0;padding-left:30px}.p-h-0,.p-l-0{padding-left:0!important}dt{font-weight:500}.m-b-0,.m-v-0{margin-bottom:0!important}.fade.in{opacity:1}.collapse.in{display:block}iframe{border:0}@media print{body{font-size:10px}.mrg-top-20,.mrg-top-30{margin-top:15px!important}.print-invisible{display:none}}.m-t-0,.m-v-0{margin-top:0!important}.m-0{margin:0!important}.m-5{margin:5px!important}.m-10{margin:10px!important}.m-15{margin:15px!important}.m-20{margin:20px!important}.m-25{margin:25px!important}.m-30{margin:30px!important}.m-35{margin:35px!important}.m-40{margin:40px!important}.m-45{margin:45px!important}.m-50{margin:50px!important}.m-55{margin:55px!important}.m-60{margin:60px!important}.m-65{margin:65px!important}.m-70{margin:70px!important}.m-75{margin:75px!important}.m-80{margin:80px!important}.m-85{margin:85px!important}.m-90{margin:90px!important}.m-95{margin:95px!important}.m-100{margin:100px!important}.m-105{margin:105px!important}.m-110{margin:110px!important}.m-115{margin:115px!important}.m-120{margin:120px!important}.m-125{margin:125px!important}.m-130{margin:130px!important}.m-135{margin:135px!important}.m-140{margin:140px!important}.m-145{margin:145px!important}.m-150{margin:150px!important}@media only screen and (max-width:767px){iframe{min-height:175px!important;height:auto}.m-100,.m-110,.m-115,.m-120,.m-125,.m-130,.m-135,.m-140,.m-145,.m-150,.m-35,.m-40,.m-45,.m-50,.m-55,.m-60,.m-65,.m-70,.m-75,.m-80,.m-85,.m-90,.m-95{margin:30px!important}}.m-h-auto,.m-l-auto{margin-left:auto!important}.m-h-auto,.m-r-auto{margin-right:auto!important}.m-v-5{margin-top:5px!important;margin-bottom:5px!important}.m-v-10{margin-top:10px!important;margin-bottom:10px!important}.m-v-15{margin-top:15px!important;margin-bottom:15px!important}.m-v-20{margin-top:20px!important;margin-bottom:20px!important}.m-v-25{margin-top:25px!important;margin-bottom:25px!important}.m-v-30{margin-top:30px!important;margin-bottom:30px!important}.m-v-35{margin-top:35px!important;margin-bottom:35px!important}.m-v-40{margin-top:40px!important;margin-bottom:40px!important}.m-v-45{margin-top:45px!important;margin-bottom:45px!important}.m-v-50{margin-top:50px!important;margin-bottom:50px!important}.m-v-55{margin-top:55px!important;margin-bottom:55px!important}.m-v-60{margin-top:60px!important;margin-bottom:60px!important}.m-v-65{margin-top:65px!important;margin-bottom:65px!important}.m-v-70{margin-top:70px!important;margin-bottom:70px!important}.m-v-75{margin-top:75px!important;margin-bottom:75px!important}.m-v-80{margin-top:80px!important;margin-bottom:80px!important}.m-v-85{margin-top:85px!important;margin-bottom:85px!important}.m-v-90{margin-top:90px!important;margin-bottom:90px!important}.m-v-95{margin-top:95px!important;margin-bottom:95px!important}.m-v-100{margin-top:100px!important;margin-bottom:100px!important}.m-v-105{margin-top:105px!important;margin-bottom:105px!important}.m-v-110{margin-top:110px!important;margin-bottom:110px!important}.m-v-115{margin-top:115px!important;margin-bottom:115px!important}.m-v-120{margin-top:120px!important;margin-bottom:120px!important}.m-v-125{margin-top:125px!important;margin-bottom:125px!important}.m-v-130{margin-top:130px!important;margin-bottom:130px!important}.m-v-135{margin-top:135px!important;margin-bottom:135px!important}.m-v-140{margin-top:140px!important;margin-bottom:140px!important}.m-v-145{margin-top:145px!important;margin-bottom:145px!important}.m-v-150{margin-top:150px!important;margin-bottom:150px!important}.m-h-5{margin-left:5px!important;margin-right:5px!important}.m-h-10{margin-left:10px!important;margin-right:10px!important}.m-h-15{margin-left:15px!important;margin-right:15px!important}.m-h-20{margin-left:20px!important;margin-right:20px!important}.m-h-25{margin-left:25px!important;margin-right:25px!important}.m-h-30{margin-left:30px!important;margin-right:30px!important}.m-h-35{margin-left:35px!important;margin-right:35px!important}.m-h-40{margin-left:40px!important;margin-right:40px!important}.m-h-45{margin-left:45px!important;margin-right:45px!important}.m-h-50{margin-left:50px!important;margin-right:50px!important}.m-h-55{margin-left:55px!important;margin-right:55px!important}.m-h-60{margin-left:60px!important;margin-right:60px!important}.m-h-65{margin-left:65px!important;margin-right:65px!important}.m-h-70{margin-left:70px!important;margin-right:70px!important}.m-h-75{margin-left:75px!important;margin-right:75px!important}.m-h-80{margin-left:80px!important;margin-right:80px!important}.m-h-85{margin-left:85px!important;margin-right:85px!important}.m-h-90{margin-left:90px!important;margin-right:90px!important}.m-h-95{margin-left:95px!important;margin-right:95px!important}.m-h-100{margin-left:100px!important;margin-right:100px!important}.m-h-105{margin-left:105px!important;margin-right:105px!important}.m-h-110{margin-left:110px!important;margin-right:110px!important}.m-h-115{margin-left:115px!important;margin-right:115px!important}.m-h-120{margin-left:120px!important;margin-right:120px!important}.m-h-125{margin-left:125px!important;margin-right:125px!important}.m-h-130{margin-left:130px!important;margin-right:130px!important}.m-h-135{margin-left:135px!important;margin-right:135px!important}.m-h-140{margin-left:140px!important;margin-right:140px!important}.m-h-145{margin-left:145px!important;margin-right:145px!important}.m-h-150{margin-left:150px!important;margin-right:150px!important}@media only screen and (max-width:767px){.m-v-100,.m-v-110,.m-v-115,.m-v-120,.m-v-125,.m-v-130,.m-v-135,.m-v-140,.m-v-145,.m-v-150,.m-v-35,.m-v-40,.m-v-45,.m-v-50,.m-v-55,.m-v-60,.m-v-65,.m-v-70,.m-v-75,.m-v-80,.m-v-85,.m-v-90,.m-v-95{margin-top:30px!important;margin-bottom:30px!important}.m-h-100,.m-h-110,.m-h-115,.m-h-120,.m-h-125,.m-h-130,.m-h-135,.m-h-140,.m-h-145,.m-h-150,.m-h-35,.m-h-40,.m-h-45,.m-h-50,.m-h-55,.m-h-60,.m-h-65,.m-h-70,.m-h-75,.m-h-80,.m-h-85,.m-h-90,.m-h-95{margin-left:30px!important;margin-right:30px!important}}.m-t-5{margin-top:5px!important}.m-t-10{margin-top:10px!important}.m-t-15{margin-top:15px!important}.m-t-20{margin-top:20px!important}.m-t-25{margin-top:25px!important}.m-t-30{margin-top:30px!important}.m-t-35{margin-top:35px!important}.m-t-40{margin-top:40px!important}.m-t-45{margin-top:45px!important}.m-t-50{margin-top:50px!important}.m-t-55{margin-top:55px!important}.m-t-60{margin-top:60px!important}.m-t-65{margin-top:65px!important}.m-t-70{margin-top:70px!important}.m-t-75{margin-top:75px!important}.m-t-80{margin-top:80px!important}.m-t-85{margin-top:85px!important}.m-t-90{margin-top:90px!important}.m-t-95{margin-top:95px!important}.m-t-100{margin-top:100px!important}.m-t-105{margin-top:105px!important}.m-t-110{margin-top:110px!important}.m-t-115{margin-top:115px!important}.m-t-120{margin-top:120px!important}.m-t-125{margin-top:125px!important}.m-t-130{margin-top:130px!important}.m-t-135{margin-top:135px!important}.m-t-140{margin-top:140px!important}.m-t-145{margin-top:145px!important}.m-t-150{margin-top:150px!important}.m-b-5{margin-bottom:5px!important}.m-b-10{margin-bottom:10px!important}.m-b-15{margin-bottom:15px!important}.m-b-20{margin-bottom:20px!important}.m-b-25{margin-bottom:25px!important}.m-b-30{margin-bottom:30px!important}.m-b-35{margin-bottom:35px!important}.m-b-40{margin-bottom:40px!important}.m-b-45{margin-bottom:45px!important}.m-b-50{margin-bottom:50px!important}.m-b-55{margin-bottom:55px!important}.m-b-60{margin-bottom:60px!important}.m-b-65{margin-bottom:65px!important}.m-b-70{margin-bottom:70px!important}.m-b-75{margin-bottom:75px!important}.m-b-80{margin-bottom:80px!important}.m-b-85{margin-bottom:85px!important}.m-b-90{margin-bottom:90px!important}.m-b-95{margin-bottom:95px!important}.m-b-100{margin-bottom:100px!important}.m-b-105{margin-bottom:105px!important}.m-b-110{margin-bottom:110px!important}.m-b-115{margin-bottom:115px!important}.m-b-120{margin-bottom:120px!important}.m-b-125{margin-bottom:125px!important}.m-b-130{margin-bottom:130px!important}.m-b-135{margin-bottom:135px!important}.m-b-140{margin-bottom:140px!important}.m-b-145{margin-bottom:145px!important}.m-b-150{margin-bottom:150px!important}.m-l-5{margin-left:5px!important}.m-l-10{margin-left:10px!important}.m-l-15{margin-left:15px!important}.m-l-20{margin-left:20px!important}.m-l-25{margin-left:25px!important}.m-l-30{margin-left:30px!important}.m-l-35{margin-left:35px!important}.m-l-40{margin-left:40px!important}.m-l-45{margin-left:45px!important}.m-l-50{margin-left:50px!important}.m-l-55{margin-left:55px!important}.m-l-60{margin-left:60px!important}.m-l-65{margin-left:65px!important}.m-l-70{margin-left:70px!important}.m-l-75{margin-left:75px!important}.m-l-80{margin-left:80px!important}.m-l-85{margin-left:85px!important}.m-l-90{margin-left:90px!important}.m-l-95{margin-left:95px!important}.m-l-100{margin-left:100px!important}.m-l-105{margin-left:105px!important}.m-l-110{margin-left:110px!important}.m-l-115{margin-left:115px!important}.m-l-120{margin-left:120px!important}.m-l-125{margin-left:125px!important}.m-l-130{margin-left:130px!important}.m-l-135{margin-left:135px!important}.m-l-140{margin-left:140px!important}.m-l-145{margin-left:145px!important}.m-l-150{margin-left:150px!important}.m-r-5{margin-right:5px!important}.m-r-10{margin-right:10px!important}.m-r-15{margin-right:15px!important}.m-r-20{margin-right:20px!important}.m-r-25{margin-right:25px!important}.m-r-30{margin-right:30px!important}.m-r-35{margin-right:35px!important}.m-r-40{margin-right:40px!important}.m-r-45{margin-right:45px!important}.m-r-50{margin-right:50px!important}.m-r-55{margin-right:55px!important}.m-r-60{margin-right:60px!important}.m-r-65{margin-right:65px!important}.m-r-70{margin-right:70px!important}.m-r-75{margin-right:75px!important}.m-r-80{margin-right:80px!important}.m-r-85{margin-right:85px!important}.m-r-90{margin-right:90px!important}.m-r-95{margin-right:95px!important}.m-r-100{margin-right:100px!important}.m-r-105{margin-right:105px!important}.m-r-110{margin-right:110px!important}.m-r-115{margin-right:115px!important}.m-r-120{margin-right:120px!important}.m-r-125{margin-right:125px!important}.m-r-130{margin-right:130px!important}.m-r-135{margin-right:135px!important}.m-r-140{margin-right:140px!important}.m-r-145{margin-right:145px!important}.m-r-150{margin-right:150px!important}.p-0{padding:0!important}.p-5{padding:5px!important}.p-10{padding:10px!important}.p-15{padding:15px!important}.p-20{padding:20px!important}.p-25{padding:25px!important}.p-30{padding:30px!important}.p-35{padding:35px!important}.p-40{padding:40px!important}.p-45{padding:45px!important}.p-50{padding:50px!important}.p-55{padding:55px!important}.p-60{padding:60px!important}.p-65{padding:65px!important}.p-70{padding:70px!important}.p-75{padding:75px!important}.p-80{padding:80px!important}.p-85{padding:85px!important}.p-90{padding:90px!important}.p-95{padding:95px!important}.p-100{padding:100px!important}.p-105{padding:105px!important}.p-110{padding:110px!important}.p-115{padding:115px!important}.p-120{padding:120px!important}.p-125{padding:125px!important}.p-130{padding:130px!important}.p-135{padding:135px!important}.p-140{padding:140px!important}.p-145{padding:145px!important}.p-150{padding:150px!important}@media only screen and (max-width:767px){.m-t-100,.m-t-110,.m-t-115,.m-t-120,.m-t-125,.m-t-130,.m-t-135,.m-t-140,.m-t-145,.m-t-150,.m-t-35,.m-t-40,.m-t-45,.m-t-50,.m-t-55,.m-t-60,.m-t-65,.m-t-70,.m-t-75,.m-t-80,.m-t-85,.m-t-90,.m-t-95{margin-top:30px!important}.m-b-100,.m-b-110,.m-b-115,.m-b-120,.m-b-125,.m-b-130,.m-b-135,.m-b-140,.m-b-145,.m-b-150,.m-b-35,.m-b-40,.m-b-45,.m-b-50,.m-b-55,.m-b-60,.m-b-65,.m-b-70,.m-b-75,.m-b-80,.m-b-85,.m-b-90,.m-b-95{margin-bottom:30px!important}.m-l-100,.m-l-110,.m-l-115,.m-l-120,.m-l-125,.m-l-130,.m-l-135,.m-l-140,.m-l-145,.m-l-150,.m-l-35,.m-l-40,.m-l-45,.m-l-50,.m-l-55,.m-l-60,.m-l-65,.m-l-70,.m-l-75,.m-l-80,.m-l-85,.m-l-90,.m-l-95{margin-left:30px!important}.m-r-100,.m-r-110,.m-r-115,.m-r-120,.m-r-125,.m-r-130,.m-r-135,.m-r-140,.m-r-145,.m-r-150,.m-r-35,.m-r-40,.m-r-45,.m-r-50,.m-r-55,.m-r-60,.m-r-65,.m-r-70,.m-r-75,.m-r-80,.m-r-85,.m-r-90,.m-r-95{margin-right:30px!important}.p-100,.p-110,.p-115,.p-120,.p-125,.p-130,.p-135,.p-140,.p-145,.p-150,.p-35,.p-40,.p-45,.p-50,.p-55,.p-60,.p-65,.p-70,.p-75,.p-80,.p-85,.p-90,.p-95{padding:30px!important}}.p-v-5{padding-top:5px!important;padding-bottom:5px!important}.p-v-10{padding-top:10px!important;padding-bottom:10px!important}.p-v-15{padding-top:15px!important;padding-bottom:15px!important}.p-v-20{padding-top:20px!important;padding-bottom:20px!important}.p-v-25{padding-top:25px!important;padding-bottom:25px!important}.p-v-30{padding-top:30px!important;padding-bottom:30px!important}.p-v-35{padding-top:35px!important;padding-bottom:35px!important}.p-v-40{padding-top:40px!important;padding-bottom:40px!important}.p-v-45{padding-top:45px!important;padding-bottom:45px!important}.p-v-50{padding-top:50px!important;padding-bottom:50px!important}.p-v-55{padding-top:55px!important;padding-bottom:55px!important}.p-v-60{padding-top:60px!important;padding-bottom:60px!important}.p-v-65{padding-top:65px!important;padding-bottom:65px!important}.p-v-70{padding-top:70px!important;padding-bottom:70px!important}.p-v-75{padding-top:75px!important;padding-bottom:75px!important}.p-v-80{padding-top:80px!important;padding-bottom:80px!important}.p-v-85{padding-top:85px!important;padding-bottom:85px!important}.p-v-90{padding-top:90px!important;padding-bottom:90px!important}.p-v-95{padding-top:95px!important;padding-bottom:95px!important}.p-v-100{padding-top:100px!important;padding-bottom:100px!important}.p-v-105{padding-top:105px!important;padding-bottom:105px!important}.p-v-110{padding-top:110px!important;padding-bottom:110px!important}.p-v-115{padding-top:115px!important;padding-bottom:115px!important}.p-v-120{padding-top:120px!important;padding-bottom:120px!important}.p-v-125{padding-top:125px!important;padding-bottom:125px!important}.p-v-130{padding-top:130px!important;padding-bottom:130px!important}.p-v-135{padding-top:135px!important;padding-bottom:135px!important}.p-v-140{padding-top:140px!important;padding-bottom:140px!important}.p-v-145{padding-top:145px!important;padding-bottom:145px!important}.p-v-150{padding-top:150px!important;padding-bottom:150px!important}.p-h-5{padding-left:5px!important;padding-right:5px!important}.p-h-10{padding-left:10px!important;padding-right:10px!important}.p-h-15{padding-left:15px!important;padding-right:15px!important}.p-h-20{padding-left:20px!important;padding-right:20px!important}.p-h-25{padding-left:25px!important;padding-right:25px!important}.p-h-30{padding-left:30px!important;padding-right:30px!important}.p-h-35{padding-left:35px!important;padding-right:35px!important}.p-h-40{padding-left:40px!important;padding-right:40px!important}.p-h-45{padding-left:45px!important;padding-right:45px!important}.p-h-50{padding-left:50px!important;padding-right:50px!important}.p-h-55{padding-left:55px!important;padding-right:55px!important}.p-h-60{padding-left:60px!important;padding-right:60px!important}.p-h-65{padding-left:65px!important;padding-right:65px!important}.p-h-70{padding-left:70px!important;padding-right:70px!important}.p-h-75{padding-left:75px!important;padding-right:75px!important}.p-h-80{padding-left:80px!important;padding-right:80px!important}.p-h-85{padding-left:85px!important;padding-right:85px!important}.p-h-90{padding-left:90px!important;padding-right:90px!important}.p-h-95{padding-left:95px!important;padding-right:95px!important}.p-h-100{padding-left:100px!important;padding-right:100px!important}.p-h-105{padding-left:105px!important;padding-right:105px!important}.p-h-110{padding-left:110px!important;padding-right:110px!important}.p-h-115{padding-left:115px!important;padding-right:115px!important}.p-h-120{padding-left:120px!important;padding-right:120px!important}.p-h-125{padding-left:125px!important;padding-right:125px!important}.p-h-130{padding-left:130px!important;padding-right:130px!important}.p-h-135{padding-left:135px!important;padding-right:135px!important}.p-h-140{padding-left:140px!important;padding-right:140px!important}.p-h-145{padding-left:145px!important;padding-right:145px!important}.p-h-150{padding-left:150px!important;padding-right:150px!important}@media only screen and (max-width:767px){.p-v-100,.p-v-110,.p-v-115,.p-v-120,.p-v-125,.p-v-130,.p-v-135,.p-v-140,.p-v-145,.p-v-150,.p-v-35,.p-v-40,.p-v-45,.p-v-50,.p-v-55,.p-v-60,.p-v-65,.p-v-70,.p-v-75,.p-v-80,.p-v-85,.p-v-90,.p-v-95{padding-top:30px!important;padding-bottom:30px!important}.p-h-100,.p-h-110,.p-h-115,.p-h-120,.p-h-125,.p-h-130,.p-h-135,.p-h-140,.p-h-145,.p-h-150,.p-h-35,.p-h-40,.p-h-45,.p-h-50,.p-h-55,.p-h-60,.p-h-65,.p-h-70,.p-h-75,.p-h-80,.p-h-85,.p-h-90,.p-h-95{padding-left:30px!important;padding-right:30px!important}}.p-t-5{padding-top:5px!important}.p-t-10{padding-top:10px!important}.p-t-15{padding-top:15px!important}.p-t-20{padding-top:20px!important}.p-t-25{padding-top:25px!important}.p-t-30{padding-top:30px!important}.p-t-35{padding-top:35px!important}.p-t-40{padding-top:40px!important}.p-t-45{padding-top:45px!important}.p-t-50{padding-top:50px!important}.p-t-55{margin-top:55px!important}.p-t-60{padding-top:60px!important}.p-t-65{padding-top:65px!important}.p-t-70{padding-top:70px!important}.p-t-75{padding-top:75px!important}.p-t-80{padding-top:80px!important}.p-t-85{padding-top:85px!important}.p-t-90{padding-top:90px!important}.p-t-95{padding-top:95px!important}.p-t-100{padding-top:100px!important}.p-t-105{padding-top:105px!important}.p-t-110{padding-top:110px!important}.p-t-115{padding-top:115px!important}.p-t-120{padding-top:120px!important}.p-t-125{padding-top:125px!important}.p-t-130{padding-top:130px!important}.p-t-135{padding-top:135px!important}.p-t-140{padding-top:140px!important}.p-t-145{padding-top:145px!important}.p-t-150{padding-top:150px!important}.p-b-5{padding-bottom:5px!important}.p-b-10{padding-bottom:10px!important}.p-b-15{padding-bottom:15px!important}.p-b-20{padding-bottom:20px!important}.p-b-25{padding-bottom:25px!important}.p-b-30{padding-bottom:30px!important}.p-b-35{padding-bottom:35px!important}.p-b-40{padding-bottom:40px!important}.p-b-45{padding-bottom:45px!important}.p-b-50{padding-bottom:50px!important}.p-b-55{margin-bottom:55px!important}.p-b-60{padding-bottom:60px!important}.p-b-65{padding-bottom:65px!important}.p-b-70{padding-bottom:70px!important}.p-b-75{padding-bottom:75px!important}.p-b-80{padding-bottom:80px!important}.p-b-85{padding-bottom:85px!important}.p-b-90{padding-bottom:90px!important}.p-b-95{padding-bottom:95px!important}.p-b-100{padding-bottom:100px!important}.p-b-105{padding-bottom:105px!important}.p-b-110{padding-bottom:110px!important}.p-b-115{padding-bottom:115px!important}.p-b-120{margin-bottom:120px!important}.p-b-125{padding-bottom:125px!important}.p-b-130{padding-bottom:130px!important}.p-b-135{padding-bottom:135px!important}.p-b-140{padding-bottom:140px!important}.p-b-145{padding-bottom:145px!important}.p-b-150{padding-bottom:150px!important}.p-l-5{padding-left:5px!important}.p-l-10{padding-left:10px!important}.p-l-15{padding-left:15px!important}.p-l-20{padding-left:20px!important}.p-l-25{padding-left:25px!important}.p-l-30{padding-left:30px!important}.p-l-35{padding-left:35px!important}.p-l-40{padding-left:40px!important}.p-l-45{padding-left:45px!important}.p-l-50{padding-left:50px!important}.p-l-55{margin-left:55px!important}.p-l-60{padding-left:60px!important}.p-l-65{padding-left:65px!important}.p-l-70{padding-left:70px!important}.p-l-75{padding-left:75px!important}.p-l-80{padding-left:80px!important}.p-l-85{padding-left:85px!important}.p-l-90{padding-left:90px!important}.p-l-95{padding-left:95px!important}.p-l-100{padding-left:100px!important}.p-l-105{padding-left:105px!important}.p-l-115{padding-left:115px!important}.p-l-120{margin-left:120px!important}.p-l-125{padding-left:125px!important}.p-l-130{padding-left:130px!important}.p-l-135{padding-left:135px!important}.p-l-140{padding-left:140px!important}.p-l-145{padding-left:145px!important}.p-l-150{padding-left:150px!important}@media only screen and (max-width:767px){.p-t-100,.p-t-110,.p-t-115,.p-t-120,.p-t-125,.p-t-130,.p-t-135,.p-t-140,.p-t-145,.p-t-150,.p-t-35,.p-t-40,.p-t-45,.p-t-50,.p-t-55,.p-t-60,.p-t-65,.p-t-70,.p-t-75,.p-t-80,.p-t-85,.p-t-90,.p-t-95{padding-top:30px!important}.p-b-100,.p-b-110,.p-b-115,.p-b-120,.p-b-125,.p-b-130,.p-b-135,.p-b-140,.p-b-145,.p-b-150,.p-b-35,.p-b-40,.p-b-45,.p-b-50,.p-b-55,.p-b-60,.p-b-65,.p-b-70,.p-b-75,.p-b-80,.p-b-85,.p-b-90,.p-b-95{padding-bottom:30px!important}.p-l-100,.p-l-110,.p-l-115,.p-l-120,.p-l-125,.p-l-130,.p-l-135,.p-l-140,.p-l-145,.p-l-150,.p-l-35,.p-l-40,.p-l-45,.p-l-50,.p-l-55,.p-l-60,.p-l-65,.p-l-70,.p-l-75,.p-l-80,.p-l-85,.p-l-90,.p-l-95{padding-left:30px!important}}.p-r-5{padding-right:5px!important}.p-r-10{padding-right:10px!important}.p-r-15{padding-right:15px!important}.p-r-20{padding-right:20px!important}.p-r-25{padding-right:25px!important}.p-r-30{padding-right:30px!important}.p-r-35{padding-right:35px!important}.p-r-40{padding-right:40px!important}.p-r-45{padding-right:45px!important}.p-r-50{padding-right:50px!important}.p-r-55{margin-right:55px!important}.p-r-60{padding-right:60px!important}.p-r-65{padding-right:65px!important}.p-r-70{padding-right:70px!important}.p-r-75{padding-right:75px!important}.p-r-80{padding-right:80px!important}.p-r-85{padding-right:85px!important}.p-r-90{padding-right:90px!important}.p-r-95{padding-right:95px!important}.p-r-100{padding-right:100px!important}.p-r-105{padding-right:105px!important}.p-l-110{padding-left:110px!important}.p-r-115{padding-right:115px!important}.p-r-120{margin-right:120px!important}.p-r-125{padding-right:125px!important}.p-r-130{padding-right:130px!important}.p-r-135{padding-right:135px!important}.p-r-140{padding-right:140px!important}.p-r-145{padding-right:145px!important}.p-r-150{padding-right:150px!important}.width-0{width:0}.width-10{width:10%}.width-15{width:15%}.width-20{width:20%}.width-25{width:25%}.width-30{width:30%}.width-35{width:35%}.width-40{width:40%}.width-45{width:45%}.width-50{width:50%}.width-55{width:55%}.width-60{width:60%}.width-65{width:65%}.width-70{width:70%}.width-75{width:75%}.width-80{width:80%}.width-85{width:85%}.width-90{width:90%}.width-95{width:95%}.width-100{width:100%}.height-max{height:100%}.full-height{min-height:100vh}.ls-0{letter-spacing:0!important}.ls-0-5{letter-spacing:.5px!important}.ls-1{letter-spacing:1px!important}.ls-1-5{letter-spacing:1.5px!important}.ls-2{letter-spacing:2px!important}.ls-2-5{letter-spacing:2.5px!important}.ls-3{letter-spacing:3px!important}.ls-3-5{letter-spacing:3.5px!important}.ls-4{letter-spacing:4px!important}.ls-4-5{letter-spacing:4.5px!important}.ls-5{letter-spacing:5px!important}.ls-5-5{letter-spacing:5.5px!important}.ls-6{letter-spacing:6px!important}.ls-6-5{letter-spacing:6.5px!important}.ls-7{letter-spacing:7px!important}.ls-7-5{letter-spacing:7.5px!important}.ls-8{letter-spacing:8px!important}.ls-8-5{letter-spacing:8.5px!important}.ls-9{letter-spacing:9px!important}.ls-9-5{letter-spacing:9.5px!important}.ls-10{letter-spacing:10px!important}.ls-11{letter-spacing:11px!important}.ls-12{letter-spacing:12px!important}.ls-13{letter-spacing:13px!important}.ls-14{letter-spacing:14px!important}.ls-15{letter-spacing:15px!important}.lh-0{line-height:0!important}.lh-0-5{line-height:.5!important}.lh-1{line-height:1!important}.lh-1-1{line-height:1.1!important}.lh-1-2{line-height:1.2!important}.lh-1-3{line-height:1.3!important}.lh-1-4{line-height:1.4!important}.lh-1-5{line-height:1.5!important}.lh-1-6{line-height:1.6!important}.lh-1-7{line-height:1.7!important}.lh-1-8{line-height:1.8!important}.lh-1-9{line-height:1.9!important}.lh-2{line-height:2!important}.lh-2-1{line-height:2.1!important}.lh-2-2{line-height:2.2!important}.lh-2-3{line-height:2.3!important}.lh-2-4{line-height:2.4!important}.lh-2-5{line-height:2.5!important}.lh-3{line-height:3!important}.lh-4{line-height:4!important}.font-size-8{font-size:8px!important}.font-size-9{font-size:9px!important}.font-size-10{font-size:10px!important}.font-size-11{font-size:11px!important}.font-size-12{font-size:12px!important}.font-size-13{font-size:13px!important}.font-size-14{font-size:14px!important}.font-size-15{font-size:15px!important}.font-size-16{font-size:16px!important}.font-size-17{font-size:17px!important}.font-size-18{font-size:18px!important}.font-size-19{font-size:19px!important}.font-size-20{font-size:20px!important}.font-size-21{font-size:21px!important}.font-size-22{font-size:22px!important}.font-size-23{font-size:23px!important}.font-size-24{font-size:24px!important}.font-size-25{font-size:25px!important}.font-size-26{font-size:26px!important}.font-size-27{font-size:27px!important}.font-size-28{font-size:28px!important}.font-size-29{font-size:29px!important}.font-size-30{font-size:30px!important}.font-size-35{font-size:35px!important}.font-size-40{font-size:40px!important}.font-size-45{font-size:45px!important}.font-size-50{font-size:50px!important}.font-size-55{font-size:55px!important}.font-size-60{font-size:60px!important}.font-size-65{font-size:65px!important}.font-size-70{font-size:70px!important}.font-size-75{font-size:75px!important}.font-size-80{font-size:80px!important}.font-size-85{font-size:85px!important}.font-size-90{font-size:90px!important}.font-size-95{font-size:95px!important}.font-size-100{font-size:100px!important}.font-size-105{font-size:105px!important}.font-size-110{font-size:110px!important}.font-size-115{font-size:115px!important}.font-size-120{font-size:120px!important}.font-size-125{font-size:125px!important}.font-size-130{font-size:130px!important}.font-size-135{font-size:135px!important}.font-size-140{font-size:140px!important}.font-size-145{font-size:145px!important}.font-size-150{font-size:150px!important}.font-size-155{font-size:155px!important}.font-size-160{font-size:160px!important}.font-size-165{font-size:165px!important}.font-size-170{font-size:170px!important}.font-size-175{font-size:175px!important}.font-size-180{font-size:180px!important}.font-size-185{font-size:185px!important}.font-size-190{font-size:190px!important}.font-size-195{font-size:195px!important}.font-size-200{font-size:200px!important}.text-thin{font-weight:300!important}.text-normal{font-weight:400!important}.text-semibold{font-weight:500!important}.text-bold{font-weight:700!important}.display-block{display:block!important}.inline-block{display:inline-block!important}.absolute{position:absolute}.fixed{position:fixed}.static{position:static}.overflow-hidden{overflow:hidden}.overflow-y-hidden{overflow-y:hidden}.overflow-auto{overflow:auto}.overflow-y-auto{overflow-y:auto}.overflow-x-auto{overflow-x:auto}.img-circle{border-radius:50%!important}.border{border:1px solid #e9eaec}.border.top{border:0!important;border-top:1px solid #e9eaec!important}.border.right{border:0!important;border-right:1px solid #e9eaec!important}.border.bottom{border:0!important;border-bottom:1px solid #e9eaec!important}.border.left{border:0!important;border-left:1px solid #e9eaec!important}@media only screen and (max-width:992px){.border.border-hide-md{border-top:0!important;border-right:0!important;border-bottom:0!important;border-left:0!important}}.no-border{border:0!important;border-radius:0!important}.rounded{border-radius:8px!important}.vertical-align{display:table;height:100%;width:100%}.vertical-align .table-cell{display:table-cell;vertical-align:middle}.vertical-align-super{vertical-align:super}.border-radius-4{border-radius:4px!important}.border-radius-6{border-radius:6px!important}.border-radius-8{border-radius:8px!important}.border-radius-10{border-radius:10px!important}.border-radius-round{border-radius:50px!important}.opacity-01{opacity:.1}.opacity-02{opacity:.2}.opacity-03{opacity:.3}.opacity-04{opacity:.4}.opacity-05{opacity:.5}.opacity-06{opacity:.6}.opacity-07{opacity:.7}.opacity-08{opacity:.8}.opacity-09{opacity:.9}.opacity-10{opacity:1}@media only screen and (max-width:767px){.p-r-100,.p-r-110,.p-r-115,.p-r-120,.p-r-125,.p-r-130,.p-r-135,.p-r-140,.p-r-145,.p-r-150,.p-r-35,.p-r-40,.p-r-45,.p-r-50,.p-r-55,.p-r-60,.p-r-65,.p-r-70,.p-r-75,.p-r-80,.p-r-85,.p-r-90,.p-r-95{padding-right:30px!important}.pull-left-sm{float:left!important}.pull-right-sm{float:right!important}.pull-none-sm{float:none!important}.border.border-hide-sm{border-top:0!important;border-right:0!important;border-bottom:0!important;border-left:0!important}.font-size-100,.font-size-105,.font-size-110,.font-size-115,.font-size-120,.font-size-125,.font-size-130,.font-size-135,.font-size-140,.font-size-145,.font-size-50,.font-size-55,.font-size-60,.font-size-65,.font-size-70,.font-size-75,.font-size-80,.font-size-85,.font-size-90,.font-size-95{font-size:45px!important}.font-size-150,.font-size-155,.font-size-160,.font-size-165,.font-size-170,.font-size-175,.font-size-180,.font-size-185,.font-size-190,.font-size-195,.font-size-200{font-size:130px!important}input.width-10,input.width-15,input.width-20,input.width-25,input.width-30,input.width-35,input.width-40,input.width-45,input.width-50,input.width-55,input.width-60,input.width-65,input.width-70,input.width-75,input.width-80,input.width-85,input.width-90,input.width-95,p.width-10,p.width-15,p.width-20,p.width-25,p.width-30,p.width-35,p.width-40,p.width-45,p.width-50,p.width-55,p.width-60,p.width-65,p.width-70,p.width-75,p.width-80,p.width-85,p.width-90,p.width-95{width:100%!important}.side-nav{left:-200px}}.side-nav{width:200px;background-color:#fff;z-index:1000;top:65px;bottom:0;position:fixed;overflow:hidden;-webkit-transition:all .2s ease;-moz-transition:all .2s ease;-o-transition:all .2s ease;-ms-transition:all .2s ease}@media print{.side-nav{display:none}}.side-nav .side-nav-inner{position:relative;height:100%}.side-nav .side-nav-inner .side-nav-menu{position:relative;list-style:none;margin:0;padding-left:0;padding-top:20px;overflow:auto;border-right:1px solid #e9eaec;height:calc(100vh - 65px)}.side-nav .side-nav-inner .side-nav-menu:after,.side-nav .side-nav-inner .side-nav-menu:before{content:" ";display:table}.side-nav .side-nav-inner .side-nav-menu li{position:relative;display:block}.side-nav .side-nav-inner .side-nav-menu li.dropdown .arrow{position:absolute;right:30px;line-height:30px;transition:all 50ms ease-in;-webkit-transition:all 50ms ease-in;-moz-transition:all 50ms ease-in;-o-transition:all 50ms ease-in;-ms-transition:all 50ms ease-in}.side-nav .side-nav-inner .side-nav-menu li.dropdown.open>a>.arrow{transform:rotate(90deg);-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-o-transform:rotate(90deg);-ms-transform:rotate(90deg)}.side-nav .side-nav-inner .side-nav-menu li.dropdown.open>.dropdown-menu{display:block}.side-nav .side-nav-inner .side-nav-menu li.dropdown.open>.dropdown-menu .dropdown-menu{padding-left:20px}.side-nav .side-nav-inner .side-nav-menu li.dropdown.open>.dropdown-menu .arrow{line-height:25px}.side-nav .side-nav-inner .side-nav-menu li a{color:#8a8a8a;transition:all .3s ease;-webkit-transition:all .3s ease;-moz-transition:all .3s ease;-o-transition:all .3s ease;-ms-transition:all .3s ease}.side-nav .side-nav-inner .side-nav-menu li a:focus,.side-nav .side-nav-inner .side-nav-menu li a:hover{text-decoration:none;color:#515365}.side-nav .side-nav-inner .side-nav-menu li a:focus .icon-holder,.side-nav .side-nav-inner .side-nav-menu li a:hover .icon-holder{color:#515365}.side-nav .side-nav-inner .side-nav-menu li a.dropdown-toggle:after{display:none;border-radius:0}.side-nav .side-nav-inner .side-nav-menu>li.side-nav-header{text-transform:uppercase;font-size:11px;padding:10px 20px;opacity:.7;margin-top:15px}.side-nav .side-nav-inner .side-nav-menu>li.dropdown ul.dropdown-menu{position:relative;width:100%;box-shadow:none;border:0;border-radius:0;padding-left:50px;padding-top:0;background-color:transparent;float:none}.side-nav .side-nav-inner .side-nav-menu>li.dropdown ul.dropdown-menu>li>a{padding:10px 15px}.side-nav .side-nav-inner .side-nav-menu>li.dropdown ul.dropdown-menu>li>a:focus,.side-nav .side-nav-inner .side-nav-menu>li.dropdown ul.dropdown-menu>li>a:hover{background-color:transparent;color:#515365}.side-nav .side-nav-inner .side-nav-menu>li.dropdown ul.dropdown-menu>li.active a{color:#515365}.side-nav .side-nav-inner .side-nav-menu>li>a{position:relative;display:block;padding:10px 15px;font-weight:500;font-size:15px;white-space:nowrap}.side-nav .side-nav-inner .side-nav-menu>li>a .icon-holder{display:inline-block;height:25px;width:25px;line-height:25px;text-align:center;position:relative;left:0;margin-right:14px;font-size:20px;border-radius:6px;transition:all .3s ease;-webkit-transition:all .3s ease;-moz-transition:all .3s ease;-o-transition:all .3s ease;-ms-transition:all .3s ease}@media only screen and (min-width:992px){.side-nav-folded .side-nav .side-nav-inner .side-nav-menu>li.side-nav-header,.side-nav-folded .side-nav .side-nav-inner .side-nav-menu>li>a .title{display:none}.side-nav-folded .side-nav{width:70px}.side-nav-folded .side-nav .side-nav-inner .side-nav-menu{overflow-x:hidden}.side-nav-folded .side-nav .side-nav-inner .side-nav-menu>li>a{padding-left:20px}.side-nav-folded .side-nav .side-nav-inner .side-nav-menu li.dropdown .arrow{opacity:0}.side-nav-folded .side-nav .side-nav-inner .side-nav-menu li.dropdown.open ul.dropdown-menu{display:none!important}.side-nav-folded .side-nav:hover{width:200px;background:#fff;z-index:9999}.side-nav-folded .side-nav:hover .side-nav-inner .side-nav-menu>li.side-nav-header{display:block}.side-nav-folded .side-nav:hover .side-nav-inner .side-nav-menu>li>a .title{display:inline-block}.side-nav-folded .side-nav:hover .side-nav-inner .side-nav-menu li.dropdown .arrow{opacity:1}.side-nav-folded .side-nav:hover .side-nav-inner .side-nav-menu li.open>ul.dropdown-menu{display:block!important}}@media only screen and (max-width:992px){.side-nav .side-nav-inner .side-nav-menu li.dropdown .arrow{right:25px}.side-nav-folded .side-nav{left:-200px}}.side-nav-folded .header .header-container .nav-logo{width:70px;padding:0}@media only screen and (max-width:767px){.side-nav-folded .header .header-container .nav-logo{width:0;overflow:hidden}.side-nav-expand{overflow:hidden}}.side-nav-folded .header .header-container .nav-logo>a .logo{width:70px;background-position:center center}.side-nav-folded .header .nav-left>li>a.sidenav-fold-toggler i:before{content:"\F054"}@media only screen and (max-width:767px){.side-nav-expand .side-nav{left:0}.side-nav-expand .header .header-container .nav-logo{width:0}.side-nav-expand .header .header-container .nav-left>li>a.sidenav-expand-toggler i:before{content:"\F04D"}.side-nav-backdrop{position:fixed;width:100%;height:100%;top:0;left:0;right:0;bottom:0;background:#515365;background:rgba(81,83,101,.5)}}.header{display:block;height:65px;width:100%;position:fixed;padding:0;z-index:1040;background-color:#fff;border-bottom:1px solid #e9eaec;margin-bottom:0;-webkit-transition:all .2s ease;-moz-transition:all .2s ease;-o-transition:all .2s ease;-ms-transition:all .2s ease}@media print{.header{display:none}}@media only screen and (max-width:992px){.header{width:100%}}.header .header-container:after,.header .header-container:before{content:" ";display:table}.header .header-container .nav-logo{padding:0 20px;line-height:0;float:left;width:200px;transition:all .2s ease;-webkit-transition:all .2s ease;-moz-transition:all .2s ease;-o-transition:all .2s ease;-ms-transition:all .2s ease}.header .header-container .nav-logo>a{display:inline-block;max-width:200px;width:100%}.header .header-container .nav-logo>a .logo{background-repeat:no-repeat;background-position:center left;display:inline-block;width:100%;min-height:calc(65px - 1px)}.header .header-container .nav-logo>a .logo.logo-white{display:none}@media only screen and (max-width:992px){.header .header-container .nav-logo{width:0;padding:0}}.header .header-container .nav-left,.header .header-container .nav-right{position:relative;list-style:none;padding-left:0;margin-bottom:0}.header .header-container .nav-left>li,.header .header-container .nav-right>li{float:left}.header .header-container .nav-left>li>a,.header .header-container .nav-right>li>a{padding:0 12px;line-height:calc(65px - 3px);min-height:calc(65px - 3px);color:#8a8a8a;display:block;transition:all .2s ease-in-out;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;-ms-transition:all .2s ease-in-out}.header .header-container .nav-left>li>a i,.header .header-container .nav-right>li>a i{font-size:22px}.header .header-container .nav-left>li>a:focus,.header .header-container .nav-left>li>a:hover,.header .header-container .nav-right>li>a:focus,.header .header-container .nav-right>li>a:hover{text-decoration:none;color:#515365}.header .header-container .nav-left>li>a.dropdown-toggle:after,.header .header-container .nav-right>li>a.dropdown-toggle:after{display:none;border-radius:0}@media only screen and (min-width:767px){.header .header-container .nav-left>li>a.sidenav-fold-toggler,.header .header-container .nav-right>li>a.sidenav-fold-toggler{display:block}.header .header-container .nav-left>li>a.sidenav-expand-toggler,.header .header-container .nav-right>li>a.sidenav-expand-toggler{display:none}}.header .header-container .nav-left .user-profile .profile-img,.header .header-container .nav-right .user-profile .profile-img{width:35px;border-radius:50%;margin-top:12px;float:left}@media only screen and (max-width:992px){.header .header-container .nav-left>li>a,.header .header-container .nav-right>li>a{padding:0 10px}.header .header-container .nav-left .user-profile,.header .header-container .nav-right .user-profile{border-right:0;border-left:0}.header .header-container .nav-left .user-profile .profile-img,.header .header-container .nav-right .user-profile .profile-img{width:30px;margin-right:0}}.header .header-container .nav-left .notifications,.header .header-container .nav-right .notifications{position:relative}.header .header-container .nav-left .notifications .counter,.header .header-container .nav-right .notifications .counter{position:absolute;right:6px;top:12px;background-color:#fd3259;color:#fff;padding:3px 5.5px;border-radius:50px;line-height:1;font-size:10px}.header .header-container .nav-left{float:left}.content-footer .footer .go-right,.header .header-container .nav-right{float:right}@media only screen and (max-width:767px){.header .header-container .nav-left>li>a.sidenav-fold-toggler,.header .header-container .nav-right>li>a.sidenav-fold-toggler{display:none}.header .header-container .nav-left>li>a.sidenav-expand-toggler,.header .header-container .nav-right>li>a.sidenav-expand-toggler{display:block}.header .header-container .nav-right .dropdown.dropdown-animated.scale-left .dropdown-menu{right:-40px!important}.header .header-container .search-input input{width:85px}}.header .header-container .search-box .search-icon-close,.header .header-container .search-box.active .search-icon{display:none}.header .header-container .search-box.active .search-icon-close{display:inline-block}.header .header-container .search-input{display:none}.header .header-container .search-input.active{display:inline-block}.header .header-container .search-input input{border:0;box-shadow:none;background-color:transparent;outline:0;height:40px;margin-top:10px;padding:5px;font-size:16px}.header .header-container .search-input input::-webkit-input-placeholder{color:#fff;color:rgba(255,255,255,.5)}.header .header-container .search-input input:-moz-placeholder{color:#fff;color:rgba(255,255,255,.5)}.header .header-container .search-input input::-moz-placeholder{color:#fff;color:rgba(255,255,255,.5)}.header .header-container .search-input input:-ms-input-placeholder{color:#fff;color:rgba(255,255,255,.5)}.header .header-container .search-input .search-predict{display:none;position:absolute;top:65px;width:350px;min-height:50px;max-height:500px;background-color:#fff;color:#8a8a8a;border-radius:4px;-webkit-box-shadow:0 0 8px 0 rgba(0,0,0,.2);-moz-box-shadow:0 0 8px 0 rgba(0,0,0,.2);box-shadow:0 0 8px 0 rgba(0,0,0,.2)}.header .header-container .search-input .search-predict.active{display:block}.header .header-container .search-input .search-predict .search-wrapper{position:relative;max-height:400px;overflow-y:auto}.header .header-container .search-input .search-footer{border-top:1px solid #e9eaec;text-align:center;padding:15px;border-bottom-left-radius:4px;border-bottom-right-radius:4px}.content-footer{padding:0 30px}.content-footer .footer{padding:20px 0;font-size:90%;border-top:1px solid #e9eaec}@media only screen and (max-width:767px){.header .header-container .search-input .search-predict{left:40px}.content-footer .footer{text-align:center}.content-footer .footer .go-right{float:none;margin-top:15px;display:block}}.page-container{min-height:100vh;padding-left:200px;transition:all .2s ease;-webkit-transition:all .2s ease;-moz-transition:all .2s ease;-o-transition:all .2s ease;-ms-transition:all .2s ease}@media print{.page-container{padding-left:0}}@media only screen and (max-width:992px){.page-container{padding-left:0}}.page-container .main-content{padding:calc(65px + 35px) 15px 15px;min-height:calc(100vh - 65px)}.page-container .main-content.full-container{padding:95px 0 0}@media print{.page-container .main-content{padding:10px 0}}@media only screen and (max-width:992px){.page-container .main-content{padding:85px 10px 10px}}.page-container .page-header{margin-bottom:30px}.page-container .page-header .header-title{display:inline-block;font-size:23px;margin-bottom:0;padding-bottom:5px;border-right:1px solid #e9eaec;padding-right:20px;line-height:1}@media only screen and (max-width:767px){.page-container .page-header .header-title{border-right:0;display:block;margin-bottom:15px}}.page-container .page-header .header-sub-title{display:inline-block;padding-left:20px}@media only screen and (max-width:767px){.page-container .page-header .header-sub-title{padding-left:0;display:block}}@media only screen and (min-width:992px){.side-nav-folded .page-container{padding-left:70px}}@media only screen and (max-width:992px){.side-nav-folded .page-container{padding-left:0}}.widget-credit-card{max-width:430px}.side-nav-dark .side-nav{background-color:#223143;color:#99abb4}.side-nav-dark .side-nav .side-nav-logo{border-bottom:1px solid rgba(120,130,140,.3);border-right:1px solid transparent}.side-nav-dark .side-nav .side-nav-logo a .logo.logo-white{display:block}.side-nav-dark .side-nav .side-nav-logo a .logo.logo-dark{display:none}.side-nav-dark .side-nav .side-nav-inner .side-nav-menu{border-right:1px solid transparent}.side-nav-dark .side-nav .side-nav-inner .side-nav-menu li a{color:#99abb4;font-weight:400}.side-nav-dark .side-nav .side-nav-inner .side-nav-menu li a:focus .arrow,.side-nav-dark .side-nav .side-nav-inner .side-nav-menu li a:focus .icon-holder,.side-nav-dark .side-nav .side-nav-inner .side-nav-menu li a:focus .title,.side-nav-dark .side-nav .side-nav-inner .side-nav-menu li a:hover .arrow,.side-nav-dark .side-nav .side-nav-inner .side-nav-menu li a:hover .icon-holder,.side-nav-dark .side-nav .side-nav-inner .side-nav-menu li a:hover .title,.side-nav-dark .side-nav .side-nav-inner .side-nav-menu li.dropdown.open>a .arrow,.side-nav-dark .side-nav .side-nav-inner .side-nav-menu li.dropdown.open>a .icon-holder,.side-nav-dark .side-nav .side-nav-inner .side-nav-menu li.dropdown.open>a .title,.side-nav-dark .side-nav .side-nav-inner .side-nav-menu>li.dropdown ul.dropdown-menu>li.active>a,.side-nav-dark .side-nav .side-nav-inner .side-nav-menu>li.dropdown ul.dropdown-menu>li>a:focus,.side-nav-dark .side-nav .side-nav-inner .side-nav-menu>li.dropdown ul.dropdown-menu>li>a:hover{color:#fff}.side-nav-dark .side-nav .side-nav-inner .side-nav-menu>li.dropdown ul.dropdown-menu{background:#192532;background:rgba(25,37,50,.5)}.header-primary .header{background-color:#6569df}.header-primary .side-nav .side-nav-inner .side-nav-menu li.dropdown.open>a .icon-holder,.header-primary .side-nav .side-nav-inner .side-nav-menu li.dropdown>a:focus .icon-holder,.header-primary .side-nav .side-nav-inner .side-nav-menu li.dropdown>a:hover .icon-holder{color:#6569df}.header-info .header{background-color:#04a1f4}.header-info .side-nav .side-nav-inner .side-nav-menu li.dropdown.open>a .icon-holder,.header-info .side-nav .side-nav-inner .side-nav-menu li.dropdown>a:focus .icon-holder,.header-info .side-nav .side-nav-inner .side-nav-menu li.dropdown>a:hover .icon-holder{color:#04a1f4}.header-success .header{background-color:#2acfd2}.header-success .side-nav .side-nav-inner .side-nav-menu li.dropdown.open>a .icon-holder,.header-success .side-nav .side-nav-inner .side-nav-menu li.dropdown>a:focus .icon-holder,.header-success .side-nav .side-nav-inner .side-nav-menu li.dropdown>a:hover .icon-holder{color:#24d5d8}.header-warning .header{background-color:#fecd2f}.header-warning .side-nav .side-nav-inner .side-nav-menu li.dropdown.open>a .icon-holder,.header-warning .side-nav .side-nav-inner .side-nav-menu li.dropdown>a:focus .icon-holder,.header-warning .side-nav .side-nav-inner .side-nav-menu li.dropdown>a:hover .icon-holder{color:#fecd2f}.header-danger .header{background-color:#fd3259}.header-danger .side-nav .side-nav-inner .side-nav-menu li.dropdown.open>a .icon-holder,.header-danger .side-nav .side-nav-inner .side-nav-menu li.dropdown>a:focus .icon-holder,.header-danger .side-nav .side-nav-inner .side-nav-menu li.dropdown>a:hover .icon-holder{color:#fd3259}.header-dark .header{background-color:#334a65}.theme-configurator{position:relative}.color-selector label,.theme-selector label{position:relative;display:inline-block;width:25px;height:25px;margin-right:5px;margin-bottom:5px;border-radius:50%;cursor:pointer}.color-selector input,.theme-selector input{opacity:0}.color-selector input:checked~.theme-color:after,.theme-selector input:checked~.theme-color:after{content:"\e64c";font-family:themify;font-size:12px;font-weight:700;display:block;color:#fff;width:100%;text-align:center;position:absolute;top:50%;transform:translateY(-50%);-webkit-transform:translateY(-50%);-moz-transform:translateY(-50%);-o-transform:translateY(-50%);-ms-transform:translateY(-50%)}.color-selector input:checked~.theme-color.bg-white:after,.theme-selector input:checked~.theme-color.bg-white:after{color:#515365}.color-selector .theme-color,.theme-selector .theme-color{position:absolute;top:0;left:0;right:0;bottom:0;border-radius:50%}.color-pallet{border:1px solid #e9eaec;min-width:180px;margin-bottom:20px}.color-pallet .box{height:120px}.color-pallet .desc{padding:10px}.alert{padding:15px 20px;border-radius:0}.alert-default{color:#7d7d7d;background-color:#f1f2f3;border-color:#d9dade}.alert-default p{color:#7d7d7d}.alert-default hr{border-color:#e9eaec}.alert-primary,.alert-primary hr{border-color:#cfd0f5}.alert-primary{color:#6569df;background-color:#f0f1fc}.alert-primary p{color:#6569df}.alert-success,.alert-success hr{border-color:#8febec}.alert-success{color:#24d5d8;background-color:#e7fbfb}.alert-success p{color:#24d5d8}.alert-info,.alert-info p{color:#04a1f4}.alert-info,.alert-info hr{border-color:#94d9fd}.alert-info{background-color:#e9f7ff}.alert-warning,.alert-warning hr{border-color:#fedf7b}.alert-warning{color:#fecd2f;background-color:#fffefa}.alert-warning p{color:#fecd2f}.alert-danger,.alert-danger p{color:#fd3259}.alert-danger,.alert-danger hr{border-color:#fecad4}.alert-danger{background-color:#fff7f9}.alert-danger-gradient,.alert-info-gradient,.alert-primary-gradient,.alert-success-gradient,.alert-warning-gradient{color:#fff;border-radius:4px}.alert-primary-gradient{border-color:transparent;background:linear-gradient(120deg,#b603c1 0,#7a38e0 100%)}.alert-success-gradient{border-color:transparent;background:linear-gradient(120deg,#1dccdf 0,#1de4bd 100%)}.alert-info-gradient{border-color:transparent;background:linear-gradient(120deg,#6a4ee1 0,#05bdd7 100%)}.alert-warning-gradient{border-color:transparent;background:linear-gradient(120deg,#f6d365 0,#fda085 100%)}.alert-danger-gradient{border-color:transparent;background:linear-gradient(120deg,#f3301a 0,#f37138 100%)}.alert-float{border-color:transparent;-webkit-box-shadow:0 7px 20px 2px rgba(9,4,25,.1);-moz-box-shadow:0 7px 20px 2px rgba(9,4,25,.1);box-shadow:0 7px 20px 2px rgba(9,4,25,.1)}.alert-icon{font-size:30px;padding:0 7px}button{outline:0;box-shadow:none}button:focus{outline:0}button.active:focus,button:active:focus{outline:0;box-shadow:none}button.disabled,button:disabled{opacity:.5;cursor:not-allowed}.btn-danger.disabled,.btn-danger:disabled,.btn-info.disabled,.btn-info:disabled,.btn-primary.disabled,.btn-primary:disabled,.btn-success.disabled,.btn-success:disabled,.btn-warning.disabled,.btn-warning:disabled{opacity:.35}.btn{cursor:pointer;font-family:Roboto,-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI","Helvetica Neue",Arial,sans-serif;font-size:14px;padding:7px 20px;margin-right:5px;margin-bottom:10px;transition:all .3s ease-in-out;-webkit-transition:all .3s ease-in-out;-moz-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;-ms-transition:all .3s ease-in-out}.modal.modal-fs,.modal.modal-left,.modal.modal-right{padding-right:0!important}.btn.dropdown-toggle,.modal-footer .btn,.modal-header h1,.modal-header h2,.modal-header h3,.modal-header h4,.modal-header h5,.modal-header h6{margin-bottom:0}.btn:focus{outline:0;box-shadow:none}.btn.active:focus,.btn:active:focus{outline:0}.btn-default{color:#515365;background-color:transparent;border-color:#dbdde0}.btn-default.active:focus,.btn-default.active:hover,.btn-default:active,.btn-default:active:focus,.btn-default:active:hover,.btn-default:focus,.btn-default:hover{color:#515365;background-color:#eeeff1;border-color:#eeeff1}.btn-primary{background-color:#6569df;border-color:#6569df;color:#fff}.btn-primary:focus,.btn-primary:hover{color:#fff;background-color:#7a7ee3;border-color:#7a7ee3}.btn-primary.active,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active{background-color:#5054db;border-color:#5054db}.btn-primary.disabled,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary:disabled,.btn-primary:disabled:focus,.btn-primary:disabled:hover,.btn-primary:not([disabled]):not(.disabled).active,.btn-primary:not([disabled]):not(.disabled):active{background-color:#6569df;border-color:#6569df}.btn-primary:not([disabled]):not(.disabled).active:focus,.btn-primary:not([disabled]):not(.disabled):active:focus{box-shadow:none}.btn-primary.btn-outline{background-color:transparent;color:#6569df;border-color:#6569df}.btn-primary.btn-outline:focus,.btn-primary.btn-outline:hover{background-color:#6569df;color:#fff}.btn-success{background-color:#24d5d8;border-color:#24d5d8;color:#fff}.btn-success:focus,.btn-success:hover{color:#fff;background-color:#38dbde;border-color:#38dbde}.btn-success.active,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active{background-color:#20bfc2;border-color:#20bfc2}.btn-success.disabled,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success:disabled,.btn-success:disabled:focus,.btn-success:disabled:hover,.btn-success:not([disabled]):not(.disabled).active,.btn-success:not([disabled]):not(.disabled):active{background-color:#24d5d8;border-color:#24d5d8}.btn-success:not([disabled]):not(.disabled).active:focus,.btn-success:not([disabled]):not(.disabled):active:focus{box-shadow:none}.btn-success.btn-outline{background-color:transparent;color:#24d5d8;border-color:#24d5d8}.btn-success.btn-outline:focus,.btn-success.btn-outline:hover{background-color:#24d5d8;color:#fff}.btn-info{background-color:#04a1f4;border-color:#04a1f4;color:#fff}.btn-info:focus,.btn-info:hover{color:#fff;background-color:#16acfb;border-color:#16acfb}.btn-info.active,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active{background-color:#0490db;border-color:#0490db}.btn-info.disabled,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info:disabled,.btn-info:disabled:focus,.btn-info:disabled:hover,.btn-info:not([disabled]):not(.disabled).active,.btn-info:not([disabled]):not(.disabled):active{background-color:#04a1f4;border-color:#04a1f4}.btn-info:not([disabled]):not(.disabled).active:focus,.btn-info:not([disabled]):not(.disabled):active:focus{box-shadow:none}.btn-info.btn-outline{background-color:transparent;color:#04a1f4;border-color:#04a1f4}.btn-info.btn-outline:focus,.btn-info.btn-outline:hover{background-color:#04a1f4;color:#fff}.btn-warning{background-color:#fecd2f;border-color:#fecd2f;color:#fff}.btn-warning:focus,.btn-warning:hover{color:#fff;background-color:#fed348;border-color:#fed348}.btn-warning.active,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active{background-color:#fec716;border-color:#fec716}.btn-warning.disabled,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning:disabled,.btn-warning:disabled:focus,.btn-warning:disabled:hover,.btn-warning:not([disabled]):not(.disabled).active,.btn-warning:not([disabled]):not(.disabled):active{background-color:#fecd2f;border-color:#fecd2f}.btn-warning:not([disabled]):not(.disabled).active:focus,.btn-warning:not([disabled]):not(.disabled):active:focus{box-shadow:none}.btn-warning.btn-outline{background-color:transparent;color:#fecd2f;border-color:#fecd2f}.btn-warning.btn-outline:focus,.btn-warning.btn-outline:hover{background-color:#fecd2f;color:#fff}.btn-danger{background-color:#fd3259;border-color:#fd3259;color:#fff}.btn-danger:focus,.btn-danger:hover{color:#fff;background-color:#fd4b6d;border-color:#fd4b6d}.btn-danger.active,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active{background-color:#fd1945;border-color:#fd1945}.btn-danger.disabled,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger:disabled,.btn-danger:disabled:focus,.btn-danger:disabled:hover,.btn-danger:not([disabled]):not(.disabled).active,.btn-danger:not([disabled]):not(.disabled):active{background-color:#fd3259;border-color:#fd3259}.btn-danger:not([disabled]):not(.disabled).active:focus,.btn-danger:not([disabled]):not(.disabled):active:focus{box-shadow:none}.btn-danger.btn-outline{background-color:transparent;color:#fd3259;border-color:#fd3259}.btn-gradient-danger,.btn-gradient-info,.btn-gradient-primary,.btn-gradient-success,.btn-gradient-warning{border:0;color:#fff}.btn-danger.btn-outline:focus,.btn-danger.btn-outline:hover{background-color:#fd3259;color:#fff}.btn-gradient-primary,.btn-gradient-primary.active,.btn-gradient-primary:active,.btn-gradient-primary:focus,.btn-gradient-primary:hover,.btn-gradient-primary:not([disabled]):not(.disabled).active,.btn-gradient-primary:not([disabled]):not(.disabled):active{background:linear-gradient(120deg,#b603c1 0,#7a38e0 100%)}.btn-gradient-primary:focus,.btn-gradient-primary:hover{opacity:.7;color:#fff}.btn-gradient-primary.active,.btn-gradient-primary:active{color:#fff}.btn-gradient-primary.disabled:focus,.btn-gradient-primary.disabled:hover{opacity:.5}.btn-gradient-success,.btn-gradient-success.active,.btn-gradient-success:active,.btn-gradient-success:focus,.btn-gradient-success:hover,.btn-gradient-success:not([disabled]):not(.disabled).active,.btn-gradient-success:not([disabled]):not(.disabled):active{background:linear-gradient(120deg,#1dccdf 0,#1de4bd 100%)}.btn-gradient-success:focus,.btn-gradient-success:hover{opacity:.7;color:#fff}.btn-gradient-success.active,.btn-gradient-success:active{color:#fff}.btn-gradient-success.disabled:focus,.btn-gradient-success.disabled:hover{opacity:.5}.btn-gradient-info,.btn-gradient-info.active,.btn-gradient-info:active,.btn-gradient-info:focus,.btn-gradient-info:hover,.btn-gradient-info:not([disabled]):not(.disabled).active,.btn-gradient-info:not([disabled]):not(.disabled):active{background:linear-gradient(120deg,#6a4ee1 0,#05bdd7 100%)}.btn-gradient-info:focus,.btn-gradient-info:hover{opacity:.7;color:#fff}.btn-gradient-info.active,.btn-gradient-info:active{color:#fff}.btn-gradient-info.disabled:focus,.btn-gradient-info.disabled:hover{opacity:.5}.btn-gradient-warning,.btn-gradient-warning.active,.btn-gradient-warning:active,.btn-gradient-warning:focus,.btn-gradient-warning:hover,.btn-gradient-warning:not([disabled]):not(.disabled).active,.btn-gradient-warning:not([disabled]):not(.disabled):active{background:linear-gradient(120deg,#f6d365 0,#fda085 100%)}.btn-gradient-warning:focus,.btn-gradient-warning:hover{opacity:.7;color:#fff}.btn-gradient-warning.active,.btn-gradient-warning:active{color:#fff}.btn-gradient-warning.disabled:focus,.btn-gradient-warning.disabled:hover{opacity:.5}.btn-gradient-danger,.btn-gradient-danger.active,.btn-gradient-danger:active,.btn-gradient-danger:focus,.btn-gradient-danger:hover,.btn-gradient-danger:not([disabled]):not(.disabled).active,.btn-gradient-danger:not([disabled]):not(.disabled):active{background:linear-gradient(120deg,#f3301a 0,#f37138 100%)}.btn-gradient-danger:focus,.btn-gradient-danger:hover{opacity:.7;color:#fff}.btn-gradient-danger.disabled:focus,.btn-gradient-danger.disabled:hover,.checkbox input[type=checkbox].disabled+label,.checkbox input[type=checkbox]:disabled+label,.radio input[type=radio].disabled+label,.radio input[type=radio]:disabled+label{opacity:.5}.btn-gradient-danger.active,.btn-gradient-danger:active{color:#fff}.show>.dropdown-toggle.btn-primary{background-color:#5054db;border-color:#5054db}.show>.dropdown-toggle.btn-primary:focus,.show>.dropdown-toggle.btn-primary:hover{background-color:#5054db;border-color:#5054db;box-shadow:none}.show>.dropdown-toggle.btn-success{background-color:#20bfc2;border-color:#20bfc2}.show>.dropdown-toggle.btn-success:focus,.show>.dropdown-toggle.btn-success:hover{background-color:#20bfc2;border-color:#20bfc2;box-shadow:none}.show>.dropdown-toggle.btn-info{background-color:#0490db;border-color:#0490db}.show>.dropdown-toggle.btn-info:focus,.show>.dropdown-toggle.btn-info:hover{background-color:#0490db;border-color:#0490db;box-shadow:none}.show>.dropdown-toggle.btn-warning{background-color:#fec716;border-color:#fec716}.show>.dropdown-toggle.btn-warning:focus,.show>.dropdown-toggle.btn-warning:hover{background-color:#fec716;border-color:#fec716;box-shadow:none}.show>.dropdown-toggle.btn-danger{background-color:#fd1945;border-color:#fd1945}.show>.dropdown-toggle.btn-danger:focus,.show>.dropdown-toggle.btn-danger:hover{background-color:#fd1945;border-color:#fd1945;box-shadow:none}.modal .modal-dialog{transition:all .2s ease-out;-webkit-transition:all .2s ease-out;-moz-transition:all .2s ease-out;-o-transition:all .2s ease-out;-ms-transition:all .2s ease-out}.modal:not(.modal-fs) .modal-dialog,.modal:not(.modal-left) .modal-dialog,.modal:not(.modal-right) .modal-dialog{transform:translateY(20px);-webkit-transform:translateY(20px);-moz-transform:translateY(20px);-o-transform:translateY(20px);-ms-transform:translateY(20px)}.modal:not(.modal-fs).show .modal-dialog,.modal:not(.modal-left).show .modal-dialog,.modal:not(.modal-right).show .modal-dialog{transform:translateY(0);-webkit-transform:translateY(0);-moz-transform:translateY(0);-o-transform:translateY(0);-ms-transform:translateY(0)}.modal.modal-right .modal-dialog{transform:translateX(100%);-webkit-transform:translateX(100%);-moz-transform:translateX(100%);-o-transform:translateX(100%);-ms-transform:translateX(100%)}.modal.modal-right.show .modal-dialog{transform:translateX(0);-webkit-transform:translateX(0);-moz-transform:translateX(0);-o-transform:translateX(0);-ms-transform:translateX(0)}.modal.modal-left .modal-dialog{transform:translateX(-100%);-webkit-transform:translateX(-100%);-moz-transform:translateX(-100%);-o-transform:translateX(-100%);-ms-transform:translateX(-100%)}.modal.modal-left.show .modal-dialog{transform:translateX(0);-webkit-transform:translateX(0);-moz-transform:translateX(0);-o-transform:translateX(0);-ms-transform:translateX(0)}.modal.modal-fs .modal-dialog{transform:scale(.7);-webkit-transform:scale(.7);-moz-transform:scale(.7);-o-transform:scale(.7);-ms-transform:scale(.7)}.modal.modal-fs.show .modal-dialog{transform:scale(1);-webkit-transform:scale(1);-moz-transform:scale(1);-o-transform:scale(1);-ms-transform:scale(1)}.modal-header{padding:15px 20px 5px;border-bottom:0}.modal-body,.modal-footer{padding:15px 20px}.modal-footer{border-top:1px solid #e9eaec;text-align:left}.modal-footer .btn+.btn{margin-left:0}.modal-content{position:relative;background-color:#fff;border:0;border-radius:0;outline:0;-webkit-box-shadow:0 16px 24px rgba(43,47,49,.25);-moz-box-shadow:0 16px 24px rgba(43,47,49,.25);box-shadow:0 16px 24px rgba(43,47,49,.25)}.modal-left .modal-dialog,.modal-right .modal-dialog{width:400px;height:100%;margin:0 auto 0 0}@media only screen and (max-width:767px){.modal-left .modal-dialog,.modal-right .modal-dialog{width:calc(100% - 50px)}}.modal-left .modal-dialog .modal-content,.modal-right .modal-dialog .modal-content{height:100%;border-radius:0}.modal-left .modal-dialog .modal-content .side-modal-wrapper,.modal-right .modal-dialog .modal-content .side-modal-wrapper{height:100%;position:relative}.modal-left .modal-dialog .modal-content .modal-footer,.modal-right .modal-dialog .modal-content .modal-footer{position:absolute;bottom:0;width:100%}.modal-right .modal-dialog{margin:0 0 0 auto}.modal-backdrop{z-index:1040;background-color:#515365}.modal-fs .modal-dialog{width:100%;margin:0 auto;height:100%;max-width:none}.list-link,.list-media{margin-bottom:0}.modal-fs .modal-dialog .modal-content{height:100%;border-radius:0;background:#fff;background:rgba(255,255,255,.95)}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{background-color:#fafafa;border:1px solid #e9eaec}.modal-fs .modal-close{position:absolute;top:20px;right:20px;padding:7px 10px;border:1px solid #9ea0b1;border-radius:50px;color:#9ea0b1}.list,.list li{position:relative}.modal-fs .modal-close:focus,.modal-fs .modal-close:hover{color:#515365;text-decoration:none;border:1px solid #515365}.list li{padding-bottom:10px}.list.arrow,.list.bullet,.list.dash,.list.star,.list.tick{list-style:none;padding-left:0}.list.arrow>li,.list.bullet>li,.list.dash>li,.list.star>li,.list.tick>li{padding-left:30px}.list.arrow>li:before,.list.bullet>li:before,.list.dash>li:before,.list.star>li:before,.list.tick>li:before{font-family:themify;position:absolute;left:0}.list.tick>li:before{content:"\e64c"}.list.star>li:before{content:"\e60a"}.list.dash>li:before{content:"-"}.list.bullet>li:before{content:"\e724"}.list.arrow>li:before{content:"\e649";font-size:10px;top:4px}.bg-overlay:before,.card-refresh:after,.card-refresh:before,.list-media .media-img .status:before{content:""}.list.decimal{list-style-type:decimal;padding-left:20px}.list.decimal li{padding-left:10px}.list.upper-roman{list-style-type:upper-roman;padding-left:20px}.list.upper-roman li{padding-left:10px}.list.lower-alpha{list-style-type:lower-alpha;padding-left:20px}.list.lower-alpha li{padding-left:10px}.list.bullet-primary>li:before{color:#6569df}.list.bullet-info li:before{color:#04a1f4}.list.bullet-success li:before{color:#24d5d8}.list.bullet-warning li:before{color:#fecd2f}.list.bullet-danger li:before{color:#fd3259}.list.bullet-white li:before{color:#fff}.list.bullet-dark li:before{color:#515365}.list-group-item{border:1px solid #e9eaec}.list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.list-group-item:last-child{border-bottom-right-radius:0;border-bottom-left-radius:0}.list-group-item.active{color:#515365}.list-group-item.disabled{color:#9ea0b1}.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#9ea0b1;background-color:transparent;border:1px solid #e9eaec}.list-group-item-action{color:#515365}.list-group-item-action:focus,.list-group-item-action:hover{color:#515365;background-color:#fafafa}.list-media{display:block;position:relative;padding-left:0;list-style:none}.list-media>.list-item{display:block}.list-media>.list-item>a{display:block;position:relative;padding:12px 0}.list-media>.list-item>a:focus,.list-media>.list-item>a:hover{text-decoration:none}.list-media>.list-item.active{background-color:#fafafa}.list-media>.list-item .media-hover:focus,.list-media>.list-item .media-hover:hover{text-decoration:none;background-color:#fafafa}.list-media .media-img{position:relative;float:left}.list-media .media-img .icon-avatar,.list-media .media-img img{line-height:40px;height:40px;width:40px;text-align:center;font-size:17px;border-radius:50px;color:#fff}.list-media .media-img .status{right:0;bottom:0;position:absolute;left:auto;top:auto}.list-media .media-img .status:before{position:absolute;background-color:transparent;width:15px;height:14px;bottom:-5px;right:-6px;border-radius:50px;border:2px solid #fff}.list-media .info{padding-left:55px;min-height:40px;height:auto;position:relative}.list-media .info .title{display:block;color:#515365;line-height:1.5}.list-media .info .title.pdd-top-5{padding-top:7px!important}.list-media .info .sub-title{display:block;font-size:12.5px;color:#adadad;color:rgba(138,138,138,.7);max-width:90%}.list-media .info .float-item{position:absolute;right:0;color:#8a8a8a;top:50%;font-size:12px;transform:translateY(-50%);-webkit-transform:translateY(-50%);-moz-transform:translateY(-50%);-o-transform:translateY(-50%);-ms-transform:translateY(-50%)}.list-media .info.status{padding-left:0;min-height:auto;height:10px;position:absolute}.list-inline>li{display:inline-block;margin-right:10px}.list-media-horizon{display:inline-block;margin-bottom:0}.list-media-horizon>li{float:left;margin-right:0}.list-media-horizon>li>a img,.list-media-horizon>li>img{width:35px;height:35px;border-radius:100%;overflow:hidden;border:2px solid #fff;display:block}.list-media-horizon>li.all-members{border-radius:100%}.list-media-horizon>li.all-members>a{width:35px;line-height:35px;display:block;text-align:center;border-radius:100%;background-color:#fafafa;color:#8a8a8a}.list-media-horizon>li.add-member>a{border:2px dashed #e9eaec;width:35px;line-height:30px;display:block;text-align:center;border-radius:100%;color:#ced0d4;margin-left:5px}.card-toolbar ul>li,.list-label>li,.status{display:inline-block}.list-link li{padding:10px 0}.list-link li a{color:#8a8a8a}.list-link li a:focus,.list-link li a:hover{color:#515365;text-decoration:none}.list-label{padding-left:0;line-height:0}.list-label>li{height:2px;width:40px;background:#fafafa;border-radius:50px;margin-right:5px}.badge{padding:5px 7px;font-size:80%;font-weight:500;line-height:1}.badge-default{color:#515365;background-color:transparent;border:1px solid #dbdde0}.badge-default[href]:focus,.badge-default[href]:hover{background-color:#f7f7f7;color:#515365}.badge-primary{background-color:#6569df}.badge-primary[href]:focus,.badge-primary[href]:hover{background-color:#7a7ee3}.badge-success{background-color:#24d5d8}.badge-success[href]:focus,.badge-success[href]:hover{background-color:#38dbde}.badge-info{background-color:#04a1f4}.badge-info[href]:focus,.badge-info[href]:hover{background-color:#16acfb}.badge-warning{color:#fff;background-color:#fecd2f}.badge-warning[href]:focus,.badge-warning[href]:hover{color:#fff;background-color:#fed348}.badge-danger{background-color:#fd3259}.badge-danger[href]:focus,.badge-danger[href]:hover{background-color:#fd4b6d}.badge-gradient-primary{color:#fff;background:linear-gradient(120deg,#b603c1 0,#7a38e0 100%)}.badge-gradient-success{color:#fff;background:linear-gradient(120deg,#1dccdf 0,#1de4bd 100%)}.badge-gradient-info{color:#fff;background:linear-gradient(120deg,#6a4ee1 0,#05bdd7 100%)}.badge-gradient-warning{color:#fff;background:linear-gradient(120deg,#f6d365 0,#fda085 100%)}.badge-gradient-danger{color:#fff;background:linear-gradient(120deg,#f3301a 0,#f37138 100%)}.badge-xl{padding:9px 15px;font-size:100%}.badge-lg{padding:8px 13px;font-size:90%}.badge-sm{padding:3px 5px;font-size:75%}.status{width:10px;height:10px;background-color:#fff;border-radius:50px;border:3px solid #c0c3c9}.status.primary{border-color:#6569df}.status.info{border-color:#04a1f4}.status.online,.status.success{border-color:#24d5d8}.status.busy,.status.danger{border-color:#fd3259}.status.away,.status.warning{border-color:#fecd2f}.status.gradient{border:0;background:#fafafa}.status.gradient.primary{background:linear-gradient(120deg,#b603c1 0,#7a38e0 100%)}.status.gradient.info{background:linear-gradient(120deg,#6a4ee1 0,#05bdd7 100%)}.status.gradient.online,.status.gradient.success{background:linear-gradient(120deg,#1dccdf 0,#1de4bd 100%)}.status.gradient.away,.status.gradient.warning{background:linear-gradient(120deg,#f6d365 0,#fda085 100%)}.status.gradient.busy,.status.gradient.danger{background:linear-gradient(120deg,#f3301a 0,#f37138 100%)}.card{position:relative;background-color:#fff;margin-bottom:30px;border:1px solid #e9eaec;border-radius:0;transition:all .3s ease-in-out;-webkit-transition:all .3s ease-in-out;-moz-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;-ms-transition:all .3s ease-in-out}.card-footer,.card-header{position:relative;min-height:55px;background-color:transparent}.card-header:first-child,.popover{border-radius:0}.card .bg-danger,.card .bg-gradient-danger,.card .bg-gradient-info,.card .bg-gradient-primary,.card .bg-gradient-success,.card .bg-gradient-warning,.card .bg-info,.card .bg-primary,.card .bg-success,.card .bg-warning,.card.bg-danger,.card.bg-gradient-danger,.card.bg-gradient-info,.card.bg-gradient-primary,.card.bg-gradient-success,.card.bg-gradient-warning,.card.bg-info,.card.bg-primary,.card.bg-success,.card.bg-warning{color:#f7f7f7}.card .bg-danger h1,.card .bg-danger h2,.card .bg-danger h3,.card .bg-danger h4,.card .bg-danger h5,.card .bg-danger h6,.card .bg-gradient-danger h1,.card .bg-gradient-danger h2,.card .bg-gradient-danger h3,.card .bg-gradient-danger h4,.card .bg-gradient-danger h5,.card .bg-gradient-danger h6,.card .bg-gradient-info h1,.card .bg-gradient-info h2,.card .bg-gradient-info h3,.card .bg-gradient-info h4,.card .bg-gradient-info h5,.card .bg-gradient-info h6,.card .bg-gradient-primary h1,.card .bg-gradient-primary h2,.card .bg-gradient-primary h3,.card .bg-gradient-primary h4,.card .bg-gradient-primary h5,.card .bg-gradient-primary h6,.card .bg-gradient-success h1,.card .bg-gradient-success h2,.card .bg-gradient-success h3,.card .bg-gradient-success h4,.card .bg-gradient-success h5,.card .bg-gradient-success h6,.card .bg-gradient-warning h1,.card .bg-gradient-warning h2,.card .bg-gradient-warning h3,.card .bg-gradient-warning h4,.card .bg-gradient-warning h5,.card .bg-gradient-warning h6,.card .bg-info h1,.card .bg-info h2,.card .bg-info h3,.card .bg-info h4,.card .bg-info h5,.card .bg-info h6,.card .bg-primary h1,.card .bg-primary h2,.card .bg-primary h3,.card .bg-primary h4,.card .bg-primary h5,.card .bg-primary h6,.card .bg-success h1,.card .bg-success h2,.card .bg-success h3,.card .bg-success h4,.card .bg-success h5,.card .bg-success h6,.card .bg-warning h1,.card .bg-warning h2,.card .bg-warning h3,.card .bg-warning h4,.card .bg-warning h5,.card .bg-warning h6,.card.bg-danger h1,.card.bg-danger h2,.card.bg-danger h3,.card.bg-danger h4,.card.bg-danger h5,.card.bg-danger h6,.card.bg-gradient-danger h1,.card.bg-gradient-danger h2,.card.bg-gradient-danger h3,.card.bg-gradient-danger h4,.card.bg-gradient-danger h5,.card.bg-gradient-danger h6,.card.bg-gradient-info h1,.card.bg-gradient-info h2,.card.bg-gradient-info h3,.card.bg-gradient-info h4,.card.bg-gradient-info h5,.card.bg-gradient-info h6,.card.bg-gradient-primary h1,.card.bg-gradient-primary h2,.card.bg-gradient-primary h3,.card.bg-gradient-primary h4,.card.bg-gradient-primary h5,.card.bg-gradient-primary h6,.card.bg-gradient-success h1,.card.bg-gradient-success h2,.card.bg-gradient-success h3,.card.bg-gradient-success h4,.card.bg-gradient-success h5,.card.bg-gradient-success h6,.card.bg-gradient-warning h1,.card.bg-gradient-warning h2,.card.bg-gradient-warning h3,.card.bg-gradient-warning h4,.card.bg-gradient-warning h5,.card.bg-gradient-warning h6,.card.bg-info h1,.card.bg-info h2,.card.bg-info h3,.card.bg-info h4,.card.bg-info h5,.card.bg-info h6,.card.bg-primary h1,.card.bg-primary h2,.card.bg-primary h3,.card.bg-primary h4,.card.bg-primary h5,.card.bg-primary h6,.card.bg-success h1,.card.bg-success h2,.card.bg-success h3,.card.bg-success h4,.card.bg-success h5,.card.bg-success h6,.card.bg-warning h1,.card.bg-warning h2,.card.bg-warning h3,.card.bg-warning h4,.card.bg-warning h5,.card.bg-warning h6{color:#fff}.card .bg-danger p,.card .bg-gradient-danger p,.card .bg-gradient-info p,.card .bg-gradient-primary p,.card .bg-gradient-success p,.card .bg-gradient-warning p,.card .bg-info p,.card .bg-primary p,.card .bg-success p,.card .bg-warning p,.card.bg-danger p,.card.bg-gradient-danger p,.card.bg-gradient-info p,.card.bg-gradient-primary p,.card.bg-gradient-success p,.card.bg-gradient-warning p,.card.bg-info p,.card.bg-primary p,.card.bg-success p,.card.bg-warning p{color:#f7f7f7}.card .bg-danger .card-header,.card .bg-gradient-danger .card-header,.card .bg-gradient-info .card-header,.card .bg-gradient-primary .card-header,.card .bg-gradient-success .card-header,.card .bg-gradient-warning .card-header,.card .bg-info .card-header,.card .bg-primary .card-header,.card .bg-success .card-header,.card .bg-warning .card-header,.card.bg-danger .card-header,.card.bg-gradient-danger .card-header,.card.bg-gradient-info .card-header,.card.bg-gradient-primary .card-header,.card.bg-gradient-success .card-header,.card.bg-gradient-warning .card-header,.card.bg-info .card-header,.card.bg-primary .card-header,.card.bg-success .card-header,.card.bg-warning .card-header{border-color:rgba(255,255,255,.3)!important}.card .bg-danger .card-footer,.card .bg-gradient-danger .card-footer,.card .bg-gradient-info .card-footer,.card .bg-gradient-primary .card-footer,.card .bg-gradient-success .card-footer,.card .bg-gradient-warning .card-footer,.card .bg-info .card-footer,.card .bg-primary .card-footer,.card .bg-success .card-footer,.card .bg-warning .card-footer,.card.bg-danger .card-footer,.card.bg-gradient-danger .card-footer,.card.bg-gradient-info .card-footer,.card.bg-gradient-primary .card-footer,.card.bg-gradient-success .card-footer,.card.bg-gradient-warning .card-footer,.card.bg-info .card-footer,.card.bg-primary .card-footer,.card.bg-success .card-footer,.card.bg-warning .card-footer{border-top:1px solid rgba(255,255,255,.2)}.card.card-shadow{-webkit-box-shadow:0 7px 20px 2px rgba(0,0,0,.2);-moz-box-shadow:0 7px 20px 2px rgba(0,0,0,.2);box-shadow:0 7px 20px 2px rgba(0,0,0,.2)}.card-header{padding:15px 25px;border-bottom:0}.card-header .card-title{margin-bottom:0;display:inline-block}.card-header p{padding-top:8px;margin-bottom:0}.card-body{padding:25px;position:relative}.card-footer{padding:10px 15px;border-top:1px solid #e9eaec}.card-footer .btn{margin-bottom:0}.card-toolbar{float:right}.card-toolbar ul{list-style:none;padding-left:0}.card-toolbar ul>li>.btn,.card-toolbar ul>li>a{margin-bottom:0;margin-right:10px;display:block}.card-toolbar ul>li>.btn{padding:7px 15px;font-size:13px}.bg-overlay>.card-toolbar{position:absolute;right:15px;top:10px}.card-title{color:#515365;margin-top:0;margin-bottom:15px}.card-img-top{border-top-left-radius:0;border-top-right-radius:0}.card-refresh:before{position:absolute;top:0;left:0;width:100%;height:100%;z-index:4;background:#fff;background:rgba(255,255,255,.7)}.card-refresh:after{position:absolute;top:calc(50% - 20px);left:calc(50% - 20px);border:3px solid #e9eaec;border-top:3px solid #24d5d8;border-radius:50%;width:40px;height:40px;z-index:5;-webkit-animation:spin 1.2s linear infinite;-moz-animation:spin 1.2s linear infinite;-ms-animation:spin 1.2s linear infinite;-o-animation:spin 1.2s linear infinite;animation:spin 1.2s linear infinite;transform:translateX(-50%) translateY(-50%);-webkit-transform:translateX(-50%) translateY(-50%);-moz-transform:translateX(-50%) translateY(-50%);-o-transform:translateX(-50%) translateY(-50%);-ms-transform:translateX(-50%) translateY(-50%)}.draggable-item{cursor:move;cursor:grab;cursor:-moz-grab;cursor:-webkit-grab}@-webkit-keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}@-moz-keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}@-ms-keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}@-o-keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}@keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}a.card{display:block}a.card:focus,a.card:hover{-webkit-box-shadow:0 7px 15px rgba(0,0,0,.075);-moz-box-shadow:0 7px 15px rgba(0,0,0,.075);box-shadow:0 7px 15px rgba(0,0,0,.075)}.bg-overlay{position:relative;overflow:hidden;color:#f2f2f2}.bg-overlay h1,.bg-overlay h2,.bg-overlay h3,.bg-overlay h4,.bg-overlay h5,.bg-overlay h6{color:#fff}.bg-overlay p{color:#f2f2f2}.bg-overlay:before{position:absolute;background:#0f0f17;opacity:.5;width:100%;height:100%;top:0;left:0;z-index:2}.bg-overlay>div{z-index:3}.bg-overlay .btn-default{color:#fff}.bg-overlay .btn-default:focus,.bg-overlay .btn-default:hover{color:#515365}.bg-overlay.primary:before{background:#6569df;opacity:.6}.bg-overlay.primary-gradient:before{background:linear-gradient(120deg,#b603c1 0,#7a38e0 100%);opacity:.8}.bg-overlay.success-gradient:before{background:linear-gradient(120deg,#1dccdf 0,#1de4bd 100%);opacity:.8}.bg-overlay.info-gradient:before{background:linear-gradient(120deg,#6a4ee1 0,#05bdd7 100%);opacity:.7}.bg-overlay.warning-gradient:before{background:linear-gradient(120deg,#f6d365 0,#fda085 100%);opacity:.7}.bg-overlay.danger-gradient:before{background:linear-gradient(120deg,#f3301a 0,#f37138 100%);opacity:.7}.card-collapse-btn{transition:all .4s ease-in-out;-webkit-transition:all .4s ease-in-out;-moz-transition:all .4s ease-in-out;-o-transition:all .4s ease-in-out;-ms-transition:all .4s ease-in-out}.card-collapse-btn.active{transform:rotate(180deg);-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-o-transform:rotate(180deg);-ms-transform:rotate(180deg)}.page-title h1,.page-title h2,.page-title h3,.page-title h4,.page-title h5,.page-title h6,.page-title p,.page-title span{font-size:20px;margin-bottom:25px;margin-top:0}.dropdown.dropdown-animated:not(.scale-left) .dropdown-menu,.dropdown.dropdown-animated:not(.scale-right) .dropdown-menu{opacity:0;visibility:hidden;-webkit-transform:translateY(15px)!important;-moz-transform:translateY(15px)!important;-ms-transform:translateY(15px)!important;transform:translateY(15px)!important;transition:all .2s ease-in-out;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;-ms-transition:all .2s ease-in-out;display:block;margin:0;top:auto!important}.dropdown.dropdown-animated:not(.scale-left) .dropdown-menu.show,.dropdown.dropdown-animated:not(.scale-right) .dropdown-menu.show{opacity:1;visibility:visible;-webkit-transform:translateY(0)!important;-moz-transform:translateY(0)!important;-ms-transform:translateY(0)!important;transform:translateY(0)!important}.dropdown.dropdown-animated.scale-left .dropdown-menu{-webkit-transform-origin:top right!important;-moz-transform-origin:top right!important;-ms-transform-origin:top right!important;transform-origin:top right!important;transform:scale(0,0)!important;-webkit-transform:scale(0,0)!important;-moz-transform:scale(0,0)!important;-ms-transform:scale(0,0)!important;transition:all .2s ease-in-out;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;-ms-transition:all .2s ease-in-out;display:block;margin:0;right:0!important;left:auto!important;top:auto!important}.dropdown.dropdown-animated.scale-left .dropdown-menu.show{transform:scale(1,1)!important;-webkit-transform:scale(1,1)!important;-moz-transform:scale(1,1)!important;-ms-transform:scale(1,1)!important}.dropdown.dropdown-animated.scale-right .dropdown-menu{-webkit-transform-origin:top left;-moz-transform-origin:top left;-ms-transform-origin:top left;transform-origin:top left;transform:scale(0,0)!important;-webkit-transform:scale(0,0)!important;-moz-transform:scale(0,0)!important;-ms-transform:scale(0,0)!important;transition:all .2s ease-in-out;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;-ms-transition:all .2s ease-in-out;display:block;margin:0;top:auto!important}.dropdown.dropdown-animated.scale-right .dropdown-menu.show{transform:scale(1,1)!important;-webkit-transform:scale(1,1)!important;-moz-transform:scale(1,1)!important;-ms-transform:scale(1,1)!important}.dropdown-menu{border:0;border-radius:0;font-size:14px;min-width:180px;color:#8a8a8a;-webkit-box-shadow:0 2px 5px rgba(0,0,0,.2);-moz-box-shadow:0 2px 5px rgba(0,0,0,.2);box-shadow:0 2px 5px rgba(0,0,0,.2);top:100%}.switch input[type=checkbox]+label:after,.switch input[type=checkbox]+label:before{top:0;left:0;content:"";position:absolute;display:block}.dropdown-menu.dropdown-md{min-width:250px}.dropdown-menu.dropdown-lg{min-width:360px}@media only screen and (max-width:767px){.dropdown-menu.dropdown-lg{min-width:280px}}.dropdown-menu.dropdown-xl{min-width:450px}.dropdown-menu>li.divider{border-bottom:1px solid #e9eaec;height:1px;overflow:hidden}.dropdown-menu>li>a{line-height:1.5;min-height:auto;padding:10px 15px;display:block;transition:all .2s ease-out;-webkit-transition:all .2s ease-out;-moz-transition:all .2s ease-out;-o-transition:all .2s ease-out;-ms-transition:all .2s ease-out;color:#8a8a8a}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#515365;text-decoration:none;background-color:#f7f7f8}.dropdown-menu.dropdown-grid{display:flex!important;flex-wrap:wrap;padding:10px}.dropdown-menu.dropdown-grid>li{display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;flex-direction:column;-webkit-box-pack:center;justify-content:center}.dropdown-menu.dropdown-grid>li>a{padding:10px;border:1px solid #e9eaec;margin:7px;border-radius:4px}.dropdown-menu.dropdown-grid.col-2>li{flex-basis:50%}.dropdown-menu.dropdown-grid.col-3>li{flex-basis:33.333333%}@media only screen and (max-width:767px){.dropdown-menu.dropdown-xl{min-width:280px}.dropdown-menu.dropdown-grid.col-3>li{flex-basis:50%}}.dropdown-menu.dropdown-grid.col-4>li{flex-basis:25%}@media only screen and (max-width:767px){.dropdown-menu.dropdown-grid.col-4>li{flex-basis:50%}}.dropdown-item{line-height:1.5;min-height:auto;padding:10px 20px;display:block;transition:all .15s ease-out;-webkit-transition:all .15s ease-out;-moz-transition:all .15s ease-out;-o-transition:all .15s ease-out;-ms-transition:all .15s ease-out;color:#8a8a8a}.dropdown-item:focus,.dropdown-item:hover{color:#515365;text-decoration:none;background-color:#f7f7f8}.dropdown-item.disabled{opacity:.3;cursor:not-allowed}.dropdown-item.disabled:focus,.dropdown-item.disabled:hover{background-color:transparent}.dropdown-item.active{background-color:#f7f7f8;color:#515365}.dropdown-toggle:after{text-align:center;display:inline;border:0;font-family:Material Design Icons;content:"\F140";line-height:0;vertical-align:middle;position:relative}.dropdown-header{padding:10px 20px;font-weight:500;color:#717171;font-size:15px}.dropdown,.dropup{display:inline-block}.accordion>.card{margin-bottom:15px}.accordion>.card>.card-header{padding:0}.accordion>.card>.card-header>.card-title>a{padding:15px 25px;display:block;color:#515365}.accordion>.card>.card-header>.card-title>a:not(.collapsed):after{transform:rotate(90deg);-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-o-transform:rotate(90deg);-ms-transform:rotate(90deg)}.accordion>.card>.card-header>.card-title>a:after{content:"\F142";font-family:"Material Design Icons";float:left;margin-right:10px;transition:all .3s ease-in-out;-webkit-transition:all .3s ease-in-out;-moz-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;-ms-transition:all .3s ease-in-out}.accordion>.card .card-body{padding-top:5px}.accordion.nested>.card{margin-bottom:0;border-bottom:0}.accordion.nested>.card:last-child{border-bottom:1px solid #e9eaec}.accordion.borderless>.card{margin-bottom:0;border-top:0;border-left:0;border-right:0}.accordion.borderless>.card:last-child{border-bottom:0}.popover{border:1px solid #e9eaec;-webkit-box-shadow:0 9px 12px rgba(0,0,0,.075);-moz-box-shadow:0 9px 12px rgba(0,0,0,.075);box-shadow:0 9px 12px rgba(0,0,0,.075)}.form-control,.page-link:focus{box-shadow:none}.popover-header{background-color:#fafafa;color:#515365;border-bottom:1px solid #e9eaec;border-top-left-radius:0;border-top-right-radius:0}.popover-body{padding:10px 15px;color:#515365}.bs-popover-auto[x-placement^=right] .arrow::before,.bs-popover-right .arrow::before{border-right-color:#e9eaec}.bs-popover-auto[x-placement^=top] .arrow::before,.bs-popover-top .arrow::before{border-top-color:#e9eaec}.bs-popover-auto[x-placement^=left] .arrow::before,.bs-popover-left .arrow::before{border-left-color:#e9eaec}.bs-popover-auto[x-placement^=bottom] .arrow::before,.bs-popover-bottom .arrow::before{border-bottom-color:#e9eaec}.tooltip-inner{background-color:#212224;border-radius:0}.bs-tooltip-auto[x-placement^=top] .arrow::before,.bs-tooltip-top .arrow::before{border-top-color:#212224}.bs-tooltip-auto[x-placement^=right] .arrow::before,.bs-tooltip-right .arrow::before{border-right-color:#212224}.bs-tooltip-auto[x-placement^=bottom] .arrow::before,.bs-tooltip-bottom .arrow::before{border-bottom-color:#212224}.bs-tooltip-auto[x-placement^=left] .arrow::before,.bs-tooltip-left .arrow::before{border-left-color:#212224}.page-link{border:1px solid transparent;border-radius:5px;padding:.4rem .7rem;margin:0 2.5px;color:#8a8a8a;transition:all .3s ease-in-out;-webkit-transition:all .3s ease-in-out;-moz-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;-ms-transition:all .3s ease-in-out}.input-group-text .checkbox input[type=checkbox]+label:before,.input-group-text .radio input[type=radio]+label:before{margin-right:0}.page-link:hover{color:#24d5d8;text-decoration:none;background-color:transparent;border-color:transparent}.page-item.disabled .page-link{color:#cacaca;border-color:transparent}.page-item.active .page-link{background:linear-gradient(120deg,#1dccdf 0,#1de4bd 100%);border-color:transparent}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{line-height:1.8;border-color:#e9eaec}.table-sm>tbody>tr>td,.table-sm>tbody>tr>th,.table-sm>tfoot>tr>td,.table-sm>tfoot>tr>th,.table-sm>thead>tr>td,.table-sm>thead>tr>th{padding:7.5px}.table-lg>tbody>tr>td,.table-lg>tbody>tr>th,.table-lg>tfoot>tr>td,.table-lg>tfoot>tr>th,.table-lg>thead>tr>td,.table-lg>thead>tr>th{padding:15px}.table-xl>tbody>tr>td,.table-xl>tbody>tr>th,.table-xl>tfoot>tr>td,.table-xl>tfoot>tr>th,.table-xl>thead>tr>td,.table-xl>thead>tr>th{padding:20px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#fbfbfb}.table-hover>tbody>tr:hover{background-color:#fafafa}.table-bordered{border:1px solid #e9eaec}.table>thead>tr>th{color:#717171;border-bottom:1px solid #e9eaec}.table .thead-dark th{background-color:#515365;border-color:#515365}.table .thead-light th,.table tr.selected{background-color:#fafafa}.table .thead-light th{border-color:#e9eaec;color:#717171}.table td,.table th{vertical-align:middle}.form-control:disabled,.form-control[readonly],.input-group-text{background-color:#f4f4f5}@media only screen and (max-width:992px){.table-overflow{width:100%;overflow-x:auto}}.form-group{margin-bottom:25px}.form-group label.control-label{display:inline-block;margin-bottom:.5rem;font-size:13px;font-weight:500;text-transform:uppercase}.checkbox input[type=checkbox]+label:before,.radio input[type=radio]+label:before{width:22px;height:22px;font-family:'Material Design Icons';font-weight:400;vertical-align:bottom;text-align:center}.form-group label.col-form-label{margin-bottom:0;line-height:1.5;padding-top:calc(.75rem + 1px);padding-bottom:calc(.75rem + 1px)}.form-control{border:1px solid #e4e5e7;border-radius:5px;line-height:2.2;font-size:14px;color:#8a8a8a;transition:all .2s ease-in;-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;-o-transition:all .2s ease-in;-ms-transition:all .2s ease-in}.form-control::-webkit-input-placeholder{color:#bdbdbd}.form-control:-moz-placeholder{color:#bdbdbd}.form-control::-moz-placeholder{color:#bdbdbd}.form-control:-ms-input-placeholder{color:#bdbdbd}.form-control:focus{outline:0;-webkit-box-shadow:1px 1px 15px rgba(0,0,0,.075);-moz-box-shadow:1px 1px 15px rgba(0,0,0,.075);box-shadow:1px 1px 15px rgba(0,0,0,.075);border-color:#24d5d8}.form-control.error{border-color:#fd3259}.form-control:disabled:focus,.form-control[readonly]:focus{border-color:#e9eaec}.form-control:disabled{cursor:not-allowed}.form-control-plaintext{padding-top:.375rem;padding-bottom:.375rem;line-height:2.2}.form-text{margin-top:5px;color:#979797}.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:.15rem .75rem}.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:.7rem .75rem}.icon-input{position:relative}.icon-input>.form-control{padding-left:50px;padding-right:50px}.icon-input>i{position:absolute;top:0;left:15px;font-size:20px;padding-top:10px;line-height:1;color:#bdbdbd}.input-group-text .checkbox,.input-group-text .radio{padding:0}.input-group>.input-group-append>.btn,.input-group>.input-group-prepend>.btn{margin:0}.input-group>.input-group-append.dropdown,.input-group>.input-group-prepend.dropdown{display:flex}.input-group-text{border:1px solid #e4e5e7;color:#a4a4a4}.textarea-md{min-height:150px}.textarea-lg{min-height:250px}.checkbox,.radio{min-height:auto;position:relative}.checkbox{padding:10px 0}.checkbox input[type=checkbox]{margin:0;display:none;width:22px}.checkbox input[type=checkbox]+label{padding-left:0}.checkbox input[type=checkbox]+label:before{content:"\F12C";display:inline-block;margin-right:10px;border:2px solid #e9eaec;border-radius:3px;font-size:15px;line-height:19px;background:#fff;color:transparent;cursor:pointer;transition:all .2s ease-in-out;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;-ms-transition:all .2s ease-in-out}.checkbox input[type=checkbox]:checked+label:before{background:#24d5d8;border-color:#24d5d8;color:#fff}.checkbox input[type=checkbox].disabled+label:before,.checkbox input[type=checkbox]:disabled+label:before{cursor:not-allowed}.checkbox input[type=checkbox].error+label:before{border-color:#ffd0d9}.checkbox.to-do input[type=checkbox]:checked+label{text-decoration:line-through}.checkbox.checkbox-primary input[type=checkbox]:checked+label:before{background:#6569df;border-color:#6569df;color:#fff}.checkbox.checkbox-info input[type=checkbox]:checked+label:before{background:#04a1f4;border-color:#04a1f4;color:#fff}.checkbox.checkbox-warning input[type=checkbox]:checked+label:before{background:#fecd2f;border-color:#fecd2f;color:#fff}.checkbox.checkbox-danger input[type=checkbox]:checked+label:before{background:#fd3259;border-color:#fd3259;color:#fff}.radio{padding:10px 0}.radio input[type=radio]{margin:0;display:none;width:22px}.radio input[type=radio]+label{padding-left:0}.radio input[type=radio]+label:before{content:"\F12F";display:inline-block;margin-right:10px;border:2px solid #e9eaec;border-radius:50%;font-size:11px;line-height:18px;background-color:#fff;color:transparent;cursor:pointer;transition:all .2s ease-in-out;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;-ms-transition:all .2s ease-in-out}.radio input[type=radio]:checked+label:before{color:#24d5d8;border-color:#24d5d8}.radio input[type=radio].disabled+label:before,.radio input[type=radio]:disabled+label:before{cursor:not-allowed}.radio.radio-primary input[type=radio]:checked+label:before{color:#6569df;border-color:#6569df}.radio.radio-info input[type=radio]:checked+label:before{color:#04a1f4;border-color:#04a1f4}.radio.radio-warning input[type=radio]:checked+label:before{color:#fecd2f;border-color:#fecd2f}.radio.radio-danger input[type=radio]:checked+label:before{color:#fd3259;border-color:#fd3259}.checkbox label,.radio label{cursor:pointer}.switch input[type=checkbox]{opacity:0;position:absolute}.switch input[type=checkbox]+label{position:relative;display:inline-block;transition:.4s ease;-webkit-transition:.4s ease;-moz-transition:.4s ease;-o-transition:.4s ease;-ms-transition:.4s ease;height:20px;width:35px;border:1px solid #e9eaec;border-radius:60px;cursor:pointer}.switch input[type=checkbox]+label:before{transition:.2s cubic-bezier(.24,0,.5,1);-webkit-transition:.2s cubic-bezier(.24,0,.5,1);-moz-transition:.2s cubic-bezier(.24,0,.5,1);-o-transition:.2s cubic-bezier(.24,0,.5,1);-ms-transition:.2s cubic-bezier(.24,0,.5,1);height:20px;width:35px;border-radius:30px}.switch input[type=checkbox]+label:after{box-shadow:0 0 0 1px rgba(0,0,0,.1),0 4px 0 0 rgba(0,0,0,.04),0 4px 9px rgba(0,0,0,.13),0 3px 3px rgba(0,0,0,.05);transition:.35s cubic-bezier(.54,1.6,.5,1);-webkit-transition:.35s cubic-bezier(.54,1.6,.5,1);-moz-transition:.35s cubic-bezier(.54,1.6,.5,1);-o-transition:.35s cubic-bezier(.54,1.6,.5,1);-ms-transition:.35s cubic-bezier(.54,1.6,.5,1);background:#f7f7f7;height:19px;width:19px;border-radius:60px}.switch input[type=checkbox]:checked+label:before{background:#24d5d8;transition:width .2s cubic-bezier(0,0,0,.1);-webkit-transition:width .2s cubic-bezier(0,0,0,.1);-moz-transition:width .2s cubic-bezier(0,0,0,.1);-o-transition:width .2s cubic-bezier(0,0,0,.1);-ms-transition:width .2s cubic-bezier(0,0,0,.1)}.switch input[type=checkbox]:checked+label:after{left:16px}.switch input[type=checkbox]:disabled+label{opacity:.7;cursor:not-allowed}.switch.switch-primary input[type=checkbox]:checked+label:before{background:#6569df}.switch.switch-info input[type=checkbox]:checked+label:before{background:#04a1f4}.switch.switch-warning input[type=checkbox]:checked+label:before{background:#fecd2f}.switch.switch-danger input[type=checkbox]:checked+label:before{background:#fd3259}.test-wrapper{padding:0;margin:0;overflow:auto;min-height:100%;transition:all .3s ease-in-out;-webkit-transition:all .3s ease-in-out;-moz-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;-ms-transition:all .3s ease-in-out;border:1px solid #e9eaec}@media only screen and (max-width:992px){.test-wrapper{position:absolute;left:0;width:100%}}.test-wrapper .test-list{position:relative;padding:0;width:100%;overflow-y:hidden;background-color:#fff}@media only screen and (min-width:992px){.test-wrapper .test-list{width:25%;border-right:1px solid #e9eaec;float:left}.test-wrapper .test-list .test-list-wrapper{height:calc(100vh - 65px - 115px - 41px)}}@media only screen and (min-width:992px) and (max-width:1440px){.test-wrapper .test-list{width:35%}}.test-wrapper .test-list .test-list-tools{padding:5px 15px;border-bottom:1px solid #e9eaec;text-align:right;display:block}.test-wrapper .test-list .test-list-tools .tools{list-style:none;padding:0}.test-wrapper .test-list .test-list-tools .tools>li{display:inline-block;padding:3px 5px}.test-wrapper .test-list .test-list-tools .tools>li>a{font-size:16px;color:#8a8a8a;display:block;transition:all .2s ease-in-out;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;-ms-transition:all .2s ease-in-out}.test-wrapper .test-list .test-list-tools .tools>li>a:focus,.test-wrapper .test-list .test-list-tools .tools>li>a:hover{color:#24d5d8}.test-wrapper .test-list .test-list-wrapper{position:relative;overflow-y:auto}.test-wrapper .test-list .test-list-wrapper .test-list-item{padding-left:0;list-style:none}.test-wrapper .test-list .test-list-wrapper .test-list-item .test-item{position:relative;display:table;width:100%;padding:15px;border-bottom:1px solid #e9eaec;cursor:pointer;transition:all .3s ease-in-out;-webkit-transition:all .3s ease-in-out;-moz-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;-ms-transition:all .3s ease-in-out}.test-wrapper .test-list .test-list-wrapper .test-list-item .test-item:focus,.test-wrapper .test-list .test-list-wrapper .test-list-item .test-item:hover{background-color:#fafafa}@media only screen and (min-width:992px){.test-wrapper .test-list .test-list-wrapper .test-list-item .test-item.active{background-color:#fafafa}}.test-wrapper .test-list .test-list-wrapper .test-list-item .test-item a{color:#8a8a8a}.test-wrapper .test-list .test-list-wrapper .test-list-item .test-item .test-avatar{position:absolute;top:20px}.test-wrapper .test-list .test-list-wrapper .test-list-item .test-item .test-avatar img{width:30px;height:30px;border-radius:50px}.test-wrapper .test-list .test-list-wrapper .test-list-item .test-item .test-detail{vertical-align:top;display:table-cell;width:100%;padding-left:45px}.test-wrapper .test-list .test-list-wrapper .test-list-item .test-item .test-detail p{margin-bottom:0}.test-wrapper .test-list .test-list-wrapper .test-list-item .test-item .test-detail .name{font-size:16px;color:#515365}.test-wrapper .test-list .test-list-wrapper .test-list-item .test-item .test-detail .subject{color:#515365;font-weight:500;margin-bottom:5px}.test-wrapper .test-list .test-list-wrapper .test-list-item .test-item .test-detail .datetime{position:absolute;top:20px;right:15px;font-size:11px}.test-wrapper .test-content{float:left;width:75%;position:relative;padding:0;background-color:#fff;height:calc(100vh - 65px - 115px);overflow:auto;transition:all .3s ease-in-out;-webkit-transition:all .3s ease-in-out;-moz-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;-ms-transition:all .3s ease-in-out}.test-wrapper .test-content.no-inbox-view{width:100%}@media only screen and (min-width:992px) and (max-width:1440px){.test-wrapper .test-content{width:65%}}@media only screen and (max-width:992px){.test-wrapper .test-content{position:fixed;width:100%;height:calc(100vh - 65px);top:calc(65px + 20px);left:-100%}.test-wrapper .test-content.open{left:0}}.test-wrapper .test-content .test-content-tools{padding:10px 15px;border-bottom:1px solid #e9eaec}@media only screen and (min-width:992px){.test-wrapper .test-content .test-content-tools{display:none}}.test-wrapper .test-content .test-content-tools ul{list-style:none;padding:0;display:inline-block}.test-wrapper .test-content .test-content-tools ul li{display:inline-block}.test-wrapper .test-content .test-content-tools ul li a{font-size:16px;padding:0 10px;color:#8a8a8a}.test-wrapper .test-content .test-content-tools ul li a:focus,.test-wrapper .test-content .test-content-tools ul li a:hover{color:#24d5d8}.test-wrapper .test-content .test-content-detail{position:relative;padding:30px;max-height:calc(100vh - 65px)}@media only screen and (max-width:992px){.test-wrapper .test-content .test-content-detail{padding:15px}.mail-nav-active .sec-side-nav{left:0}}.test-wrapper .test-content .test-content-detail .detail-head{position:relative}.test-wrapper .test-content .test-content-detail .detail-head .thumb-img{width:50px;height:50px}.test-wrapper .test-content .test-content-detail .detail-head .info{height:50px;padding-left:65px}.test-wrapper .test-content .test-content-detail .detail-head .info .title{padding-top:5px}.test-wrapper .test-content .test-content-detail .detail-head .info .sub-title{max-width:100%}.test-wrapper .test-content .test-content-detail .detail-head .tools{padding:0;list-style:none;float:right;margin-top:15px}.test-wrapper .test-content .test-content-detail .detail-head .tools>li{display:inline-block;padding:10px}.test-wrapper .test-content .test-content-detail .detail-head .tools>li a{color:#8a8a8a}.test-wrapper .test-content .test-content-detail .detail-head .tools>li a:focus,.test-wrapper .test-content .test-content-detail .detail-head .tools>li a:hover{color:#515365}.test-wrapper .test-content .test-content-detail .detail-body{padding:25px 30px;position:relative}.test-wrapper .test-content .test-content-detail .detail-foot{padding:15px 30px}.test-wrapper .test-content .test-content-detail .detail-foot .attachments{list-style:none;padding-left:0}.test-wrapper .test-content .test-content-detail .detail-foot .attachments>li{display:inline-block;border:1px solid #e9eaec;margin-right:10px;margin-bottom:10px;border-radius:6px}.test-wrapper .test-content .test-content-detail .detail-foot .attachments>li>a{display:block;color:#8a8a8a}.test-wrapper .test-content .test-content-detail .detail-foot .attachments>li>a .file-icon{float:left;padding:8px 15px;font-size:28px;border-right:1px solid #e9eaec}.test-wrapper .test-content .test-content-detail .detail-foot .attachments>li>a .file-info{display:inline-block;padding:8px 15px 8px 10px}.test-wrapper .test-content .test-content-detail .detail-foot .attachments>li>a .file-info .file-name,.test-wrapper .test-content .test-content-detail .detail-foot .attachments>li>a .file-info .file-size{display:block}.test-wrapper .test-content .test-content-detail .detail-foot .attachments>li>a:focus,.test-wrapper .test-content .test-content-detail .detail-foot .attachments>li>a:hover{color:#515365}.test-wrapper .test-content .test-content-detail .detail-foot .attachments>li>a:focus .file-icon,.test-wrapper .test-content .test-content-detail .detail-foot .attachments>li>a:hover .file-icon{color:#24d5d8}.test-wrapper .email-compose{position:relative}.test-wrapper .email-compose .email-compose-tools{background-color:#fafafa;padding:10px 15px;border-bottom:1px solid #e9eaec}@media only screen and (min-width:992px){.test-wrapper .email-compose .email-compose-tools{display:none}}.test-wrapper .email-compose .email-compose-tools ul{list-style:none;padding:0;display:inline-block}.test-wrapper .email-compose .email-compose-tools ul li{display:inline-block}.test-wrapper .email-compose .email-compose-tools ul li a{font-size:16px;padding:0 10px;color:#8a8a8a}.test-wrapper .email-compose .email-compose-tools ul li a:focus,.test-wrapper .email-compose .email-compose-tools ul li a:hover{color:#24d5d8}.test-wrapper .email-compose .email-compose-body{padding:30px 20px}.test-wrapper .email-compose .email-compose-body .send-header .selectize-input{box-shadow:none;border:0;border-bottom:1px solid #e9eaec;font-size:14px;padding:12px}.test-wrapper .email-compose .email-compose-body .send-header .selectize-input input::-webkit-input-placeholder{font-size:14px;color:#bdbdbd}.test-wrapper .email-compose .email-compose-body .send-header .selectize-input input:-moz-placeholder{font-size:14px;color:#bdbdbd}.test-wrapper .email-compose .email-compose-body .send-header .selectize-input input::-moz-placeholder{font-size:14px;color:#bdbdbd}.test-wrapper .email-compose .email-compose-body .send-header .selectize-input input:-ms-input-placeholder{font-size:14px;color:#bdbdbd}.test-wrapper .email-compose .email-compose-body .send-header .subject{border:0;padding:12px}.test-wrapper .email-compose .email-compose-body .send-header .subject::-webkit-input-placeholder{font-size:14px;color:#bdbdbd}.test-wrapper .email-compose .email-compose-body .send-header .subject:-moz-placeholder{font-size:14px;color:#bdbdbd}.test-wrapper .email-compose .email-compose-body .send-header .subject::-moz-placeholder{font-size:14px;color:#bdbdbd}.test-wrapper .email-compose .email-compose-body .send-header .subject:-ms-input-placeholder{font-size:14px;color:#bdbdbd}.test-wrapper .email-compose .email-compose-body .note-editor{margin-top:5px}.test-wrapper .email-compose .email-compose-body .note-editor.note-frame .note-statusbar{display:none}.test-wrapper .email-compose .email-compose-body .note-editor .panel-heading.note-toolbar{position:absolute;z-index:9;width:100%;bottom:0;border-bottom:0;border-top:1px solid #e9eaec}@media only screen and (max-width:992px){.mail-nav-active .test-wrapper{left:200px}} + + /** + * Featherlight - ultra slim jQuery lightbox + * Version 1.5.0 - http://noelboss.github.io/featherlight/ + * + * Copyright 2016, Noël Raoul Bossart (http://www.noelboss.com) + * MIT Licensed. +**/ +@media all{.featherlight{display:none;position:fixed;top:0;right:0;bottom:0;left:0;z-index:2147483647;text-align:center;white-space:nowrap;cursor:pointer;background:#333;background:rgba(0,0,0,0)}.featherlight:last-of-type{background:rgba(0,0,0,.8)}.featherlight:before{content:'';display:inline-block;height:100%;vertical-align:middle;margin-right:-.25em}.featherlight .featherlight-content{position:relative;text-align:left;vertical-align:middle;display:inline-block;overflow:auto;padding:25px 25px 0;border-bottom:25px solid transparent;margin-left:5%;margin-right:5%;max-height:95%;background:#fff;cursor:auto;white-space:normal}.featherlight .featherlight-inner{display:block}.featherlight .featherlight-close-icon{position:absolute;z-index:9999;top:0;right:0;line-height:25px;width:25px;cursor:pointer;text-align:center;font-family:Arial,sans-serif;background:#fff;background:rgba(255,255,255,.3);color:#000}.featherlight .featherlight-image{width:100%}.featherlight-iframe .featherlight-content{border-bottom:0;padding:0}.featherlight iframe{border:0}.featherlight *{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}}@media only screen and (max-width:1024px){.featherlight .featherlight-content{margin-left:10px;margin-right:10px;max-height:98%;padding:10px 10px 0;border-bottom:10px solid transparent}} + +/** + * json-tree + * Copyright (c) 2013 Leonardo Menezes + * https://github.com/lmenezes/json-tree + * MIT Licensed. + */ +.jstBracket,.jstComma,.jstValue{white-space:pre-wrap}.jstValue{font-size:10px;font-weight:400;font-family:"Lucida Console",Monaco,monospace}.jstProperty{color:#666;word-wrap:break-word}.jstBool{color:#2525CC}.jstNum{color:#D036D0}.jstNull{color:gray}.jstStr{color:#2DB669}.jstFold:after{content:' -';cursor:pointer}.jstExpand{white-space:normal}.jstExpand:after{content:' +';cursor:pointer}.jstFolded{white-space:normal!important}.jstHiddenBlock{display:none} + + + +/** + * Extent Framework, Version 4, Spark, HtmlReporter + * AventStack + * Licender under Apache 2.0 + **/ + +body, p { + font-family: Roboto,-apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Arial, sans-serif; + color: #585858; + font-size: 13px; +} +h5 { + font-size: 16px; + font-weight: 500; +} +table > thead > tr > th { + font-weight: 500 !important; + font-size: 11px; + text-transform: uppercase; +} +td { + word-break: break-all; +} +.small, small { + font-size: 85%; +} + +/** + * Topnav + * +**/ +.header, .header .header-container .nav-left>li>a, .header .header-container .nav-right>li>a { + height: 55px; + min-height: 55px; + line-height: 55px; +} +.header .header-container .nav-logo>a .logo { + min-height: 52px; +} +.header .header-container .nav-left>li>a i { + font-size: 18px; +} + +/** + * Sidenav + * +**/ +.side-nav { + top: 55px; +} +.side-nav-controls { + position: absolute; + left: -15px; + bottom: 10px; +} +.side-nav-controls li { + list-style: none; +} +.side-nav .side-nav-inner .side-nav-menu>li>a { + font-size: inherit; +} + +/** + * Wrappers + * +**/ +.page-container .main-content { + padding: 55px 0 0; + height: calc(100vh); + min-height: calc(100vh); +} +.test-wrapper { + border-left: none !important; +} +.test-wrapper .test-content { + height: calc(100vh - 64px); +} +.test-list-item { + margin-bottom: 50px; +} +.side-nav { + background-color: transparent; +} + + +/** + * base classes + * +**/ +.text-sm { + font-size: 11px; +} +.form-control, .form-control:focus { + color: #ccc; +} +.dropdown-toggle:after { + display: none; +} +.box-height-150 { + height: 150px !important; +} + +/** + * Test Content + * +**/ + +/* test list */ +.test-wrapper .test-list .test-list-wrapper .test-list-item .test-item { + padding: 10px 15px; +} +.test-wrapper .test-list { + background: #fff; +} +.test-wrapper .test-list .test-list-wrapper .test-list-item .test-item .test-detail { + display: block; + padding-left: 5px; +} +.test-view.test-wrapper .test-list .test-list-wrapper .test-list-item .test-item .test-detail { + padding-left: 40px; +} +.status-avatar { + width: 20px; + height: 20px; + border-radius: 100%; + text-align: center; + vertical-align: middle; + color: #000; + font-size: 11px; + font-weight: 500; + padding-top: 1px; + text-transform: lowercase; +} +.test-view .status-avatar { + position: absolute; + padding-top: 3px; + top: 18px; +} +.accordion .status-avatar { + top: 20px; + position: relative; + right: 20px; +} +.test-detail .name { + font-size: 13px !important; + font-weight: 500; + word-break: break-all; + width: 80%; +} + +/* attributes-view */ +.attributes-view .info > span { + cursor: pointer; +} + +/* bdd-report */ +.bdd-report .accordion .status-avatar { + right: 0; +} +.bdd-report .node { + padding: 20px 15px 0; +} +.bdd-report .card .card-body { + padding: 0 16px 20px 16px; +} +.bdd-report .accordion .node { + +} +.bdd-report .accordion .node-description { + font-weight: 400; + padding-left: 40px; +} +.bdd-report .accordion>.card>.card-header { + padding-bottom: 20px; +} +.given, .when, .then, .and, .asterisk, .but { + font-weight: 400; + padding-top: 10px; +} +.bdd-report .alert-icon { + font-size: 11px; + border-radius: 100%; + padding: 0; + height: 20px; + width: 20px; + margin-right: 15px; +} +.bdd-report .alert-icon > i { + padding-left: 4px; + padding-top: 4px; +} +.bdd-report .alert-icon > i.fa-times { + padding-left: 6px; +} +.bdd-report .details, .bdd-report .code-block { + margin-left: 35px; +} +.bdd-report .code-block { + width: 95%; +} +.bdd-report .scenario_outline { + padding: 10px 20px 0; +} +.bdd-report .scenario_outline .card-header { + padding: 0; + min-height: auto !important; +} +.bdd-report .scenario_outline .card-header .node { + padding: 0; +} +.bdd-report .scenario_outline .card-header .status-avatar { + top: 2px; + margin-right: 15px; +} +.bdd-report .scenario { + font-weight: 500; +} +.bdd-report .card-body.l1 { + border: 1px solid rgba(0,0,0,.125); + margin-bottom: 20px; + padding-top: 15px; +} +.bdd-report .card-body.l1 .card-body { + padding: 0; +} + +/* content */ +.test-wrapper .test-content .test-content-detail { + padding: 30px 20px; +} +.test-wrapper .test-content .test-content-detail .detail-head .info { + padding-left: 0; +} +.test-wrapper .test-content .test-content-detail .detail-body { + padding: 0; +} +.test-wrapper .test-content .test-content-detail .detail-foot { + padding: 15px 0; +} +pre, .code-block { + background-color: #f8f9fa; + border: 1px solid #ebedef; + border-radius: 4px; + color: #222 !important; + font-family: Consolas,monospace; + font-size: 13px; + margin: 0; + padding: 7px 10px; + white-space: pre-wrap; +} +textarea { + resize: auto; + width: 100%; +} +.status-col { + width: 70px; +} +.timestamp-col { + width: 110px; +} +img.r-img { + width: 5%; +} + +/* nodes */ +.card > .accordion { + margin-left: 20px; + margin-right: 20px; +} +.detail-body + .accordion { + margin-top: -20px; +} +.card-header .card-title { + display: block; + cursor: pointer; +} +.card .card-body { + padding: 20px; +} +.node + a { + float: right !important; +} +.node { + display: inline-block; + padding: 20px; + font-weight: 500; +} +.accordion > .card > .card-header > .card-title > a:not(.collapsed):after { + display: none; +} +.card-body .description { + margin-top: -20px; + margin-bottom: 20px; + font-size: 90%; +} + +/* status */ +.log-status { + border-radius: 100%; +} +.item-meta .badge { + font-size: 11px; +} +.transparent-bg { + background-color:transparent !important; +} +.text-fail,.text-fatal { + color:#ff5722 !important; +} +.text-error { + color:#ff9800 !important; +} +.text-warning { + color:#ffc107 !important; +} +.text-info { + color:#00bcd4 !important; +} +.text-skip { + color: #64b5f6 !important; +} +.text-pass { + color: #1c965b !important; +} +.fail-bg, .fatal-bg,.avatar.fail,.avatar.fatal { + background: #e57373; +} +.pass-bg,.avatar.pass { + background: #9ccc65; +} +.skip-bg,.avatar.skip { + background: #ff9900; +} +.error-bg,.avatar.skip { + background: #ffd54f; +} +.warn-bg,.avatar.warn,.warning-bg,.avatar.warning { + background: #ffc107; +} +.b-skip { + border-color: #64b5f6; +} + .badge-skip { + background-color: #ff9900 !important; + color: #fff; + } +.badge.status { + background: transparent !important; +} + +/* jsonTree */ +.jstValue { + font-size: 11px; +} +.jstProperty, .jstFold { + color: #444; +} +.dark .jstProperty, .dark .jstFold { + color: #eee; +} +.jstStr { + color: #00b300; +} +.dark .jstStr { + color: #7ffaaa; +} +.dark .jstBool { + color: #668cff; +} +.dark .jstNum { + color: #ff66ff; +} + +/** + * dashboard + * +**/ +.dashboard-view .media>.card-header { + padding:0 +} + + +/** + * Themes + * +**/ + +.dark .header, body.dark { + background-color: #08111c; +} +.dark .side-nav, .dark .test-list { + background-color: #19222d !important; + border-right: none; +} +.dark .test-wrapper { + border: none; +} +.dark .test-list-tools, .dark .header { + border-bottom: 1px solid #19222d !important; +} +.dark .test-item, .dark .table>thead>tr>th, .dark .table>tbody>tr>td { + border-bottom: 1px solid #494949 !important; +} +.dark .table>thead>tr>th, .dark .table>tbody>tr>td, .dark .card-footer, .dark td, .dark th { + border-top: 1px solid #494949; +} +.dark .test-item.active, .dark .test-item:hover { + background-color: #19221c !important; +} +.dark .test-detail .name, .dark p { + color: rgba(141,164,191,.95) !important; +} +.dark .test-wrapper, .dark .test-content, .dark .dashboard-view .container-fluid { + background-color: #243140; +} +.dark .card, .dark .attachments>li, .dark .badge-default { + color: rgba(141,164,191,.95) !important; + border: 1px solid #494949 !important; +} +.dark .card, .dark tr.bg-gray, .dark .table, .dark table, dark tr, .dark th, .dark td, .dark .table-striped>tbody>tr:nth-of-type(odd) { + background-color: transparent !important; +} +.dark .side-nav .side-nav-inner .side-nav-menu, .dark .file-icon { + border-right: 1px solid #494949 !important; +} +.dark .node { + color: #999; +} +.dark, .dark .table>thead>tr>th, .dark h1, .dark h2, .dark h3, .dark h4, .dark .font-weight-light, .dark .card-title, .dark .detail-head h4 { + color: #999; +} +.dark pre, .dark .code-block { + background: transparent; + border: 1px solid #555; + color: rgba(180,200,220,.95) !important; +} + +@media only screen and (min-width: 992px) { + .test-wrapper .test-list .test-list-wrapper { + height: calc(100vh - 106px); + } + .test-wrapper .test-list { + width: 32%; + } + .test-wrapper .test-content { + width: 68%; + } +} +@media only screen and (max-width: 992px) { + .test-wrapper .test-content.open { + top: 65px; + } +} diff --git a/src/main/resources/com/aventstack/extentreports/offline/spark/js/spark-script.js b/src/main/resources/com/aventstack/extentreports/offline/spark/js/spark-script.js new file mode 100644 index 0000000..c853841 --- /dev/null +++ b/src/main/resources/com/aventstack/extentreports/offline/spark/js/spark-script.js @@ -0,0 +1,381 @@ +/*! jQuery v3.2.1 | (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",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)}});function _a(a,b,c,d,e){return new _a.prototype.init(a,b,c,d,e)}r.Tween=_a,_a.prototype={constructor:_a,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||r.easing._default,this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(r.cssNumber[c]?"":"px")},cur:function(){var a=_a.propHooks[this.prop];return a&&a.get?a.get(this):_a.propHooks._default.get(this)},run:function(a){var b,c=_a.propHooks[this.prop];return this.options.duration?this.pos=b=r.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):_a.propHooks._default.set(this),this}},_a.prototype.init.prototype=_a.prototype,_a.propHooks={_default:{get:function(a){var b;return 1!==a.elem.nodeType||null!=a.elem[a.prop]&&null==a.elem.style[a.prop]?a.elem[a.prop]:(b=r.css(a.elem,a.prop,""),b&&"auto"!==b?b:0)},set:function(a){r.fx.step[a.prop]?r.fx.step[a.prop](a):1!==a.elem.nodeType||null==a.elem.style[r.cssProps[a.prop]]&&!r.cssHooks[a.prop]?a.elem[a.prop]=a.now:r.style(a.elem,a.prop,a.now+a.unit)}}},_a.propHooks.scrollTop=_a.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},r.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},_default:"swing"},r.fx=_a.prototype.init,r.fx.step={};var ab,bb,cb=/^(?:toggle|show|hide)$/,db=/queueHooks$/;function eb(){bb&&(d.hidden===!1&&a.requestAnimationFrame?a.requestAnimationFrame(eb):a.setTimeout(eb,r.fx.interval),r.fx.tick())}function fb(){return a.setTimeout(function(){ab=void 0}),ab=r.now()}function gb(a,b){var c,d=0,e={height:a};for(b=b?1:0;d<4;d+=2-b)c=ca[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function hb(a,b,c){for(var d,e=(kb.tweeners[b]||[]).concat(kb.tweeners["*"]),f=0,g=e.length;f1)},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)?lb: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)}}),lb={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=mb[b]||r.find.attr;mb[b]=function(a,b,d){var e,f,g=b.toLowerCase();return d||(f=mb[g],mb[g]=e,e=null!=c(a,b,d)?g:null,mb[g]=f),e}});var nb=/^(?:input|select|textarea|button)$/i,ob=/^(?: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):nb.test(a.nodeName)||ob.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 pb(a){var b=a.match(L)||[];return b.join(" ")}function qb(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,qb(this)))});if("string"==typeof a&&a){b=a.match(L)||[];while(c=this[i++])if(e=qb(c),d=1===c.nodeType&&" "+pb(e)+" "){g=0;while(f=b[g++])d.indexOf(" "+f+" ")<0&&(d+=f+" ");h=pb(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,qb(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof a&&a){b=a.match(L)||[];while(c=this[i++])if(e=qb(c),d=1===c.nodeType&&" "+pb(e)+" "){g=0;while(f=b[g++])while(d.indexOf(" "+f+" ")>-1)d=d.replace(" "+f+" "," ");h=pb(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,qb(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=qb(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&&(" "+pb(qb(c))+" ").indexOf(b)>-1)return!0;return!1}});var rb=/\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(rb,""):null==c?"":c)}}}),r.extend({valHooks:{option:{get:function(a){var b=r.find.attr(a,"value");return null!=b?b:pb(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 sb=/^(?: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&&!sb.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,sb.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 tb=a.location,ub=r.now(),vb=/\?/;r.parseXML=function(b){var c;if(!b||"string"!=typeof b)return null;try{c=(new a.DOMParser).parseFromString(b,"text/xml")}catch(d){c=void 0}return c&&!c.getElementsByTagName("parsererror").length||r.error("Invalid XML: "+b),c};var wb=/\[\]$/,xb=/\r?\n/g,yb=/^(?:submit|button|image|reset|file)$/i,zb=/^(?:input|select|textarea|keygen)/i;function Ab(a,b,c,d){var e;if(Array.isArray(b))r.each(b,function(b,e){c||wb.test(a)?d(a,e):Ab(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)Ab(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)Ab(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")&&zb.test(this.nodeName)&&!yb.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(xb,"\r\n")}}):{name:b.name,value:c.replace(xb,"\r\n")}}).get()}});var Bb=/%20/g,Cb=/#.*$/,Db=/([?&])_=[^&]*/,Eb=/^(.*?):[ \t]*([^\r\n]*)$/gm,Fb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Gb=/^(?:GET|HEAD)$/,Hb=/^\/\//,Ib={},Jb={},Kb="*/".concat("*"),Lb=d.createElement("a");Lb.href=tb.href;function Mb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(L)||[];if(r.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Nb(a,b,c,d){var e={},f=a===Jb;function g(h){var i;return e[h]=!0,r.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Ob(a,b){var c,d,e=r.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&r.extend(!0,a,d),a}function Pb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}if(f)return f!==i[0]&&i.unshift(f),c[f]}function Qb(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}r.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:tb.href,type:"GET",isLocal:Fb.test(tb.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Kb,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":r.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Ob(Ob(a,r.ajaxSettings),b):Ob(r.ajaxSettings,a)},ajaxPrefilter:Mb(Ib),ajaxTransport:Mb(Jb),ajax:function(b,c){"object"==typeof b&&(c=b,b=void 0),c=c||{};var e,f,g,h,i,j,k,l,m,n,o=r.ajaxSetup({},c),p=o.context||o,q=o.context&&(p.nodeType||p.jquery)?r(p):r.event,s=r.Deferred(),t=r.Callbacks("once memory"),u=o.statusCode||{},v={},w={},x="canceled",y={readyState:0,getResponseHeader:function(a){var b;if(k){if(!h){h={};while(b=Eb.exec(g))h[b[1].toLowerCase()]=b[2]}b=h[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return k?g:null},setRequestHeader:function(a,b){return null==k&&(a=w[a.toLowerCase()]=w[a.toLowerCase()]||a,v[a]=b),this},overrideMimeType:function(a){return null==k&&(o.mimeType=a),this},statusCode:function(a){var b;if(a)if(k)y.always(a[y.status]);else for(b in a)u[b]=[u[b],a[b]];return this},abort:function(a){var b=a||x;return e&&e.abort(b),A(0,b),this}};if(s.promise(y),o.url=((b||o.url||tb.href)+"").replace(Hb,tb.protocol+"//"),o.type=c.method||c.type||o.method||o.type,o.dataTypes=(o.dataType||"*").toLowerCase().match(L)||[""],null==o.crossDomain){j=d.createElement("a");try{j.href=o.url,j.href=j.href,o.crossDomain=Lb.protocol+"//"+Lb.host!=j.protocol+"//"+j.host}catch(z){o.crossDomain=!0}}if(o.data&&o.processData&&"string"!=typeof o.data&&(o.data=r.param(o.data,o.traditional)),Nb(Ib,o,c,y),k)return y;l=r.event&&o.global,l&&0===r.active++&&r.event.trigger("ajaxStart"),o.type=o.type.toUpperCase(),o.hasContent=!Gb.test(o.type),f=o.url.replace(Cb,""),o.hasContent?o.data&&o.processData&&0===(o.contentType||"").indexOf("application/x-www-form-urlencoded")&&(o.data=o.data.replace(Bb,"+")):(n=o.url.slice(f.length),o.data&&(f+=(vb.test(f)?"&":"?")+o.data,delete o.data),o.cache===!1&&(f=f.replace(Db,"$1"),n=(vb.test(f)?"&":"?")+"_="+ub++ +n),o.url=f+n),o.ifModified&&(r.lastModified[f]&&y.setRequestHeader("If-Modified-Since",r.lastModified[f]),r.etag[f]&&y.setRequestHeader("If-None-Match",r.etag[f])),(o.data&&o.hasContent&&o.contentType!==!1||c.contentType)&&y.setRequestHeader("Content-Type",o.contentType),y.setRequestHeader("Accept",o.dataTypes[0]&&o.accepts[o.dataTypes[0]]?o.accepts[o.dataTypes[0]]+("*"!==o.dataTypes[0]?", "+Kb+"; q=0.01":""):o.accepts["*"]);for(m in o.headers)y.setRequestHeader(m,o.headers[m]);if(o.beforeSend&&(o.beforeSend.call(p,y,o)===!1||k))return y.abort();if(x="abort",t.add(o.complete),y.done(o.success),y.fail(o.error),e=Nb(Jb,o,c,y)){if(y.readyState=1,l&&q.trigger("ajaxSend",[y,o]),k)return y;o.async&&o.timeout>0&&(i=a.setTimeout(function(){y.abort("timeout")},o.timeout));try{k=!1,e.send(v,A)}catch(z){if(k)throw z;A(-1,z)}}else A(-1,"No Transport");function A(b,c,d,h){var j,m,n,v,w,x=c;k||(k=!0,i&&a.clearTimeout(i),e=void 0,g=h||"",y.readyState=b>0?4:0,j=b>=200&&b<300||304===b,d&&(v=Pb(o,y,d)),v=Qb(o,v,y,j),j?(o.ifModified&&(w=y.getResponseHeader("Last-Modified"),w&&(r.lastModified[f]=w),w=y.getResponseHeader("etag"),w&&(r.etag[f]=w)),204===b||"HEAD"===o.type?x="nocontent":304===b?x="notmodified":(x=v.state,m=v.data,n=v.error,j=!n)):(n=x,!b&&x||(x="error",b<0&&(b=0))),y.status=b,y.statusText=(c||x)+"",j?s.resolveWith(p,[m,x,y]):s.rejectWith(p,[y,x,n]),y.statusCode(u),u=void 0,l&&q.trigger(j?"ajaxSuccess":"ajaxError",[y,o,j?m:n]),t.fireWith(p,[y,x]),l&&(q.trigger("ajaxComplete",[y,o]),--r.active||r.event.trigger("ajaxStop")))}return y},getJSON:function(a,b,c){return r.get(a,b,c,"json")},getScript:function(a,b){return r.get(a,void 0,b,"script")}}),r.each(["get","post"],function(a,b){r[b]=function(a,c,d,e){return r.isFunction(c)&&(e=e||d,d=c,c=void 0),r.ajax(r.extend({url:a,type:b,dataType:e,data:c,success:d},r.isPlainObject(a)&&a))}}),r._evalUrl=function(a){return r.ajax({url:a,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},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)},r.ajaxSettings.xhr=function(){try{return new a.XMLHttpRequest}catch(b){}};var Rb={0:200,1223:204},Sb=r.ajaxSettings.xhr();o.cors=!!Sb&&"withCredentials"in Sb,o.ajax=Sb=!!Sb,r.ajaxTransport(function(b){var c,d;if(o.cors||Sb&&!b.crossDomain)return{send:function(e,f){var g,h=b.xhr();if(h.open(b.type,b.url,b.async,b.username,b.password),b.xhrFields)for(g in b.xhrFields)h[g]=b.xhrFields[g];b.mimeType&&h.overrideMimeType&&h.overrideMimeType(b.mimeType),b.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest");for(g in e)h.setRequestHeader(g,e[g]);c=function(a){return function(){c&&(c=d=h.onload=h.onerror=h.onabort=h.onreadystatechange=null,"abort"===a?h.abort():"error"===a?"number"!=typeof h.status?f(0,"error"):f(h.status,h.statusText):f(Rb[h.status]||h.status,h.statusText,"text"!==(h.responseType||"text")||"string"!=typeof h.responseText?{binary:h.response}:{text:h.responseText},h.getAllResponseHeaders()))}},h.onload=c(),d=h.onerror=c("error"),void 0!==h.onabort?h.onabort=d:h.onreadystatechange=function(){4===h.readyState&&a.setTimeout(function(){c&&d()})},c=c("abort");try{h.send(b.hasContent&&b.data||null)}catch(i){if(c)throw i}},abort:function(){c&&c()}}}),r.ajaxPrefilter(function(a){a.crossDomain&&(a.contents.script=!1)}),r.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(a){return r.globalEval(a),a}}}),r.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),r.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(e,f){b=r(" \ No newline at end of file diff --git a/src/main/resources/com/aventstack/extentreports/view/commons/commons-macros.ftl b/src/main/resources/com/aventstack/extentreports/view/commons/commons-macros.ftl index e7af660..6967e19 100644 --- a/src/main/resources/com/aventstack/extentreports/view/commons/commons-macros.ftl +++ b/src/main/resources/com/aventstack/extentreports/view/commons/commons-macros.ftl @@ -1,19 +1,19 @@ <#macro attributes test> - <#if test.hasCategory()> + <#if TestService.testHasCategory(test)> <#list test.categoryContext.all as category> ${category.name} - <#if test.hasAuthor()> + <#if TestService.testHasAuthor(test)> <#list test.authorContext.all as author> ${author.name} - <#if test.hasDevice()> + <#if TestService.testHasDevice(test)> <#list test.deviceContext.all as device> ${device.name} @@ -23,9 +23,8 @@ <#macro media el> - <#if el.hasScreenCapture()> - <#if el.screenCaptureContext??>${el.screenCaptureContext.last.source} - <#else>${el.screenCaptureList[0].source} + <#if el.screenCaptureContext?? && !el.screenCaptureContext.isEmpty()> + ${el.screenCaptureContext.last.source} @@ -33,10 +32,10 @@ <#assign n=test level=n.level> <#if level!=0><#assign n=test.parent><#if n.level!=0><#assign n=n.parent><#if n.level!=0><#assign n=n.parent> - + ${test.status} ${test.name} <#if level!=0>
${test.parent.name} - ${test.runDuration}c + ${TestService.getRunDuration(test)}c <@attributes test=test /> <@media el=test /> diff --git a/src/main/resources/com/aventstack/extentreports/view/commons/commons-tag.ftl b/src/main/resources/com/aventstack/extentreports/view/commons/commons-tag.ftl index 397d4f8..f798ff4 100644 --- a/src/main/resources/com/aventstack/extentreports/view/commons/commons-tag.ftl +++ b/src/main/resources/com/aventstack/extentreports/view/commons/commons-tag.ftl @@ -37,7 +37,7 @@ Source - <#list category.getTestList() as test> + <#list category.tests as test> <@row test=test level=test.level /> diff --git a/src/main/resources/com/aventstack/extentreports/view/commons/commons-variables.ftl b/src/main/resources/com/aventstack/extentreports/view/commons/commons-variables.ftl index 4afd7a0..c0ffa55 100644 --- a/src/main/resources/com/aventstack/extentreports/view/commons/commons-variables.ftl +++ b/src/main/resources/com/aventstack/extentreports/view/commons/commons-variables.ftl @@ -1,13 +1,13 @@ -<#assign config=report.configContext> +<#assign config=report.configurationStore> <#assign offline="false"> -<#if config.getValue("enableOfflineMode")??><#assign offline=config.getValue("enableOfflineMode")> +<#if config.getConfig("enableOfflineMode")??><#assign offline=config.getConfig("enableOfflineMode")> -<#assign theme=config.containsKey('theme')?then(config.getValue('theme')?lower_case, '')> +<#assign theme=config.containsConfig('theme')?then(config.getConfig('theme')?lower_case, '')> <#assign systemAttributeContext=report.getSystemAttributeContext().getSystemAttributeList()> -<#assign categoryContext=report.getCategoryContextInfo().getTestAttributeTestContextList()> -<#assign authorContext=report.getAuthorContextInfo().getTestAttributeTestContextList()> -<#assign deviceContext=report.getDeviceContextInfo().getTestAttributeTestContextList()> -<#assign exceptionContext=report.getExceptionContextInfo().getExceptionTestContextList()> +<#assign categoryContext=report.getCategoryContextInfo().getTestAttributeTestContext()> +<#assign authorContext=report.getAuthorContextInfo().getTestAttributeTestContext()> +<#assign deviceContext=report.getDeviceContextInfo().getTestAttributeTestContext()> +<#assign exceptionContext=report.exceptionContextInfo.exceptionTestContext> <#assign reportType="" parentHeading="Tests" childHeading="Steps" grandChildHeading="" size=2> <#if report.analysisStrategy=="SUITE"> @@ -23,4 +23,28 @@ <#assign parentHeading="Class" childHeading="Methods" grandChildHeading="" size=2> -<#assign timeStampFormat=config.getValue('timeStampFormat')> \ No newline at end of file +<#assign timeStampFormat=config.getConfig('timeStampFormat')> + +<#assign boxsize='col-md-6' displayEvents=true> +<#if report.reportStatusStats.childCount!=0> + <#assign boxsize='col-sm-12 col-md-4'> + +<#if (report.analysisStrategy=="BDD") || (report.reportStatusStats.childCount != 0 && report.reportStatusStats.grandChildCount != 0)> + <#assign boxsize='col-sm-12 col-md-4' displayEvents=false> + + +<#assign chartWidth="115" chartHeight="90" chartBoxHeight="94"> + +<#assign reportType="" parentHeading="Tests" childHeading="Steps" grandChildHeading="" size=2> +<#if report.analysisStrategy=="SUITE"> + <#assign parentHeading="Suite" childHeading="Tests" grandChildHeading="Tests" size=2> + <#if report.reportStatusStats.grandChildCount!=0> + <#assign childHeading="Classes" grandChildHeading="Tests" size=3> + + +<#if report.analysisStrategy=="BDD"> + <#assign reportType="bdd" parentHeading="Features" childHeading="Scenarios" grandChildHeading="Steps" size=3> + +<#if report.analysisStrategy=="CLASS"> + <#assign parentHeading="Class" childHeading="Methods" grandChildHeading="" size=2> + \ No newline at end of file diff --git a/src/main/resources/com/aventstack/extentreports/view/logger/logger-dashboard.ftl b/src/main/resources/com/aventstack/extentreports/view/logger/logger-dashboard.ftl index ec4f38f..c6e22cb 100644 --- a/src/main/resources/com/aventstack/extentreports/view/logger/logger-dashboard.ftl +++ b/src/main/resources/com/aventstack/extentreports/view/logger/logger-dashboard.ftl @@ -25,10 +25,10 @@ - <#assign p="https://cdn.rawgit.com/extent-framework/extent-github-cdn/d74480e/commons/js/"> - <#if offline=="true"><#assign p=config.getValue("offlineDirectory")> + <#assign p="https://cdn.jsdelivr.net/gh/extent-framework/extent-github-cdn@832f979664f9d68bf618db3ac87498ac6c1a6390/commons/js/"> + <#if offline=="true"><#assign p=config.getConfig("offlineDirectory")> - <#if config.containsKey("scripts") && config.getValue("scripts")?has_content> + <#if config.containsConfig("scripts") && config.getConfig("scripts")?has_content> <#include "../commons/commons-inject-js.ftl"> <#include "../commons/commons-dashboard-scripts.ftl"> diff --git a/src/main/resources/com/aventstack/extentreports/view/logger/logger-exception.ftl b/src/main/resources/com/aventstack/extentreports/view/logger/logger-exception.ftl index 613aac4..223fc26 100644 --- a/src/main/resources/com/aventstack/extentreports/view/logger/logger-exception.ftl +++ b/src/main/resources/com/aventstack/extentreports/view/logger/logger-exception.ftl @@ -47,10 +47,10 @@ - <#assign p="https://cdn.rawgit.com/extent-framework/extent-github-cdn/d74480e/commons/js/"> - <#if offline=="true"><#assign p=config.getValue("offlineDirectory")> + <#assign p="https://cdn.jsdelivr.net/gh/extent-framework/extent-github-cdn@832f979664f9d68bf618db3ac87498ac6c1a6390/commons/js/"> + <#if offline=="true"><#assign p=config.getConfig("offlineDirectory")> - <#if config.containsKey("scripts") && config.getValue("scripts")?has_content> + <#if config.containsConfig("scripts") && config.getConfig("scripts")?has_content> <#include "../commons/commons-inject-js.ftl"> diff --git a/src/main/resources/com/aventstack/extentreports/view/logger/logger-tag.ftl b/src/main/resources/com/aventstack/extentreports/view/logger/logger-tag.ftl index d53e3e5..ce25a77 100644 --- a/src/main/resources/com/aventstack/extentreports/view/logger/logger-tag.ftl +++ b/src/main/resources/com/aventstack/extentreports/view/logger/logger-tag.ftl @@ -55,10 +55,10 @@ - <#assign p="https://cdn.rawgit.com/extent-framework/extent-github-cdn/d74480e/commons/js/"> - <#if offline=="true"><#assign p=config.getValue("offlineDirectory")> + <#assign p="https://cdn.jsdelivr.net/gh/extent-framework/extent-github-cdn@832f979664f9d68bf618db3ac87498ac6c1a6390/commons/js/"> + <#if offline=="true"><#assign p=config.getConfig("offlineDirectory")> - <#if config.containsKey("scripts") && config.getValue("scripts")?has_content> + <#if config.containsConfig("scripts") && config.getConfig("scripts")?has_content> <#include "../commons/commons-inject-js.ftl"> diff --git a/src/main/resources/com/aventstack/extentreports/view/logger/logger-test.ftl b/src/main/resources/com/aventstack/extentreports/view/logger/logger-test.ftl index 0e3ea58..fde08aa 100644 --- a/src/main/resources/com/aventstack/extentreports/view/logger/logger-test.ftl +++ b/src/main/resources/com/aventstack/extentreports/view/logger/logger-test.ftl @@ -74,7 +74,7 @@ -
  • ${config.getValue("reportName")}
  • +
  • ${config.getConfig("reportName")}
  • 4.0
  • @@ -108,28 +108,28 @@ ${log.timestamp?string("MM.dd.yyyy HH:mm:ss")}  ${log.status?replace("ing","")}<#list log.status.toString()?replace("ing","")?length..5 as x>  ${spacer}[${test.name}] - <#if log.hasScreenCapture()>${log.screenCaptureContext.last.sourceWithIcon} + <#if LogService.logHasScreenCapture(log)>${log.screenCaptureContext.last.source} <#if log.details??>${log.details}<#if log.exceptionInfo??>threw an exception
    <#macro attributes test> - <#if test.hasCategory()> + <#if TestService.testHasCategory(test)> <#list test.categoryContext.all as category> ${category.name} - <#if test.hasAuthor()> + <#if TestService.testHasCategory(test)> <#list test.authorContext.all as author> ${author.name} - <#if test.hasDevice()> + <#if TestService.testHasCategory(test)> <#list test.deviceContext.all as device> ${device.name} @@ -159,10 +159,10 @@ - <#assign p="https://cdn.rawgit.com/extent-framework/extent-github-cdn/d74480e/logger/js/"> - <#if offline=="true"><#assign p=config.getValue("offlineDirectory")> + <#assign p="https://cdn.jsdelivr.net/gh/extent-framework/extent-github-cdn@832f979664f9d68bf618db3ac87498ac6c1a6390/logger/js/"> + <#if offline=="true"><#assign p=config.getConfig("offlineDirectory")> - <#if config.containsKey("scripts") && config.getValue("scripts")?has_content> + <#if config.containsConfig("scripts") && config.getConfig("scripts")?has_content> <#include "../commons/commons-inject-js.ftl"> diff --git a/src/main/resources/com/aventstack/extentreports/view/logger/partials/logger-head.ftl b/src/main/resources/com/aventstack/extentreports/view/logger/partials/logger-head.ftl index 703b0a6..84ae5e0 100644 --- a/src/main/resources/com/aventstack/extentreports/view/logger/partials/logger-head.ftl +++ b/src/main/resources/com/aventstack/extentreports/view/logger/partials/logger-head.ftl @@ -1,6 +1,6 @@ - - ${config.getValue("documentTitle")} + + ${config.getConfig("documentTitle")} @@ -9,13 +9,13 @@ <#if offline=="true"> - - + + <#else> - + - <#if config.containsKey("styles")> + <#if config.containsConfig("styles")> <#include "../../commons/commons-inject-css.ftl"> diff --git a/src/main/resources/com/aventstack/extentreports/view/logger/partials/logger-nav-right-items.ftl b/src/main/resources/com/aventstack/extentreports/view/logger/partials/logger-nav-right-items.ftl index 7b08467..7e0a331 100644 --- a/src/main/resources/com/aventstack/extentreports/view/logger/partials/logger-nav-right-items.ftl +++ b/src/main/resources/com/aventstack/extentreports/view/logger/partials/logger-nav-right-items.ftl @@ -1,3 +1,3 @@ -
  • ${config.getValue("reportName")}
  • +
  • ${config.getConfig("reportName")}
  • ${report.startTime?datetime?string["${timeStampFormat}"]}
  • 4.0
  • diff --git a/src/main/resources/com/aventstack/extentreports/view/logger/partials/logger-nav.ftl b/src/main/resources/com/aventstack/extentreports/view/logger/partials/logger-nav.ftl index 35223ba..dc1619f 100644 --- a/src/main/resources/com/aventstack/extentreports/view/logger/partials/logger-nav.ftl +++ b/src/main/resources/com/aventstack/extentreports/view/logger/partials/logger-nav.ftl @@ -37,7 +37,7 @@ - <#if config.getValue("enableDashboard")=="true"> + <#if config.getConfig("enableDashboard")=="true">
  • diff --git a/src/main/resources/com/aventstack/extentreports/view/spark/dashboard.ftl b/src/main/resources/com/aventstack/extentreports/view/spark/dashboard.ftl index c831d74..48f9a32 100644 --- a/src/main/resources/com/aventstack/extentreports/view/spark/dashboard.ftl +++ b/src/main/resources/com/aventstack/extentreports/view/spark/dashboard.ftl @@ -1,37 +1,5 @@ <#include "../commons/commons-variables.ftl"> -<#assign systemAttributeContext=report.getSystemAttributeContext().getSystemAttributeList()> -<#assign authorContext=report.getAuthorContextInfo().getTestAttributeTestContextList()> -<#assign categoryContext=report.getCategoryContextInfo().getTestAttributeTestContextList()> -<#assign deviceContext=report.getDeviceContextInfo().getTestAttributeTestContextList()> -<#assign exceptionContext=report.getExceptionContextInfo().getExceptionTestContextList()> -<#assign config=report.getConfigContext()> -<#assign timeStampFormat = config.getValue('timeStampFormat')> - -<#assign boxsize='col-md-12'> -<#if report.reportStatusStats.childCount!=0> - <#assign boxsize='col-sm-12 col-md-6'> - -<#if (report.analysisStrategy=="BDD") || (report.reportStatusStats.childCount != 0 && report.reportStatusStats.grandChildCount != 0)> - <#assign boxsize='col-sm-12 col-md-4'> - - -<#assign chartWidth="115" chartHeight="90" chartBoxHeight="94"> - -<#assign reportType="" parentHeading="Tests" childHeading="Steps" grandChildHeading="" size=2> -<#if report.analysisStrategy=="SUITE"> - <#assign parentHeading="Suite" childHeading="Tests" grandChildHeading="Tests" size=2> - <#if report.reportStatusStats.grandChildCount!=0> - <#assign childHeading="Classes" grandChildHeading="Tests" size=3> - - -<#if report.analysisStrategy=="BDD"> - <#assign reportType="bdd" parentHeading="Features" childHeading="Scenarios" grandChildHeading="Steps" size=3> - -<#if report.analysisStrategy=="CLASS"> - <#assign parentHeading="Class" childHeading="Methods" grandChildHeading="" size=2> - - <#include "partials/head.ftl"> @@ -42,509 +10,11 @@ <#include "partials/sidenav.ftl">
    -
    -
    -
    -
    -
    -
    ${parentHeading}
    -
    -
    -
    - -
    -
    - -
    -
    - <#if report.reportStatusStats.childCount != 0> -
    -
    -
    -
    ${childHeading}
    -
    -
    -
    - -
    -
    - -
    -
    - - <#if report.reportStatusStats.grandChildCount != 0> -
    -
    -
    -
    ${grandChildHeading}
    -
    -
    -
    - -
    -
    - -
    -
    - -
    -
    -
    -
    -
    -
    -
    -

    ${parentHeading}

    -

    ${report.reportStatusStats.parentCount}

    - - - ${report.reportStatusStats.parentPercentagePass?string("#.00")}% - -
    -
    - -
    -
    -
    -
    -
    - <#if report.reportStatusStats.childCount != 0> -
    -
    -
    -
    -
    -

    ${childHeading}

    -

    ${report.reportStatusStats.childCount}

    - - - ${report.reportStatusStats.childPercentagePass?string("#.00")}% - -
    -
    - -
    -
    -
    -
    -
    - -
    -
    -
    -
    -
    -

    Start

    -
    ${report.startTime?datetime?string["${timeStampFormat}"]}
    - -
    -
    - -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -

    Duration

    -
    ${report.longRunDuration}
    - -
    -
    - -
    -
    -
    -
    -
    -
    - <#if config.getValue("enableTimeline")=='true'> -
    -
    -
    -
    -
    Timeline
    -
    -
    -
    - -
    -
    -
    -
    -
    - -
    - <#if (authorContext?? && authorContext?size != 0)> -
    -
    -
    -
    Author
    -
    -
    - - - - - - - - - - - - <#list authorContext as author> - - - - - - - - - -
    NamePassedFailedOthersPassed %
    ${author.name}${author.passed}${author.failed}${author.others} - <#if author.size()!=0> - ${(author.passed/author.size())*100}% - <#else> - 0% - -
    -
    -
    -
    - - <#if (categoryContext?? && categoryContext?size != 0)> -
    -
    -
    -
    Tags
    -
    -
    - - - - - - - - - - - - <#list report.categoryContextInfo.testAttributeTestContextList as category> - - - - - - - - - -
    NamePassedFailedOthersPassed %
    ${category.name}${category.passed}${category.failed}${category.others} - <#if category.size()!=0> - ${(category.passed/category.size())*100}% - <#else> - 0% - -
    -
    -
    -
    - - <#if (deviceContext?? && deviceContext?size != 0)> -
    -
    -
    -
    Device
    -
    -
    - - - - - - - - - - - - <#list deviceContext as device> - - - - - - - - - -
    NamePassedFailedOthersPassed %
    ${device.name}${device.passed}${device.failed}${device.others} - <#if device.size()!=0> - ${(device.passed/device.size())*100}% - <#else> - 0% - -
    -
    -
    -
    - - <#if systemAttributeContext?size != 0> -
    -
    -
    -
    Environment
    -
    -
    - - - - - - - - - <#list report.systemAttributeContext.systemAttributeList as sa> - <#if sa?? && sa.name?? && sa.value??> - - - - - - - -
    NameValue
    ${ sa.name }${ sa.value }
    -
    -
    -
    - -
    -
    + <#include "partials/dashboard.ftl">
    - - <#if config.getValue("enableTimeline")=='true'> - - <#include "partials/scripts.ftl"> - \ No newline at end of file diff --git a/src/main/resources/com/aventstack/extentreports/view/spark/exception.ftl b/src/main/resources/com/aventstack/extentreports/view/spark/exception.ftl index e58e9e6..7d5fb5c 100644 --- a/src/main/resources/com/aventstack/extentreports/view/spark/exception.ftl +++ b/src/main/resources/com/aventstack/extentreports/view/spark/exception.ftl @@ -3,95 +3,14 @@ <#include "partials/head.ftl"> - +
    <#include "partials/navbar.ftl"> <#include "partials/sidenav.ftl">
    -
    -
    - -
    -
      - <#list exceptionContext as context> -
    • -
      -
      -

      ${context.exceptionInfo.exceptionName}

      -

      ${context.testList?size} tests

      -
      -
      -
      -
      -

      ${context.exceptionInfo.exceptionName}

      -
      - - - - - - - - - - <#list context.testList as test> - - - - - - - -
      StatusTimestampTestName
      -
      - -
      -
      ${test.startTime?string[("HH:mm:ss a")]} - ${test.name} - <#if test.parent??> -
      - ${test.parent.name} -
      - -
      -
      -
    • - -
    -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    + <#include "partials/exception.ftl">
    diff --git a/src/main/resources/com/aventstack/extentreports/view/spark/macros/attributes.ftl b/src/main/resources/com/aventstack/extentreports/view/spark/macros/attributes.ftl index ee9411a..cd59bf0 100644 --- a/src/main/resources/com/aventstack/extentreports/view/spark/macros/attributes.ftl +++ b/src/main/resources/com/aventstack/extentreports/view/spark/macros/attributes.ftl @@ -1,15 +1,15 @@ <#macro attributes test> - <#if test.hasAuthor()> + <#if TestService.testHasAuthor(test)> <#list test.authorContext.all as author> ${author.name} - <#if test.hasCategory()> + <#if TestService.testHasCategory(test)> <#list test.categoryContext.all as category> ${category.name} - <#if test.hasDevice()> + <#if TestService.testHasDevice(test)> <#list test.deviceContext.all as device> ${device.name} diff --git a/src/main/resources/com/aventstack/extentreports/view/spark/macros/log.ftl b/src/main/resources/com/aventstack/extentreports/view/spark/macros/log.ftl index e69fe25..3b7e1e9 100644 --- a/src/main/resources/com/aventstack/extentreports/view/spark/macros/log.ftl +++ b/src/main/resources/com/aventstack/extentreports/view/spark/macros/log.ftl @@ -16,7 +16,7 @@ <#else> ${log.details} - <#if log.hasScreenCapture()> + <#if LogService.logHasScreenCapture(log)> ${log.screenCaptureContext.last.source} diff --git a/src/main/resources/com/aventstack/extentreports/view/spark/macros/recurse_nodes.ftl b/src/main/resources/com/aventstack/extentreports/view/spark/macros/recurse_nodes.ftl index 8fb5d9b..4e5f2be 100644 --- a/src/main/resources/com/aventstack/extentreports/view/spark/macros/recurse_nodes.ftl +++ b/src/main/resources/com/aventstack/extentreports/view/spark/macros/recurse_nodes.ftl @@ -1,29 +1,29 @@ <#include "log.ftl"> <#macro recurse_nodes test> -<#if test.hasChildren()> +<#if TestService.testHasChildren(test)>
    <#list test.nodeContext.all as node>
    - <#if node.hasLog()> + <#if TestService.testHasLog(node)> <@log test=node /> - <#if node.hasScreenCapture()> - ${node.screenCaptureList[0].source} - + <#list node.screenCaptureContext.all as sc> + ${sc.source} +
    - <#if node.hasChildren()> + <#if TestService.testHasChildren(node)> <@recurse_nodes test=node />
    diff --git a/src/main/resources/com/aventstack/extentreports/view/spark/partials/bdd-content.ftl b/src/main/resources/com/aventstack/extentreports/view/spark/partials/bdd-content.ftl index 48c9384..4c74b0e 100644 --- a/src/main/resources/com/aventstack/extentreports/view/spark/partials/bdd-content.ftl +++ b/src/main/resources/com/aventstack/extentreports/view/spark/partials/bdd-content.ftl @@ -1,32 +1,32 @@ <#macro stepdetails test> - <#if test.hasLog()> + <#if TestService.testHasLog(test)> <#list test.logContext.all as log> <#if log.exceptionInfo??> <#else>
    ${log.details}
    - <#if log.hasScreenCapture()> - ${log.screenCaptureContext.last.source} + <#if LogService.logHasScreenCapture(log)> +
    ${log.screenCaptureContext.last.source}
    -<#if test.hasChildren()> +<#if TestService.testHasChildren(test)>
    <#list test.nodeContext.all as node>
    - <#if node.hasChildren()> - <#if node.behaviorDrivenTypeName=="Scenario Outline"> + <#if TestService.testHasChildren(node)> + <#if node.bddType?? && node.behaviorDrivenTypeName=="Scenario Outline">
    <#list node.nodeContext.all as child>
    @@ -56,7 +56,7 @@
    <#list node.nodeContext.all as child> -
    +
    diff --git a/src/main/resources/com/aventstack/extentreports/view/spark/partials/dashboard.ftl b/src/main/resources/com/aventstack/extentreports/view/spark/partials/dashboard.ftl new file mode 100644 index 0000000..3bde40c --- /dev/null +++ b/src/main/resources/com/aventstack/extentreports/view/spark/partials/dashboard.ftl @@ -0,0 +1,385 @@ +
    +
    +
    +
    +
    +
    ${parentHeading}
    +
    +
    +
    + +
    +
    + +
    +
    + <#if report.reportStatusStats.childCount != 0> +
    +
    +
    +
    ${childHeading}
    +
    +
    +
    + +
    +
    + +
    +
    + + <#if report.reportStatusStats.grandChildCount != 0> +
    +
    +
    +
    ${grandChildHeading}
    +
    +
    +
    + +
    +
    + +
    +
    + + <#if report.reportStatusStats.eventsCount != 0 && displayEvents> +
    +
    +
    +
    Log events
    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    ${parentHeading}
    +

    ${report.reportStatusStats.parentCount}

    + + + ${report.reportStatusStats.parentPercentagePass?string("#.00")}% + +
    +
    + +
    +
    +
    +
    +
    + <#if report.reportStatusStats.childCount != 0> +
    +
    +
    +
    +
    +
    ${childHeading}
    +

    ${report.reportStatusStats.childCount}

    + + + ${report.reportStatusStats.childPercentagePass?string("#.00")}% + +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    Start
    +

    ${report.startTime?datetime?string["${timeStampFormat}"]}

    + +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    Duration
    +

    ${report.longRunDuration}

    + +
    +
    + +
    +
    +
    +
    +
    +
    + <#if config.getConfig("enableTimeline")=='true'> +
    +
    +
    +
    +
    Timeline
    +
    +
    +
    + +
    +
    +
    +
    +
    + +
    + <#if (authorContext?? && authorContext?size != 0)> +
    +
    +
    +
    Author
    +
    +
    + + + + + + + + + + + + <#list authorContext as author> + + + + + + + + + +
    NamePassedFailedOthersPassed %
    ${author.name}${author.passed}${author.failed}${author.others} + <#if author.size()!=0> + ${(author.passed/author.size())*100}% + <#else> + 0% + +
    +
    +
    +
    + + <#if (categoryContext?? && categoryContext?size != 0)> +
    +
    +
    +
    Tags
    +
    +
    + + + + + + + + + + + + <#list categoryContext as category> + + + + + + + + + +
    NamePassedFailedOthersPassed %
    ${category.name}${category.passed}${category.failed}${category.others} + <#if category.size()!=0> + ${(category.passed/category.size())*100}% + <#else> + 0% + +
    +
    +
    +
    + + <#if (deviceContext?? && deviceContext?size != 0)> +
    +
    +
    +
    Device
    +
    +
    + + + + + + + + + + + + <#list deviceContext as device> + + + + + + + + + +
    NamePassedFailedOthersPassed %
    ${device.name}${device.passed}${device.failed}${device.others} + <#if device.size()!=0> + ${(device.passed/device.size())*100}% + <#else> + 0% + +
    +
    +
    +
    + + <#if systemAttributeContext?size != 0> +
    +
    +
    +
    Environment
    +
    +
    + + + + + + + + + <#list report.systemAttributeContext.systemAttributeList as sa> + <#if sa?? && sa.name?? && sa.value??> + + + + + + + +
    NameValue
    ${ sa.name }${ sa.value }
    +
    +
    +
    + +
    +
    + +<#if config.getConfig("enableTimeline")=='true'> + + \ No newline at end of file diff --git a/src/main/resources/com/aventstack/extentreports/view/spark/partials/exception.ftl b/src/main/resources/com/aventstack/extentreports/view/spark/partials/exception.ftl new file mode 100644 index 0000000..3936249 --- /dev/null +++ b/src/main/resources/com/aventstack/extentreports/view/spark/partials/exception.ftl @@ -0,0 +1,82 @@ +
    +
    + +
    +
      + <#list exceptionContext as context> +
    • +
      +
      +

      ${context.exceptionInfo.exceptionName}

      +

      ${context.tests?size} tests

      +
      +
      +
      +
      +

      ${context.exceptionInfo.exceptionName}

      +
      + + + + + + + + + + <#list context.tests as test> + + + + + + + +
      StatusTimestampTestName
      +
      + +
      +
      ${test.startTime?string[("HH:mm:ss a")]} + ${test.name} + <#if test.parent??> +
      + ${test.parent.name} +
      + +
      +
      +
    • + +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    \ No newline at end of file diff --git a/src/main/resources/com/aventstack/extentreports/view/spark/partials/head.ftl b/src/main/resources/com/aventstack/extentreports/view/spark/partials/head.ftl index ccc1042..99ea49a 100644 --- a/src/main/resources/com/aventstack/extentreports/view/spark/partials/head.ftl +++ b/src/main/resources/com/aventstack/extentreports/view/spark/partials/head.ftl @@ -1,4 +1,4 @@ -<#assign resourceCDN=config.getValue('resourceCDN') cdnURI="cdn.rawgit.com/extent-framework/extent-github-cdn/" csscommit="24cb10e" jscommit="24cb10e" iconcommit="d74480e"> +<#assign resourceCDN=config.getConfig('resourceCDN') cdnURI="cdn.jsdelivr.net/gh/extent-framework/extent-github-cdn@" csscommit="b00a2d0486596e73dd7326beacf352c639623a0e" jscommit="b00a2d0486596e73dd7326beacf352c639623a0e" iconcommit="b00a2d0486596e73dd7326beacf352c639623a0e"> <#if resourceCDN=="extentreports"> <#assign cdnURI="extentreports.com/resx" csscommit="" jscommit="" iconcommit=""> @@ -6,10 +6,17 @@ - ${config.getValue("documentTitle")} - - - - + ${config.getConfig("documentTitle")} + <#if offline=="true"> + + + + + <#else> + + + + + <#include "../../commons/commons-inject-css.ftl"> \ No newline at end of file diff --git a/src/main/resources/com/aventstack/extentreports/view/spark/partials/navbar.ftl b/src/main/resources/com/aventstack/extentreports/view/spark/partials/navbar.ftl index 8c2acc2..e1a27cf 100644 --- a/src/main/resources/com/aventstack/extentreports/view/spark/partials/navbar.ftl +++ b/src/main/resources/com/aventstack/extentreports/view/spark/partials/navbar.ftl @@ -28,7 +28,7 @@
    \ No newline at end of file diff --git a/src/main/resources/com/aventstack/extentreports/view/spark/partials/standard-content.ftl b/src/main/resources/com/aventstack/extentreports/view/spark/partials/standard-content.ftl index 17f4146..0cbdf50 100644 --- a/src/main/resources/com/aventstack/extentreports/view/spark/partials/standard-content.ftl +++ b/src/main/resources/com/aventstack/extentreports/view/spark/partials/standard-content.ftl @@ -1,12 +1,12 @@ -<#if test.hasLog()> +<#if TestService.testHasLog(test)>
    <@log test=test />
    -<#if test.hasScreenCapture()> +<#if TestService.testHasScreenCapture(test)>
    -<#if test.hasChildren()> +<#if TestService.testHasChildren(test)>
    <@recurse_nodes test=test />
    diff --git a/src/main/resources/com/aventstack/extentreports/view/spark/partials/tag.ftl b/src/main/resources/com/aventstack/extentreports/view/spark/partials/tag.ftl new file mode 100644 index 0000000..3afb465 --- /dev/null +++ b/src/main/resources/com/aventstack/extentreports/view/spark/partials/tag.ftl @@ -0,0 +1,92 @@ +
    +
    + +
    +
      + <#list categoryContext as context> +
    • +
      +
      +

      ${context.name}

      +

      ${context.size()} tests

      + + <#if context.passed!=0>${context.passed} + <#if context.failed!=0>${context.failed} + <#if context.skipped!=0>${context.skipped} + <#if context.others!=0>${context.others} + +
      +
      +
      +
      +

      ${context.name}

      + <#if context.passed!=0>${context.passed} passed + <#if context.failed!=0>${context.failed} failed + <#if context.skipped!=0>${context.skipped} skipped + <#if context.others!=0>${context.others} others +
      + + + + + + + + + + <#list context.tests as test> + + + + + + + +
      StatusTimestampTestName
      +
      + +
      +
      ${test.startTime?string[("HH:mm:ss a")]} + ${test.name} + <#if test.parent??> +
      + ${test.parent.name} +
      + +
      +
      +
    • + +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    \ No newline at end of file diff --git a/src/main/resources/com/aventstack/extentreports/view/spark/partials/test.ftl b/src/main/resources/com/aventstack/extentreports/view/spark/partials/test.ftl new file mode 100644 index 0000000..2a543c2 --- /dev/null +++ b/src/main/resources/com/aventstack/extentreports/view/spark/partials/test.ftl @@ -0,0 +1,128 @@ +
    +
    +
    + +
      + + <#if authorContext?? && authorContext?size != 0> + + + <#if categoryContext?? && categoryContext?size != 0> + + + <#if deviceContext?? && deviceContext?size != 0> + + +
    +
    +
    +
      + <#list report.testList as test> +
    • +
      + +
      +
      +
      +

      ${test.name}

      +

      ${TestService.getRunDuration(test)}

      + ${test.startTime?string("HH:mm:ss a")} +
      +
      +
      +
      +
      +
      +
      ${test.name}
      + ${test.startTime?string("MM.dd.yyyy HH:mm:ss")} + ${test.endTime?string("MM.dd.yyyy HH:mm:ss")} + ${TestService.getRunDuration(test)} +
      + <#if TestService.testHasAttributes(test)> +
      + <@attributes test=test /> +
      + + <#if test.description??> +
      + ${test.description} +
      + +
      +
      + <#if !isbdd> + <#include "standard-content.ftl"> + <#else> + <#include "bdd-content.ftl"> + +
      +
    • + +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    \ No newline at end of file diff --git a/src/main/resources/com/aventstack/extentreports/view/spark/spark.spa.ftl b/src/main/resources/com/aventstack/extentreports/view/spark/spark.spa.ftl new file mode 100644 index 0000000..e690b83 --- /dev/null +++ b/src/main/resources/com/aventstack/extentreports/view/spark/spark.spa.ftl @@ -0,0 +1,42 @@ +<#include "../commons/commons-variables.ftl"> +<#include "../commons/commons-macros.ftl"> +<#include "macros/attributes.ftl"> +<#include "macros/log.ftl"> +<#include "macros/recurse_nodes.ftl"> + +<#assign isbdd=false pageClass=""> +<#if report.testList?? && report.testList?has_content && report.testList[0].isBehaviorDrivenType()> + <#assign pageClass="bdd-report" isbdd=true> + + + + +<#include "partials/head.ftl"> +<#if offline=="true"> + +<#else> + + + +
    +
    + <#include "partials/navbar.ftl"> + <#include "partials/sidenav.ftl"> +
    +
    + <#include "partials/test.ftl"> + <#if categoryContext?? && categoryContext?size != 0> + <#include "partials/tag.ftl"> + + <#if exceptionContext?? && exceptionContext?size != 0> + <#include "partials/exception.ftl"> + + + <#include "partials/dashboard.ftl"> +
    +
    +
    +
    + <#include "partials/scripts.ftl"> + + \ No newline at end of file diff --git a/src/main/resources/com/aventstack/extentreports/view/spark/tag.ftl b/src/main/resources/com/aventstack/extentreports/view/spark/tag.ftl index dc3d07e..f2b8812 100644 --- a/src/main/resources/com/aventstack/extentreports/view/spark/tag.ftl +++ b/src/main/resources/com/aventstack/extentreports/view/spark/tag.ftl @@ -3,103 +3,14 @@ <#include "partials/head.ftl"> - +
    <#include "partials/navbar.ftl"> <#include "partials/sidenav.ftl">
    -
    -
    - -
    -
      - <#list categoryContext as context> -
    • -
      -
      -

      ${context.name}

      -

      ${context.size()} tests

      - - <#if context.passed!=0>${context.passed} - <#if context.failed!=0>${context.failed} - <#if context.skipped!=0>${context.skipped} - -
      -
      -
      -
      -

      ${context.name}

      - <#if context.passed!=0>${context.passed} passed - <#if context.failed!=0>${context.failed} failed - <#if context.skipped!=0>${context.skipped} skipped -
      - - - - - - - - - - <#list context.testList as test> - - - - - - - -
      StatusTimestampTestName
      -
      - -
      -
      ${test.startTime?string[("HH:mm:ss a")]} - ${test.name} - <#if test.parent??> -
      - ${test.parent.name} -
      - -
      -
      -
    • - -
    -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    + <#include "partials/tag.ftl">
    diff --git a/src/main/resources/com/aventstack/extentreports/view/spark/test.ftl b/src/main/resources/com/aventstack/extentreports/view/spark/test.ftl index 510a085..6380060 100644 --- a/src/main/resources/com/aventstack/extentreports/view/spark/test.ftl +++ b/src/main/resources/com/aventstack/extentreports/view/spark/test.ftl @@ -12,142 +12,19 @@ <#include "partials/head.ftl"> - - +<#if offline=="true"> + +<#else> + + +
    <#include "partials/navbar.ftl"> <#include "partials/sidenav.ftl">
    -
    -
    -
    - -
      - - <#if authorContext?? && authorContext?size != 0> - - - <#if categoryContext?? && categoryContext?size != 0> - - - <#if deviceContext?? && deviceContext?size != 0> - - -
    -
    -
    -
      - <#list report.testList as test> -
    • -
      - -
      -
      -
      -

      ${test.name}

      -

      ${test.runDuration}

      - ${test.startTime?string("HH:mm:ss a")} -
      -
      -
      -
      -
      -
      -
      ${test.name}
      - ${test.startTime?string("MM.dd.yyyy HH:mm:ss")} - ${test.endTime?string("MM.dd.yyyy HH:mm:ss")} - ${test.runDuration} -
      - <#if test.hasAttributes()> -
      - <@attributes test=test /> -
      - - <#if test.description??> -
      - ${test.description} -
      - -
      -
      - <#if !isbdd> - <#include "partials/standard-content.ftl"> - <#else> - <#include "partials/bdd-content.ftl"> - -
      -
    • - -
    -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    + <#include "partials/test.ftl">
    diff --git a/src/main/resources/com/aventstack/extentreports/view/v3html/author-view/v3-html-author-view.ftl b/src/main/resources/com/aventstack/extentreports/view/v3html/author-view/v3-html-author-view.ftl index 1d7cce1..386671c 100644 --- a/src/main/resources/com/aventstack/extentreports/view/v3html/author-view/v3-html-author-view.ftl +++ b/src/main/resources/com/aventstack/extentreports/view/v3html/author-view/v3-html-author-view.ftl @@ -49,10 +49,10 @@ - <#list author.getTestList() as test> + <#list author.tests as test> ${ test.startTime?datetime?string["${timeStampFormat}"] } - ${ test.hierarchicalName } + ${ test.name } ${ test.status } diff --git a/src/main/resources/com/aventstack/extentreports/view/v3html/category-view/v3-html-category-view.ftl b/src/main/resources/com/aventstack/extentreports/view/v3html/category-view/v3-html-category-view.ftl index eae1e24..cb3a62c 100644 --- a/src/main/resources/com/aventstack/extentreports/view/v3html/category-view/v3-html-category-view.ftl +++ b/src/main/resources/com/aventstack/extentreports/view/v3html/category-view/v3-html-category-view.ftl @@ -49,10 +49,10 @@ - <#list category.getTestList() as test> + <#list category.tests as test> ${ test.startTime?datetime?string["${timeStampFormat}"] } - ${ test.hierarchicalName } + ${ test.name } ${ test.status } diff --git a/src/main/resources/com/aventstack/extentreports/view/v3html/dashboard-view/v3-html-dashboard-view.ftl b/src/main/resources/com/aventstack/extentreports/view/v3html/dashboard-view/v3-html-dashboard-view.ftl index 2eb1c8e..f995b83 100644 --- a/src/main/resources/com/aventstack/extentreports/view/v3html/dashboard-view/v3-html-dashboard-view.ftl +++ b/src/main/resources/com/aventstack/extentreports/view/v3html/dashboard-view/v3-html-dashboard-view.ftl @@ -73,7 +73,7 @@ Name Passed Failed - Others + Skipped Passed % <#list categoryContext as category> @@ -81,7 +81,7 @@ ${category.name} ${category.passed} ${category.failed} - ${category.others} + ${category.skipped} <#if category.size()!=0> ${(category.passed/category.size())*100}% diff --git a/src/main/resources/com/aventstack/extentreports/view/v3html/exception-view/v3-html-exception-view.ftl b/src/main/resources/com/aventstack/extentreports/view/v3html/exception-view/v3-html-exception-view.ftl index b5721e8..29b985d 100644 --- a/src/main/resources/com/aventstack/extentreports/view/v3html/exception-view/v3-html-exception-view.ftl +++ b/src/main/resources/com/aventstack/extentreports/view/v3html/exception-view/v3-html-exception-view.ftl @@ -21,7 +21,7 @@
  • ${ exception.exceptionInfo.getExceptionName() } - ${ exception.testList?size } + ${ exception.tests?size }
    @@ -34,14 +34,14 @@ - <#list exception.getTestList() as test> - <#list test.getExceptionInfoList() as testException> + <#list exception.tests as test> + <#list test.exceptionInfoContext.all as testException> <#if testException.getExceptionName() == exception.exceptionInfo.getExceptionName()> ${ test.startTime?datetime?string["${timeStampFormat}"] } - ${ test.hierarchicalName } + ${ test.name } - + diff --git a/src/main/resources/com/aventstack/extentreports/view/v3html/test-view/v3-html-bdd.ftl b/src/main/resources/com/aventstack/extentreports/view/v3html/test-view/v3-html-bdd.ftl index 160064c..c4fd719 100644 --- a/src/main/resources/com/aventstack/extentreports/view/v3html/test-view/v3-html-bdd.ftl +++ b/src/main/resources/com/aventstack/extentreports/view/v3html/test-view/v3-html-bdd.ftl @@ -8,20 +8,20 @@
    ${test.description}
    <#list test.nodeContext.all as node> -
    - <#if node.hasCategory()> +
    + <#if TestService.testHasCategory(node)>
    <#list node.categoryContext.all as category> ${category.name}
    - ${node.runDuration} + ${TestService.getRunDuration(node)}
    -
    ${MaterialIcon.getIcon(node.status)} ${node.getBehaviorDrivenType().getSimpleName()}: ${node.name}
    - <#if node.screenCaptureList?? && node.screenCaptureList?size != 0> +
    ${MaterialIcon.getIcon(node.status)} ${node.behaviorDrivenTypeName}: ${node.name}
    + <#if TestService.testHasScreenCapture(node)>
      - <#list node.screenCaptureList as sc> + <#list node.screenCaptureContext.all as sc>
    • panorama
    @@ -30,14 +30,14 @@ ${node.description}
    - <#if node.hasChildren()> + <#if TestService.testHasChildren(node)>
      <#list node.nodeContext.all as child> -
    • +
    • ${MaterialIcon.getIcon(child.status)}${child.name}
      - <#if child.screenCaptureList?? && child.screenCaptureList?size != 0> + <#if TestService.testHasScreenCapture(child)>
        - <#list child.screenCaptureList as sc> + <#list child.screenCaptureContext.all as sc>
      • panorama
      @@ -49,14 +49,14 @@
      ${log.details}
      - <#if child.hasChildren()> + <#if TestService.testHasChildren(child)>
        <#list child.nodeContext.all as gc> -
      • +
      • ${MaterialIcon.getIcon(gc.status)}${gc.name}
        - <#if gc.screenCaptureList?? && gc.screenCaptureList?size != 0> + <#if TestService.testHasScreenCapture(gc)>
          - <#list gc.screenCaptureList as sc> + <#list gc.screenCaptureContext.all as sc>
        • panorama
        diff --git a/src/main/resources/com/aventstack/extentreports/view/v3html/test-view/v3-html-standard.ftl b/src/main/resources/com/aventstack/extentreports/view/v3html/test-view/v3-html-standard.ftl index 518ebb1..7aa8bfd 100644 --- a/src/main/resources/com/aventstack/extentreports/view/v3html/test-view/v3-html-standard.ftl +++ b/src/main/resources/com/aventstack/extentreports/view/v3html/test-view/v3-html-standard.ftl @@ -1,28 +1,28 @@
        ${ test.startTime?datetime?string["${timeStampFormat}"] } ${ test.endTime?datetime?string["${timeStampFormat}"] } - ${ test.getRunDuration()?string } + ${ TestService.getRunDuration(test)?string }
        <#if test.description?? && test.description?has_content>
        ${ test.description}
        -<#if test.hasAuthor() || test.hasCategory()> +<#if TestService.testHasAttributes(test)>
        - <#if test.hasCategory()> + <#if TestService.testHasCategory(test)>
        <#list test.categoryContext.all as category> ${ category.name }
        - <#if test.hasAuthor()> + <#if TestService.testHasAuthor(test)>
        <#list test.authorContext.all as author> ${ author.name }
        - <#if test.hasDevice()> + <#if TestService.testHasDevice(test)>
        <#list test.deviceContext.all as device> ${ device.name } @@ -31,7 +31,7 @@
        -<#if test.hasLog()> +<#if TestService.testHasLog(test)>
        @@ -58,7 +58,7 @@ <#else> ${log.details} - <#if log.hasScreenCapture()>${log.screenCaptureContext.last.source} + <#if LogService.logHasScreenCapture(log)>${log.screenCaptureContext.last.source} @@ -66,18 +66,18 @@
        -<#if test.nodeContext?? && test.nodeContext.all?size != 0> +<#if TestService.testHasChildren(test)>
          <#macro recurse_nodes nodeList> <#list nodeList as node> - <#assign leaf=(node.hasChildren())?then('','leaf')> -
        • + <#assign leaf=(TestService.testHasChildren(node))?then('','leaf')> +
        • ${ node.name }
          ${ node.startTime?datetime?string["${timeStampFormat}"] } - · ${ node.runDuration } + · ${ TestService.getRunDuration(node) } ${ node.status } - <#if node.hasCategory()> + <#if TestService.testHasCategory(node)>
          <#list node.categoryContext.all as category> ${ category.name } @@ -89,13 +89,13 @@ <#if node.getStatus()=='pass' && disableToggleActionForPassedNode=='true'> <#assign displayContent=false> - <#if node.hasLog() && displayContent> + <#if TestService.testHasLog(node) && displayContent>
          - <#if node.hasLog()> + <#if TestService.testHasLog(node)> <#if node.description?? && node.description?has_content>
          ${ node.description}
          - <#if node.hasAuthor()> + <#if TestService.testHasAuthor(node)>
          <#list node.authorContext.all as author> ${ author.name } @@ -128,15 +128,15 @@ <#else> ${log.details} - <#if log.hasScreenCapture()>${log.screenCaptureContext.last.source} + <#if LogService.logHasScreenCapture(log)>${log.screenCaptureContext.last.source} - <#if node.screenCaptureList?? && node.screenCaptureList?size != 0> + <#if TestService.testHasScreenCapture(node)>
            - <#list node.screenCaptureList as sc> + <#list node.screenCaptureContext.all as sc>
          • ${ sc.source }
          @@ -145,7 +145,7 @@
          - <#if node.hasChildren()> + <#if TestService.testHasChildren(node)>
            <@recurse_nodes nodeList=node.nodeContext.all />
          diff --git a/src/main/resources/com/aventstack/extentreports/view/v3html/test-view/v3-html-test-view-charts.ftl b/src/main/resources/com/aventstack/extentreports/view/v3html/test-view/v3-html-test-view-charts.ftl index 882f23c..1b1fbed 100644 --- a/src/main/resources/com/aventstack/extentreports/view/v3html/test-view/v3-html-test-view-charts.ftl +++ b/src/main/resources/com/aventstack/extentreports/view/v3html/test-view/v3-html-test-view-charts.ftl @@ -18,7 +18,7 @@ ${ report.reportStatusStats.parentCountPass } ${parentLabel} passed
          - ${ report.reportStatusStats.parentCountFail + report.reportStatusStats.parentCountFatal } ${parentLabel} failed, ${ report.reportStatusStats.parentCountError + report.reportStatusStats.parentCountWarning + report.reportStatusStats.parentCountSkip } others + ${ report.reportStatusStats.parentCountFail + report.reportStatusStats.parentCountFatal } ${parentLabel} failed, ${ report.reportStatusStats.parentCountSkip } skipped
          @@ -33,7 +33,9 @@ ${ report.reportStatusStats.childCountPass } ${childLabel} passed
        - ${ report.reportStatusStats.childCountFail + report.reportStatusStats.childCountFatal } ${childLabel} failed, ${ report.reportStatusStats.childCountError + report.reportStatusStats.childCountWarning + report.reportStatusStats.childCountSkip + report.reportStatusStats.childCountInfo } others + ${ report.reportStatusStats.childCountFail + report.reportStatusStats.childCountFatal } ${childLabel} failed, + ${report.reportStatusStats.childCountSkip} skipped, + ${ report.reportStatusStats.childCountError + report.reportStatusStats.childCountWarning + report.reportStatusStats.childCountInfo } others
    @@ -49,7 +51,9 @@ ${ report.reportStatusStats.grandChildCountPass } ${grandChildLabel} passed
    - ${ report.reportStatusStats.grandChildCountFail + report.reportStatusStats.grandChildCountFatal } ${grandChildLabel} failed, ${ report.reportStatusStats.grandChildCountSkip + report.reportStatusStats.grandChildCountError + report.reportStatusStats.grandChildCountWarning + report.reportStatusStats.grandChildCountInfo } others + ${ report.reportStatusStats.grandChildCountFail + report.reportStatusStats.grandChildCountFatal } ${childLabel} failed, + ${report.reportStatusStats.grandChildCountSkip} skipped, + ${ report.reportStatusStats.grandChildCountError + report.reportStatusStats.grandChildCountWarning + report.reportStatusStats.grandChildCountInfo } others
    diff --git a/src/main/resources/com/aventstack/extentreports/view/v3html/test-view/v3-html-test-view.ftl b/src/main/resources/com/aventstack/extentreports/view/v3html/test-view/v3-html-test-view.ftl index 1244956..f3b7e3a 100644 --- a/src/main/resources/com/aventstack/extentreports/view/v3html/test-view/v3-html-test-view.ftl +++ b/src/main/resources/com/aventstack/extentreports/view/v3html/test-view/v3-html-test-view.ftl @@ -38,7 +38,7 @@