changeset 10766:cd2e46a780b0

Merge
author kcr
date Fri, 22 Dec 2017 05:25:44 -0800
parents efac496a39cc 14621a723393
children 5a3cc1b5bb22
files
diffstat 10 files changed, 266 insertions(+), 179 deletions(-) [+]
line wrap: on
line diff
--- a/modules/javafx.base/src/main/java/javafx/collections/ListChangeListener.java	Thu Dec 21 14:42:35 2017 -0800
+++ b/modules/javafx.base/src/main/java/javafx/collections/ListChangeListener.java	Fri Dec 22 05:25:44 2017 -0800
@@ -78,18 +78,17 @@
      *     public void onChanged(Change<Item> c) {
      *         while (c.next()) {
      *             if (c.wasPermutated()) {
-     *                     for (int i = c.getFrom(); i < c.getTo(); ++i) {
-     *                          //permutate
-     *                     }
-     *                 } else if (c.wasUpdated()) {
-     *                          //update item
-     *                 } else {
-     *                     for (Item remitem : c.getRemoved()) {
-     *                         remitem.remove(Outer.this);
-     *                     }
-     *                     for (Item additem : c.getAddedSubList()) {
-     *                         additem.add(Outer.this);
-     *                     }
+     *                 for (int i = c.getFrom(); i < c.getTo(); ++i) {
+     *                      //permutate
+     *                 }
+     *             } else if (c.wasUpdated()) {
+     *                      //update item
+     *             } else {
+     *                 for (Item remitem : c.getRemoved()) {
+     *                     remitem.remove(Outer.this);
+     *                 }
+     *                 for (Item additem : c.getAddedSubList()) {
+     *                     additem.add(Outer.this);
      *                 }
      *             }
      *         }
--- a/modules/javafx.controls/src/main/java/javafx/scene/control/TableView.java	Thu Dec 21 14:42:35 2017 -0800
+++ b/modules/javafx.controls/src/main/java/javafx/scene/control/TableView.java	Fri Dec 22 05:25:44 2017 -0800
@@ -116,11 +116,11 @@
  * <h2>Creating a TableView</h2>
  *
  * <p>
- * {@literal Creating a TableView is a multi-step process, and also depends on the
+ * Creating a TableView is a multi-step process, and also depends on the
  * underlying data model needing to be represented. For this example we'll use
- * an ObservableList<Person>, as it is the simplest way of showing data in a
- * TableView. The <code>Person</code> class will consist of a first
- * name and last name properties. That is:}
+ * an {@literal ObservableList<Person>}, as it is the simplest way of showing data in a
+ * TableView. The {@code Person} class will consist of a first
+ * name and last name properties. That is:
  *
  * <pre>
  * {@code
@@ -148,10 +148,9 @@
  * {@code
  * TableView<Person> table = new TableView<Person>();}</pre>
  *
- * {@literal
  * <p>With the basic table defined, we next focus on the data model. As mentioned,
- * for this example, we'll be using a ObservableList<Person>. We can immediately
- * set such a list directly in to the TableView, as such:}
+ * for this example, we'll be using a {@literal ObservableList<Person>}. We can immediately
+ * set such a list directly in to the TableView, as such:
  *
  * <pre>
  * {@code
@@ -207,7 +206,7 @@
  *         return p.getValue().firstNameProperty();
  *     }
  *  });
- * }}</pre>
+ * }</pre>
  *
  * <h3>TableView Selection / Focus APIs</h3>
  * <p>To track selection and focus, it is necessary to become familiar with the
