/** Ensures that ExternalJavaActionCalls with unchecked precondition are not displayed. */ public void testPopupMenuWithExternalJavaActionCallAndFalsePrecondition() { // When getting the contextual menu of // "Employee" Class -- "wage" attribute // The precondition value is false and the Java Action Call action // should // not be displayed boolean foundContextMenu = true; final SWTBotTreeItem node = editor .bot() .tree() .getTreeItem(TREE_ITEM_WITH_JAVA_ACTION_CONTAINER_NAME) .expand() .getNode(TREE_ITEM_WITH_JAVA_ACTION_NAME) .select(); // The test must be passed in the exception, so we deactivated the catch // of // "error log" view setErrorCatchActive(false); try { node.contextMenu(JAVA_ACTION_CALL_NAME); } catch (TimeoutException e) { foundContextMenu = false; } assertFalse( "Java Action Call " + JAVA_ACTION_CALL_NAME + " should not be displayed on TreeITem " + TREE_ITEM_WITH_JAVA_ACTION_NAME, foundContextMenu); setErrorCatchActive(true); }
@Test public void translationEditorFilterControls() throws Exception { SWTBotCheckBox emptyChkBox = editor.bot().checkBox(EMPTY_TRANSLATIONS); assertTrue("Filter empty translations is default checked", emptyChkBox.isChecked()); SWTBotCheckBox depPrjTrans = editor.bot().checkBox(DEPPROJ_TRANSLATIONS); assertTrue("Filter dependent project translations is default checked", depPrjTrans.isChecked()); }
@Test public void shouldExchangeCompareEditorSidesBetweenIncomingAndOutgoingChanges() throws Exception { // given resetRepositoryToCreateInitialTag(); makeChangesAndCommit(PROJ1); // compare HEAD against tag launchSynchronization(HEAD, INITIAL_TAG, false); SWTBotEditor compEditor = getCompareEditorForFileInWorspaceModel(FILE1); SWTBot outgoingCompare = compEditor.bot(); // save left value from compare editor String outgoingLeft = outgoingCompare.styledText(0).getText(); // save right value from compare editor String outgoingRight = outgoingCompare.styledText(1).getText(); compEditor.close(); // when // compare tag against HEAD launchSynchronization(INITIAL_TAG, HEAD, false); // then SWTBot incomingComp = getCompareEditorForFileInWorspaceModel(FILE1).bot(); String incomingLeft = incomingComp.styledText(0).getText(); String incomingRight = incomingComp.styledText(1).getText(); // right side from compare editor should be equal with left assertThat(outgoingLeft, equalTo(incomingRight)); // left side from compare editor should be equal with right assertThat(outgoingRight, equalTo(incomingLeft)); }
@Test public void testCreateNewDawnEditorSetName() throws Exception { getBot().menu("File").menu("New").menu("Other...").click(); SWTBotShell shell = getBot().shell("New"); shell.activate(); getBot().tree().expandNode("Dawn Examples").select(DawnAcoreTestUtil.CREATION_WIZARD_NAME_EMF); getBot().button("Next >").click(); shell = getBot().shell("New"); shell.activate(); SWTBotText fileSemanticNameLabel = getBot().textWithLabel(resourceFieldLabel); fileSemanticNameLabel.setText("test.acore"); assertEquals("test.acore", fileSemanticNameLabel.getText()); getBot().button("Next >").click(); SWTBotCombo comboBox = getBot().comboBox(0); // bot.ccomboBox(0); comboBox.setFocus(); comboBox.setSelection("ACore Root"); getBot().button("Finish").click(); SWTBotEditor editor = getBot().editorByTitle("test.acore"); assertNotNull(editor); editor.close(); }
@Test public void testCreateNewDawnAcoreEditor() throws Exception { getBot().menu("File").menu("New").menu("Other...").click(); SWTBotShell shell = getBot().shell("New"); shell.activate(); getBot().tree().expandNode("Dawn Examples").select(DawnAcoreTestUtil.CREATION_WIZARD_NAME_EMF); getBot().button("Next >").click(); getBot().button("Next >").click(); shell = getBot().shell("New"); shell.activate(); SWTBotCombo comboBox = getBot().comboBox(0); // bot.ccomboBox(0); comboBox.setFocus(); comboBox.setSelection("ACore Root"); getBot().button("Finish").click(); sleep(500); SWTBotEditor editor = getBot().editorByTitle("default.acore"); assertNotNull(editor); editor.close(); { assertEquals(true, resourceExists("/default.acore")); } }
@Test @Ignore // workspace model dosn't show non-workspace files ... yet ;) public void shouldShowCompareEditorForNonWorkspaceFileFromSynchronization() throws Exception { // given String content = "file content"; String name = "non-workspace.txt"; File root = new File(getTestDirectory(), REPO1); File nonWorkspace = new File(root, name); BufferedWriter writer = new BufferedWriter(new FileWriter(nonWorkspace)); writer.append(content); writer.close(); // when launchSynchronization(INITIAL_TAG, HEAD, true); // then SWTBotTree syncViewTree = bot.viewByTitle("Synchronize").bot().tree(); SWTBotTreeItem workingTree = syncViewTree.expandNode(PROJ1); assertEquals(1, syncViewTree.getAllItems().length); workingTree.expand().getNode(name).doubleClick(); SWTBotEditor editor = bot.editorByTitle(name); editor.setFocus(); // the WidgetNotFoundException will be thrown when widget with given content cannot be not found SWTBotStyledText left = editor.bot().styledText(content); SWTBotStyledText right = editor.bot().styledText(""); // to be complete sure assert that both sides are not the same assertNotSame(left, right); }
public static void movepositions( final SWTGefBot bot, SWTBotGefEditor gmfEditor, final String sourcelane, final String destlane, final String element, final int j, final int i) { final SWTBotEditor botEditor = bot.activeEditor(); gmfEditor = bot.gefEditor(botEditor.getTitle()); final SWTBotGefEditPart lane2 = gmfEditor.getEditPart(sourcelane); lane2.parent().select().resize(PositionConstants.NORTH, 100, 150); // compute target destination final SWTBotGefEditPart lane3 = gmfEditor.getEditPart(destlane); // move step2 to lane2 final SWTBotGefEditPart ele = gmfEditor.getEditPart(element).parent(); ele.select(); // move step2 to lane2 SWTBotGefEditPart step = gmfEditor.getEditPart(element).parent(); step.select(); IFigure figure = ((GraphicalEditPart) step.part()).getFigure(); final Rectangle dest = figure.getBounds().getCopy(); figure.translateToAbsolute(dest); gmfEditor.drag(step, dest.x + j, dest.y + i); step = gmfEditor.getEditPart(element).parent(); step.select(); figure = ((GraphicalEditPart) step.part()).getFigure(); final Rectangle targetdest = figure.getBounds().getCopy(); figure.translateToAbsolute(targetdest); Assert.assertTrue("Move has failed", !targetdest.equals(dest)); bot.waitUntil( new ICondition() { @Override public boolean test() throws Exception { return getPartRecursively(lane3.parent(), element) != null; } @Override public void init(final SWTBot bot) {} @Override public String getFailureMessage() { System.out.println(element + "is not in sourcelane"); return "element is not in sourcelane (unable to move the step)"; } }); }
/** @throws Exception */ private void checkTab(String tabName) throws Exception { SWTBotCTabItem tabItem = editor.bot().cTabItem(tabName); tabItem.setFocus(); SWTBotTable table = editor.bot().table(); SWTBotTableColumn tCol = table.header("Translation of"); tCol.setFocus(); tCol = table.header("Kind"); tCol.setFocus(); SWTBotButton bttn = editor.bot().button("Edit Source Model"); assertFalse(bttn.isEnabled()); }
private void addNewCreationToolToVSM() { final SWTBotEditor activeEditor = bot.activeEditor(); activeEditor.setFocus(); Group group = syncExec( new Result<Group>() { @Override public Group run() { SWTBotTree tree = activeEditor.bot().tree(); SWTBotTreeItem[] allItems = tree.getAllItems(); Resource vsmResource = (Resource) allItems[0].widget.getData(); return (Group) vsmResource.getContents().get(0); } }); final TableDescription tableDesc = (TableDescription) group.getOwnedViewpoints().get(0).getOwnedRepresentations().get(0); // Add Mock Creation Line tool final CreateLineTool tool = DescriptionFactory.eINSTANCE.createCreateLineTool(); tool.setMapping(tableDesc.getAllLineMappings().get(0)); tool.setName(CREATION_TOOL); // Add change context ChangeContext changeContext = ToolFactory.eINSTANCE.createChangeContext(); changeContext.setBrowseExpression("var:container"); tool.setFirstModelOperation(changeContext); // A complete tool is not needed : it must contains a model operation. EditingDomain ed = AdapterFactoryEditingDomain.getEditingDomainFor(tableDesc); ed.getCommandStack() .execute( new AbstractCommand() { @Override public void execute() { tableDesc.getOwnedCreateLine().add(tool); } @Override public boolean canExecute() { return true; } @Override public void redo() {} }); assertTrue("Tool creation should have modified the VSM.", activeEditor.isDirty()); activeEditor.save(); }
/** Ensures that PopupMenu is not created if its precondition is not checked. */ public void testPopupMenuWithFalsePrecondition() { // When getting the contextual menu of // "NamedEntity" Class -- "wrongFeature" attribute // The precondition value is false and the Pop-up Menu should // not be displayed boolean foundContextMenu = true; SWTBotTreeItem unaplicableNode = editor .bot() .tree() .getTreeItem(TREE_ITEM_WITH_UNAPLICABLE_POPUP_CONTAINER_NAME) .expand() .getNode(TREE_ITEM_WITH_UNAPLICABLE_POPUP_NAME); try { unaplicableNode.contextMenu(POP_UP_MENU_NAME); } catch (TimeoutException e) { foundContextMenu = false; } assertFalse( "Pop-up Menu " + POP_UP_MENU_NAME + " should not be displayed on TreeITem " + TREE_ITEM_WITH_UNAPLICABLE_POPUP_NAME, foundContextMenu); }
/** * Create a new Form and save it * * @param bot * @param gmfEditor * @param nameOfStepOnwhichCreateTheForm * @return */ public static SWTBotEditor createFormWhenOnAProcessWithStep1( final SWTGefBot bot, final SWTBotGefEditor gmfEditor, final String nameOfStepOnwhichCreateTheForm) { final SWTBotGefEditPart part = gmfEditor.getEditPart(nameOfStepOnwhichCreateTheForm); if (part != null) { System.out.println("wow part is not null" + part.toString()); } else { System.out.println("part is null"); } try { System.out.println( "tosting is:" + part.toString() + "source size is:" + part.sourceConnections().size() + "target size is:" + part.targetConnections().size() + "parent" + part.parent().toString()); } catch (final Exception e) { System.out.println("Exception is:" + e.getMessage()); } part.click(); // part.focus(); bot.viewById("org.bonitasoft.studio.views.properties.application").show(); bot.viewById("org.bonitasoft.studio.views.properties.application").setFocus(); SWTBotTestUtil.selectTabbedPropertyView(bot, "Pageflow"); final SWTBotView properties = bot.viewById(SWTBotTestUtil.VIEWS_PROPERTIES_APPLICATION); properties.bot().button("Add...").click(); bot.waitUntil(Conditions.shellIsActive("Add form...")); bot.button(IDialogConstants.NEXT_LABEL).click(); bot.button("Unselect all").click(); bot.button(IDialogConstants.FINISH_LABEL).click(); final SWTBotEditor activeEditor = bot.activeEditor(); activeEditor.save(); return activeEditor; }
@Test public void testConditionExpressions() throws IOException, InterruptedException { SWTBotTestUtil.importProcessWIthPathFromClass( bot, "TestDecisionTable-1.0.bos", SWTBotTestUtil.IMPORTER_TITLE_BONITA, "TestDecisionTable", getClass(), false); final SWTBotEditor botEditor = bot.activeEditor(); final SWTBotGefEditor gmfEditor = bot.gefEditor(botEditor.getTitle()); gmfEditor.getEditPart("sf1").click(); bot.viewById(SWTBotTestUtil.VIEWS_PROPERTIES_PROCESS_GENERAL).show(); SWTBotTestUtil.selectTabbedPropertyView(bot, "General"); bot.radio(useDecisionTable).click(); bot.waitUntil(Conditions.widgetIsEnabled(bot.button(editDecisionTable))); bot.button(editDecisionTable).click(); bot.waitUntil(Conditions.shellIsActive(Messages.wizardPageTitle)); bot.waitUntil(Conditions.widgetIsEnabled(bot.link("<A>" + Messages.addRow + "</A>"))); bot.link("<A>" + Messages.addRow + "</A>").click(Messages.addRow); bot.waitUntil(Conditions.widgetIsEnabled(bot.link("<A>" + Messages.addCondition + "</A>"))); addTrueCondition(0, "true"); addTrueCondition(1, "1==2"); addFalseCondition(2, "sdkgjskrg"); changeCondition(2, "myBoolean"); testUpdateLineButtonEnabled(); bot.toolbarButtonWithId(ExpressionViewer.SWTBOT_ID_ERASEBUTTON, 0).click(); bot.sleep(1000); testUpdateLineButtonNotEnabled(); changeCondition(0, "myText==\"\""); testUpdateLineButtonEnabled(); bot.button(Messages.updateLine).click(); bot.button(IDialogConstants.FINISH_LABEL); SWTBotTestUtil.waitUntilBonitaBPmShellIsActive(bot); bot.saveAllEditors(); }
@Test public void testCreateNewDawnDiagramTypeFolder() throws Exception { { CDOSession session = openSession(); ResourceSet resourceSet = new ResourceSetImpl(); CDOTransaction transaction = session.openTransaction(resourceSet); final URI uri = URI.createURI("cdo:/folder/dummy"); resourceSet.createResource(uri); transaction.commit(); } getBot().menu("File").menu("New").menu("Other...").click(); SWTBotShell shell = getBot().shell("New"); shell.activate(); getBot().tree().expandNode("Dawn Examples").select(DawnAcoreTestUtil.CREATION_WIZARD_NAME_EMF); getBot().button("Next >").click(); shell = getBot().shell("New"); shell.activate(); SWTBotText fileNameLabel = getBot().textWithLabel(resourceFieldLabel); fileNameLabel.setText("test.acore"); SWTBotText folder = getBot().textWithLabel("Enter or select the parent folder: "); folder.setText("/folder"); SWTBotPreferences.KEYBOARD_LAYOUT = "EN_US"; getBot().button("Next >").click(); SWTBotCombo comboBox = getBot().comboBox(0); // bot.ccomboBox(0); comboBox.setFocus(); comboBox.setSelection("ACore Root"); getBot().button("Finish").click(); SWTBotEditor editor = getBot().editorByTitle("test.acore"); assertNotNull(editor); editor.close(); { assertEquals(true, resourceExists("/folder/test.acore")); } }
private static SWTBotEditor checkActiveEditorTitle(SWTBotExt bot, String expectedOpenedFileName) { SWTBotEditor activeEditor = null; try { bot.waitUntil( new ActiveEditorHasTitleCondition(bot, expectedOpenedFileName), Timing.time10S()); activeEditor = bot.activeEditor(); } catch (TimeoutException toe) { activeEditor = bot.activeEditor(); fail( "Opened file has to have title " + expectedOpenedFileName + " but has " + activeEditor.getTitle()); } return activeEditor; }
/** Test show type action on VSM and hide type action. */ public void testShowHideTypeAction() { SWTBotView projectExplorer = bot.viewByTitle("Model Explorer"); projectExplorer.setFocus(); projectExplorer.bot().tree().expandNode(getProjectName()).expandNode(VSM_FILE).doubleClick(); SWTBotEditor activeEditor = bot.activeEditor(); activeEditor.setFocus(); String nodeLabel = "platform:/resource/" + getProjectName() + "/" + VSM_FILE; SWTBotMenu contextualMenu = activeEditor .bot() .tree() .expandNode(nodeLabel) .expandNode(GROUP) .expandNode(VIEWPOINT_NAME) .expandNode(REPRESENTATION_NAME) .contextMenu(SHOW_TYPE); contextualMenu.click(); contextualMenu = activeEditor .bot() .tree() .expandNode(nodeLabel) .expandNode(TYPED_GROUP) .expandNode(TYPED_VIEWPOINT_NAME) .expandNode(TYPED_REPRESENTATION_NAME) .contextMenu(HIDE_TYPE); contextualMenu.click(); contextualMenu = activeEditor .bot() .tree() .expandNode(nodeLabel) .expandNode(GROUP) .expandNode(VIEWPOINT_NAME) .expandNode(REPRESENTATION_NAME) .contextMenu(SHOW_TYPE); }
/** * Select the given element in the given editor. * * @param editor the editor where the bot must process * @param element the element to select * @return the selected node */ public SWTBotTreeItem selectNode(SWTBotEditor editor, EObject element) { assertNotNull("The model has not been initialized.", testModelResource); final List<Object> expansionPath = EEFModelHelper.getExpansionPath(element); final Iterator<Object> iterator = expansionPath.iterator(); Object next = null; SWTBotTreeItem node2 = editor.bot().tree().getTreeItem(testModelResource.getURI().toString()); while (iterator.hasNext()) { sleep(1000); node2.expand(); next = iterator.next(); node2 = selectSubNode(node2, next); } return node2; }
/** * Save all editors * * @param bot */ public static void save(final SWTBotEditor editor) { editor .bot() .waitUntil( new DefaultCondition() { @Override public boolean test() throws Exception { return editor.isDirty(); } @Override public String getFailureMessage() { return "Editor never dirty"; } }, 10000, 1000); editor.save(); editor .bot() .waitUntil( new DefaultCondition() { @Override public boolean test() throws Exception { return !editor.isDirty(); } @Override public String getFailureMessage() { return "Editor still dirty"; } }, 10000, 1000); }
@Test public void stashAndApplyChanges() throws Exception { String originalContent = getTestFileContent(); String modifiedContent = "changes to stash"; touch(modifiedContent); assertEquals(modifiedContent, getTestFileContent()); ContextMenuHelper.clickContextMenu( selectProject(), "Team", STASHES, UIText.StashesMenu_StashChangesActionText); SWTBotShell createDialog = bot.shell(UIText.StashCreateCommand_titleEnterCommitMessage); SWTBotText enterMessageText = createDialog.bot().text(0); String stashMessage = "stash message"; enterMessageText.setText(stashMessage); createDialog.bot().button(IDialogConstants.OK_LABEL).click(); assertEquals(originalContent, getTestFileContent()); ContextMenuHelper.clickContextMenu( selectProject(), "Team", STASHES, MessageFormat.format(UIText.StashesMenu_StashItemText, Integer.valueOf(0), stashMessage)); SWTBotEditor stashEditor = bot.activeEditor(); // Check if text with message is there stashEditor.bot().styledText(stashMessage); stashEditor .bot() .toolbarButtonWithTooltip(util.getPluginLocalizedValue("StashApplyCommand.label")) .click(); assertEquals(modifiedContent, getTestFileContent()); }
/** * @param path * @param modelName * @return the root of the new resource */ private EObject getRoot(String path, String modelName) { final URI fileURI = URI.createPlatformResourceURI(path + "/" + modelName, true); Resource resource = editingDomain.getResourceSet().getResource(fileURI, true); setTestModelResource(resource); final SWTBotTreeItem modelTreeItem = editor.bot().tree().getTreeItem(testModelResource.getURI().toString()); resource = (Resource) syncExec( new Result<Object>() { public Object run() { return modelTreeItem.widget.getData(); } }); setTestModelResource(resource); assertFalse("The model is empty.", resource.getContents().isEmpty()); return resource.getContents().get(0); }
/** * Gets the editor tree. * * @param bot the bot * @return the editor tree * @throws Exception the exception */ public static SWTBotTree getEditorTree(final SWTWorkbenchBot bot, String title) throws Exception { SWTBotEditor editor = bot.editorByTitle(title); SWTBotTree tree = editor.bot().tree(); return tree; }
private static void goToTableEnd() { SWTBotEditor eventsEditor = SWTBotUtils.activeEventsEditor(fBot); eventsEditor.setFocus(); eventsEditor.bot().table().pressShortcut(Keystrokes.END); }
@Test public void testServerBuild() { SWTBotTestUtil.createNewDiagram(bot); final SWTBotEditor activeEditor = bot.activeEditor(); final String editorTitle = activeEditor.getTitle(); // System.out.println("editorTitle1 = "+editorTitle1); assertFalse("Error: first diagram name is empty.", editorTitle.isEmpty()); new BotProcessDiagramPropertiesViewFolder(bot) .selectExecutionTab() .selectInstantiationFormTab() .selectLegacy(); new BotGefProcessDiagramEditor(bot).selectElement("Step1"); new BotExecutionDiagramPropertiesView(bot).selectFormTab().selectLegacy(); // get the GEF editor to activate tools final SWTBotGefEditor gmfEditor = bot.gefEditor(editorTitle); // Create 2 Pools gmfEditor.activateTool("Pool"); gmfEditor.click(200, 500); new BotProcessDiagramPropertiesViewFolder(bot) .selectExecutionTab() .selectInstantiationFormTab() .selectLegacy(); gmfEditor.activateTool("Pool"); gmfEditor.click(200, 800); new BotProcessDiagramPropertiesViewFolder(bot) .selectExecutionTab() .selectInstantiationFormTab() .selectLegacy(); // Save Diagram bot.menu("Diagram").menu("Save").click(); // System.out.println(editorTitle); bot.waitUntil(Conditions.widgetIsEnabled(bot.menu("Server"))); // Menu Server > Build... bot.menu("Server").menu("Build...").click(); // shell 'Build' final SWTBotShell shell = bot.shell(Messages.buildTitle); bot.waitUntil(Conditions.shellIsActive(Messages.buildTitle)); // select and check created Diagram in the Tree final SWTBotTree tree = bot.treeWithLabel("Select processes to export"); final SWTBotTreeItem diagramTreeItem = tree.getTreeItem(editorTitle); // check the diagram to export diagramTreeItem.select().check(); diagramTreeItem.expand(); // Number of pool in the diagram final int poolListSize = diagramTreeItem.getItems().length; // System.out.println("Diagram contains "+ poolListSize + " items"); assertEquals("Error: Diagram must contain 3 Pools.", 3, poolListSize); // unselect the first pool of the list diagramTreeItem.getNode(0).select(); diagramTreeItem.getNode(0).uncheck(); final Vector<String> poolTitleList = new Vector<String>(3); final int poolTitleListSize = poolTitleList.size(); // check the selected pools for (int i = 1; i < poolTitleListSize; i++) { final SWTBotTreeItem poolTreeItem = diagramTreeItem.getNode(i); poolTitleList.set(i, poolTreeItem.getText()); final String poolName = getItemName(poolTitleList.get(i)); // test the good pool is checked assertFalse("Error: Pool " + i + " should be checked.", !poolTreeItem.isChecked()); assertFalse("Error: Pool selected is not the good one.", !poolName.equals("Pool" + i)); } // create tmp directory to write diagrams final File tmpBarFolder = new File(ProjectUtil.getBonitaStudioWorkFolder(), "testExportBar"); tmpBarFolder.mkdirs(); // set the path where files are saved final String tmpBarFolderPath = tmpBarFolder.getAbsolutePath(); bot.comboBoxWithLabel(Messages.destinationPath + " *").setText(tmpBarFolderPath); // String tmpBarFolderPath = bot.comboBoxWithLabel(Messages.destinationPath+" *").getText(); // System.out.println("tmpBarFolder = "+tmpBarFolderPath); // click 'Finish' button to close 'Build' shell bot.waitUntil(Conditions.widgetIsEnabled(bot.button(IDialogConstants.FINISH_LABEL))); bot.button(IDialogConstants.FINISH_LABEL).click(); // click 'OK' button to close 'Export' shell bot.waitUntil(new ShellIsActiveWithThreadSTacksOnFailure(Messages.exportSuccessTitle)); bot.button(IDialogConstants.OK_LABEL).click(); // wait the shell to close before checking creation of files bot.waitUntil(Conditions.shellCloses(shell)); // check pools files exist for (int i = 1; i < poolTitleListSize; i++) { final String tmpPoolTitle = poolTitleList.get(i); final String poolFileName = getItemName(tmpPoolTitle) + "--" + getItemVersion(tmpPoolTitle) + ".bar"; final File poolFile = new File(tmpBarFolderPath, poolFileName); assertTrue("Error: The Pool export must exist", poolFile.exists()); assertTrue("Error: The Pool export must be a file", poolFile.isFile()); } }
@AfterClass public static void tearDown() throws Exception { editor.close(); on.selectNode(new Path(DS_PROJECT)).collapse(); AbstractSWTBotTest.deleteProjects(); }
/** @return */ protected SWTBotGefEditor getGefEditor() { SWTBotEditor activeEditor = bot.activeEditor(); String title = activeEditor.getTitle(); SWTBotGefEditor ed = bot.gefEditor(title); return ed; }