--- a/modules/javafx.graphics/src/main/java/javafx/scene/Group.java	Thu Dec 21 14:42:35 2017 -0800
+++ b/modules/javafx.graphics/src/main/java/javafx/scene/Group.java	Fri Dec 22 05:25:44 2017 -0800
@@ -179,7 +179,7 @@
 
     /**
      * Group defines the preferred width as simply being the width of its layout bounds, which
-     * in turn is simply the sum of the positions and widths of all of its children. That is,
+     * in turn is simply the union of the layout bounds of all of its children. That is,
      * the preferred width is the one that it is at, because a Group cannot be resized.
      *
      * Note: as the layout bounds in autosize Group depend on the Group to be already laid-out,
@@ -199,7 +199,7 @@
 
     /**
      * Group defines the preferred height as simply being the height of its layout bounds, which
-     * in turn is simply the sum of the positions and heights of all of its children. That is,
+     * in turn is simply the union of the layout bounds of all of its children. That is,
      * the preferred height is the one that it is at, because a Group cannot be resized.
      *
      * Note: as the layout bounds in autosize Group depend on the Group to be already laid-out,
--- a/modules/javafx.graphics/src/main/java/javafx/scene/layout/RowConstraints.java	Thu Dec 21 14:42:35 2017 -0800
+++ b/modules/javafx.graphics/src/main/java/javafx/scene/layout/RowConstraints.java	Fri Dec 22 05:25:44 2017 -0800
@@ -49,15 +49,15 @@
  *         gridpane.getRowConstraints().add(row);
  *     }
  * }</pre>
- * Or, to create a GridPane where rows take 25%, 50%, 25% of its width:
+ * Or, to create a GridPane where rows take 25%, 50%, 25% of its height:
  * <pre>{@code
  *     GridPane gridpane = new GridPane();
  *     RowConstraints row1 = new RowConstraints();
- *     row1.setPercentWidth(25);
+ *     row1.setPercentHeight(25);
  *     RowConstraints row2 = new RowConstraints();
- *     row2.setPercentWidth(50);
+ *     row2.setPercentHeight(50);
  *     RowConstraints row3 = new RowConstraints();
- *     row3.setPercentWidth(25);
+ *     row3.setPercentHeight(25);
  *     gridpane.getRowConstraints().addAll(row1,row2,row3);
  * }</pre>
  *
--- a/modules/javafx.graphics/src/main/java/javafx/scene/paint/Stop.java	Thu Dec 21 14:42:35 2017 -0800
+++ b/modules/javafx.graphics/src/main/java/javafx/scene/paint/Stop.java	Fri Dec 22 05:25:44 2017 -0800
@@ -41,7 +41,7 @@
  * <pre>{@code
  * // object bounding box relative (proportional:true, default)
  * Stop[] stops = { new Stop(0, Color.WHITE), new Stop(1, Color.BLACK)};
- * LinearGradient lg = new LinearGradient(0, 0, 1, 0, true, CycleMethod.No_CYCLE, stops);
+ * LinearGradient lg = new LinearGradient(0, 0, 1, 0, true, CycleMethod.NO_CYCLE, stops);
  * Rectangle r = new Rectangle();
  * r.setFill(lg);
  * }</pre>
--- a/modules/javafx.web/src/main/java/com/sun/javafx/webkit/prism/WCPathImpl.java	Thu Dec 21 14:42:35 2017 -0800
+++ b/modules/javafx.web/src/main/java/com/sun/javafx/webkit/prism/WCPathImpl.java	Fri Dec 22 05:25:44 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -104,165 +104,60 @@
         path.append(arc, true);
     }
 
-    public void addArc(double x, double y, double r, double startAngle,
-                       double endAngle, boolean aclockwise)
+    public void addArc(double x, double y, double r, double sa,
+                       double ea, boolean aclockwise)
     {
+        // Use single precision float as native
+        final float TWO_PI = 2.0f * (float) Math.PI;
+        float startAngle = (float) sa;
+        float endAngle = (float) ea;
+
         if (log.isLoggable(Level.FINE)) {
-            log.log(Level.FINE, "WCPathImpl({0}).addArc({1},{2},{3},{4},{5},{6})",
+            log.log(Level.FINE, "WCPathImpl({0}).addArc(x={1},y={2},r={3},sa=|{4}|,ea=|{5}|,aclock={6})",
                     new Object[] {getID(), x, y, r, startAngle, endAngle, aclockwise});
         }
+
         hasCP = true;
 
+        float newEndAngle = endAngle;
+        // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-context-2d-arc
+        // If the anticlockwise argument is false and endAngle-startAngle is equal
+        // to or greater than 2pi, or,
+        // if the anticlockwise argument is true and startAngle-endAngle is equal to
+        // or greater than 2pi,
+        // then the arc is the whole circumference of this ellipse, and the point at
+        // startAngle along this circle's circumference, measured in radians clockwise
+        // from the ellipse's semi-major axis, acts as both the start point and the
+        // end point.
 
-        double eps = 0.001;
+        // below condition is already handled in normalizeAngles(), CanvasPath.cpp.
+        // if (!anticlockwise && end_angle - start_angle >= twoPiFloat) {
+        //   new_end_angle = start_angle + twoPiFloat;
+        // } else if (anticlockwise && start_angle - end_angle >= twoPiFloat) {
+        //   new_end_angle = start_angle - twoPiFloat;
+        // } else
 
-        if (!aclockwise) {
-            if (endAngle < 0.0) {
-                if (endAngle < -2.0*Math.PI - eps) {
-                    int eMult = (int) (-endAngle / (2*Math.PI)) ;
-                    endAngle += eMult*2.0*Math.PI;
-                }
+        // Otherwise, the arc is the path along the circumference of this ellipse
+        // from the start point to the end point, going anti-clockwise if the
+        // anticlockwise argument is true, and clockwise otherwise.
+        // Since the points are on the ellipse, as opposed to being simply angles
+        // from zero, the arc can never cover an angle greater than 2pi radians.
+        //
+        // NOTE: When startAngle = 0, endAngle = 2Pi and anticlockwise = true, the
+        // spec does not indicate clearly.
+        // We draw the entire circle, because some web sites use arc(x, y, r, 0,
+        // 2*Math.PI, true) to draw circle.
+        // We preserve backward-compatibility.
+        if (!aclockwise && startAngle > endAngle) {
+            newEndAngle = startAngle + (TWO_PI - ((startAngle - endAngle) % TWO_PI));
+        } else if (aclockwise && startAngle < endAngle) {
+            newEndAngle = startAngle - (TWO_PI - ((endAngle - startAngle) % TWO_PI));
+        }
 
-                endAngle += 2.0*Math.PI;
-            } else {
-                if (endAngle > 2.0*Math.PI + eps) {
-                    int eMult = (int) (endAngle / (2*Math.PI));
-                    endAngle -= eMult*2.0*Math.PI;
-                }
-            }
-
-            if (startAngle < 0.0) {
-                if (startAngle < -2.0*Math.PI - eps) {
-                    int sMult = (int) (-startAngle / (2*Math.PI));
-                    startAngle += sMult*2.0*Math.PI;
-                }
-
-                startAngle += 2.0*Math.PI;
-            } else {
-                if (startAngle > 2.0*Math.PI + eps) {
-                    int sMult = (int) (startAngle / (2*Math.PI));
-                    startAngle -= sMult*2.0*Math.PI;
-                }
-            }
-
-            double d = startAngle - endAngle;
-
-            if (startAngle < endAngle) {
-                d = Math.abs(d);
-            }
-
-            endAngle = (float) (2.0 * Math.PI - endAngle);
-
-            Shape arc = new Arc2D((float)(x - r), (float)(y - r),
-                                  (float)(2*r), (float)(2*r),
-                (float) ((endAngle * 180.0) / Math.PI),
-                (float) ((d * 180.0) / Math.PI),Arc2D.OPEN);
-
-            PathIterator pi = arc.getPathIterator(null);
-            List<Integer> segStack = new ArrayList<Integer>();
-            List<Float> valStack = new ArrayList<Float>();
-            float [] coords = new float[6];
-            while(!pi.isDone()) {
-                switch(pi.currentSegment(coords)) {
-                    case PathIterator.SEG_MOVETO:
-                        valStack.add(coords[1]);
-                        valStack.add(coords[0]);
-                        break;
-                    case PathIterator.SEG_QUADTO:
-                        throw new RuntimeException("Unexpected segment: " +
-                                                   "SEG_QUADTO");
-                    case PathIterator.SEG_CUBICTO:
-                        valStack.add(coords[1]);
-                        valStack.add(coords[0]);
-                        valStack.add(coords[3]);
-                        valStack.add(coords[2]);
-                        valStack.add(coords[5]);
-                        valStack.add(coords[4]);
-                        segStack.add(PathIterator.SEG_CUBICTO);
-                        break;
-                    case PathIterator.SEG_CLOSE:
-                        throw new RuntimeException("Unexpected segment: " +
-                                                   "SEG_CLOSE");
-                }
-
-                pi.next();
-            }
-
-            segStack.add(PathIterator.SEG_MOVETO);
-
-            Path2D invArc = new Path2D();
-            int segIndex = segStack.size();
-            int valIndex = valStack.size();
-            while (segIndex > 0) {
-                switch(segStack.get(--segIndex)) {
-                    case PathIterator.SEG_MOVETO:
-                        invArc.moveTo(valStack.get(--valIndex), valStack.get(--valIndex));
-                        break;
-                    case PathIterator.SEG_LINETO:
-                        invArc.lineTo(valStack.get(--valIndex), valStack.get(--valIndex));
-                        break;
-                    case PathIterator.SEG_QUADTO:
-                        invArc.quadTo(valStack.get(--valIndex), valStack.get(--valIndex),
-                                      valStack.get(--valIndex), valStack.get(--valIndex));
-                        break;
-                    case PathIterator.SEG_CUBICTO:
-                        invArc.curveTo(valStack.get(--valIndex), valStack.get(--valIndex),
-                                       valStack.get(--valIndex), valStack.get(--valIndex),
-                                       valStack.get(--valIndex), valStack.get(--valIndex));
-                        break;
-                }
-            }
-            path.append(invArc, true);
-        } else {
-
-            if (endAngle < 0.0) {
-                if (endAngle < -2.0*Math.PI - eps) {
-                    int eMult = (int) (-endAngle / (2*Math.PI));
-                    endAngle += eMult*2.0*Math.PI;
-                }
-
-                endAngle += 2.0*Math.PI;
-            } else {
-                if (endAngle > 2.0*Math.PI + eps) {
-                    int eMult = (int) (endAngle / (2*Math.PI));
-                    endAngle -= eMult*2.0*Math.PI;
-                }
-            }
-
-            if (startAngle < 0.0) {
-                if (startAngle < -2.0*Math.PI - eps) {
-                    int sMult = (int) (-startAngle / (2*Math.PI));
-                    startAngle += sMult*2.0*Math.PI;
-                }
-
-                startAngle += 2.0*Math.PI;
-            } else {
-                if (startAngle > 2.0*Math.PI + eps) {
-                    int sMult = (int) (startAngle / (2*Math.PI));
-                    startAngle -= sMult*2.0*Math.PI;
-                }
-            }
-
-            double d = startAngle - endAngle;
-
-            if (startAngle < endAngle) {
-                d += 2*Math.PI;
-                if (d < eps) {
-                    d += 2*Math.PI;
-                }
-            }
-
-            if (Math.abs(startAngle) > eps) {
-                startAngle = (float) (2.0 * Math.PI - startAngle);
-            }
-
-
-            path.append(new Arc2D((float)(x - r), (float)(y - r),
-                                  (float)(2*r), (float)(2*r),
-                                  (float)((startAngle*180.0f)/Math.PI),
-                                  (float)((d*180.0f)/Math.PI),
-                                  Arc2D.OPEN), true);
-        }
+        path.append(new Arc2D((float) (x - r), (float) (y - r),
+                              (float) (2 * r), (float) (2 * r),
+                              (float) Math.toDegrees(-startAngle),
+                              (float) Math.toDegrees(startAngle - newEndAngle), Arc2D.OPEN), true);
     }
 
     public boolean contains(int rule, double x, double y) {
--- a/modules/javafx.web/src/test/java/test/javafx/scene/web/CanvasTest.java	Thu Dec 21 14:42:35 2017 -0800
+++ b/modules/javafx.web/src/test/java/test/javafx/scene/web/CanvasTest.java	Fri Dec 22 05:25:44 2017 -0800
@@ -146,4 +146,24 @@
             }
         });
     }
+
+    // JDK-8191035
+    @Test public void testCanvasArc() {
+        final String htmlCanvasArc =
+                "<canvas id='canvas' width='600' height='300'></canvas> <script>" +
+                        "var context = document.getElementById('canvas').getContext('2d');" +
+                        "context.beginPath();" +
+                        "context.arc(300, 150, 75, -1.5707, 2.1362, false);" +
+                        "context.strokeStyle = 'red';" +
+                        "context.stroke();  </script>";
+
+        loadContent(htmlCanvasArc);
+        submit(() -> {
+            int redColor = 255;
+            assertEquals("Arc startAngle", redColor,
+                    (int) getEngine().executeScript("document.getElementById('canvas').getContext('2d').getImageData(260,213,1,1).data[0]"));
+            assertEquals("Arc endAngle", redColor,
+                    (int) getEngine().executeScript("document.getElementById('canvas').getContext('2d').getImageData(300,75,1,1).data[0]"));
+        });
+    }
 }
--- a/modules/jdk.packager/src/main/java/jdk/packager/internal/legacy/Module.java	Thu Dec 21 14:42:35 2017 -0800
+++ b/modules/jdk.packager/src/main/java/jdk/packager/internal/legacy/Module.java	Fri Dec 22 05:25:44 2017 -0800
@@ -51,7 +51,9 @@
 
     public String getModuleName() {
         File file = new File(getFileName());
-        return getFileWithoutExtension(file.getName());
+        // do not try to remove extension for directories
+        return moduleType == ModuleType.ExplodedModule ?
+                file.getName() : getFileWithoutExtension(file.getName());
     }
 
     public String getFileName() {
--- a/modules/jdk.packager/src/main/resources/com/sun/javafx/tools/packager/Bundle.properties	Thu Dec 21 14:42:35 2017 -0800
+++ b/modules/jdk.packager/src/main/resources/com/sun/javafx/tools/packager/Bundle.properties	Fri Dec 22 05:25:44 2017 -0800
@@ -83,6 +83,8 @@
 \          limit the universe of observable modules\n\
 \  --strip-native-commands <true/false>\n\
 \          include or exclude the native commands\n\
+\  -singleton\n\
+\          prevents multiple instances of the application from launching.\n\
 \  -title <title>\n\
 \          title of the application.\n\
 \  -vendor <vendor>\n\
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/system/src/test/java/test/robot/javafx/scene/JDK8183100Test.java	Fri Dec 22 05:25:44 2017 -0800
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package test.robot.javafx.scene;
+
+import test.com.sun.javafx.scene.control.infrastructure.KeyEventFirer;
+import test.com.sun.javafx.scene.control.infrastructure.KeyModifier;
+import javafx.application.Platform;
+import javafx.scene.Scene;
+import javafx.scene.control.Button;
+import javafx.scene.control.ToggleButton;
+import javafx.scene.control.ToggleGroup;
+import javafx.scene.input.KeyCode;
+import javafx.scene.input.KeyCodeCombination;
+import javafx.scene.layout.Pane;
+import javafx.scene.layout.Priority;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.VBox;
+import javafx.scene.layout.StackPane;
+import javafx.scene.paint.Color;
+import javafx.stage.Stage;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.Test;
+import test.robot.testharness.VisualTestBase;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * A visual styling regression has been fixed under JDK8183100.
+ * This test validates it.
+ */
+public class JDK8183100Test extends VisualTestBase {
+
+    private Stage testStage;
+    private Scene testScene;
+    private int count = 0;
+    private final double TOLERANCE = 0.07;
+    static List<TabContents> TAB_CONTENTS = new ArrayList<>();
+
+    class TabContents extends StackPane {
+        public TabContents() {
+            // It is important that this node has some styling,
+            // either via setStyle() or getStyleClass().add().
+            setStyle("-fx-background-color: blue");
+
+            Platform.runLater(() -> {
+                TAB_CONTENTS.add(this);
+                TAB_CONTENTS.forEach(TabContents::fillWithFreshYellowPane);
+            });
+        }
+
+        void fillWithFreshYellowPane() {
+            Pane yellowPane = new Pane();
+            yellowPane.setStyle("-fx-background-color: yellow");
+            getChildren().setAll(yellowPane);
+        }
+    }
+
+    @Test(timeout=15000)
+    public void stackPaneColorTest() {
+        final int WIDTH = 200;
+        final int HEIGHT = 100;
+
+        // Top half of the app: Horizontal navigation bar above the application.
+        Button addTabButton = new Button("Add tab");
+        HBox tabBar = new HBox(addTabButton);
+
+        // Bottom half of the app: The actual tab contents.
+        StackPane container = new StackPane();
+
+        // It is important that this node has some styling,
+        // either via setStyle() or getStyleClass().add().
+        container.setStyle("-fx-background-color: red");
+        VBox.setVgrow(container, Priority.ALWAYS);
+
+        VBox root = new VBox(tabBar, container);
+
+        ToggleGroup group = new ToggleGroup();
+
+        addTabButton.setOnAction(unused -> {
+            ToggleButton tb = new ToggleButton("Tab "+count);
+            count++;
+
+            TabContents contents = new TabContents();
+            runAndWait(() -> {
+                tb.setToggleGroup(group);
+                tb.setSelected(true);
+                tabBar.getChildren().add(tb);
+
+                // Immediately select the new tab...
+                container.getChildren().setAll(contents);
+            });
+
+            // Add key accelerator for 'Tab 0' button only
+            if (count == 1) {
+                tb.getScene().getAccelerators().put(
+                    new KeyCodeCombination(KeyCode.DIGIT0, KeyCodeCombination.CONTROL_DOWN),
+                    new Runnable() {
+                        @Override public void run() {
+                           tb.fire();
+                        }
+                    });
+            }
+
+            tb.setOnAction(actionEvent -> {
+                container.getChildren().setAll(contents);
+            });
+        });
+
+        runAndWait(() -> {
+            testStage = getStage();
+            testScene = new Scene(root, WIDTH, HEIGHT);
+
+            testStage.setScene(testScene);
+
+            // Add key accelerator for addTabButton
+            addTabButton.getScene().getAccelerators().put(
+            new KeyCodeCombination(KeyCode.A, KeyCodeCombination.CONTROL_DOWN),
+            new Runnable() {
+                @Override public void run() {
+                    addTabButton.fire();
+                }
+            });
+
+            testStage.show();
+        });
+
+        waitFirstFrame();
+
+        KeyEventFirer keyboard = new KeyEventFirer(testScene);
+
+        // Add 3 buttons by pressing Ctrl+A on keyboard
+        for (int i = 0; i < 3; i++) {
+            keyboard.doKeyPress(KeyCode.A, KeyModifier.CTRL);
+            assertEquals(i+1, count);
+        }
+
+        // Select Tab0 by pressing Ctrl+0
+        runAndWait(() -> {
+            keyboard.doKeyPress(KeyCode.DIGIT0, KeyModifier.CTRL);
+        });
+
+        runAndWait(() -> {
+            Color color = getColor(testScene, 100, 50); // center pixel of scene
+            assertColorEquals(Color.YELLOW, color, TOLERANCE);
+        });
+    }
+}