use of gate.Document in project gate-core by GateNLP.
the class MainFrame method initGuiComponents.
protected void initGuiComponents() {
this.getContentPane().setLayout(new BorderLayout());
Integer width = Gate.getUserConfig().getInt(GateConstants.MAIN_FRAME_WIDTH, 1024);
Integer height = Gate.getUserConfig().getInt(GateConstants.MAIN_FRAME_HEIGHT, 768);
Rectangle maxDimensions = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds();
this.setSize(new Dimension(Math.min(width, maxDimensions.width), Math.min(height, maxDimensions.height)));
if (Gate.getUserConfig().getBoolean(GateConstants.MAIN_FRAME_MAXIMIZED))
setExtendedState(JFrame.MAXIMIZED_BOTH);
setIconImages(Arrays.asList(new Image[] { new GATEVersionIcon(256, 256).getImage(), new GATEVersionIcon(128, 128).getImage(), new GATEVersionIcon(64, 64).getImage(), new GATEVersionIcon(48, 48).getImage(), new GATEVersionIcon(32, 32).getImage(), new GATEIcon(22, 22).getImage(), new GATEIcon(16, 16).getImage() }));
resourcesTree = new ResourcesTree();
resourcesTree.setModel(resourcesTreeModel);
resourcesTree.setRowHeight(0);
resourcesTree.setEditable(true);
ResourcesTreeCellRenderer treeCellRenderer = new ResourcesTreeCellRenderer();
resourcesTree.setCellRenderer(treeCellRenderer);
resourcesTree.setCellEditor(new ResourcesTreeCellEditor(resourcesTree, treeCellRenderer));
resourcesTree.setInvokesStopCellEditing(true);
resourcesTree.setRowHeight(0);
// expand all nodes
resourcesTree.expandRow(0);
resourcesTree.expandRow(1);
resourcesTree.expandRow(2);
resourcesTree.expandRow(3);
resourcesTree.expandRow(4);
resourcesTree.getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
resourcesTree.setEnabled(true);
ToolTipManager.sharedInstance().registerComponent(resourcesTree);
resourcesTreeScroll = new JScrollPane(resourcesTree);
resourcesTree.setDragEnabled(true);
resourcesTree.setTransferHandler(new TransferHandler() {
// drag and drop that export a list of the selected documents
@Override
public int getSourceActions(JComponent c) {
return COPY;
}
@Override
protected Transferable createTransferable(JComponent c) {
TreePath[] paths = resourcesTree.getSelectionPaths();
if (paths == null) {
return new StringSelection("");
}
Handle handle;
List<String> documentsNames = new ArrayList<String>();
for (TreePath path : paths) {
if (path != null) {
Object value = path.getLastPathComponent();
value = ((DefaultMutableTreeNode) value).getUserObject();
if (value instanceof Handle) {
handle = (Handle) value;
if (handle.getTarget() instanceof Document) {
documentsNames.add(((Document) handle.getTarget()).getName());
}
}
}
}
return new StringSelection("ResourcesTree" + Arrays.toString(documentsNames.toArray()));
}
@Override
protected void exportDone(JComponent c, Transferable data, int action) {
}
@Override
public boolean canImport(JComponent c, DataFlavor[] flavors) {
return false;
}
@Override
public boolean importData(JComponent c, Transferable t) {
return false;
}
});
lowerScroll = new JScrollPane();
JPanel lowerPane = new JPanel();
lowerPane.setLayout(new OverlayLayout(lowerPane));
JPanel animationPane = new JPanel();
animationPane.setOpaque(false);
animationPane.setLayout(new BoxLayout(animationPane, BoxLayout.X_AXIS));
JPanel vBox = new JPanel();
vBox.setLayout(new BoxLayout(vBox, BoxLayout.Y_AXIS));
vBox.setOpaque(false);
JPanel hBox = new JPanel();
hBox.setLayout(new BoxLayout(hBox, BoxLayout.X_AXIS));
hBox.setOpaque(false);
vBox.add(Box.createVerticalGlue());
vBox.add(animationPane);
hBox.add(vBox);
hBox.add(Box.createHorizontalGlue());
lowerPane.add(hBox);
lowerPane.add(lowerScroll);
animator = new CartoonMinder(animationPane);
Thread thread = new Thread(Thread.currentThread().getThreadGroup(), animator, "MainFrame animation");
thread.setDaemon(true);
thread.setPriority(Thread.MIN_PRIORITY);
thread.start();
leftSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT, resourcesTreeScroll, lowerPane);
leftSplit.setResizeWeight(0.7);
leftSplit.setContinuousLayout(true);
leftSplit.setOneTouchExpandable(true);
// Create a new logArea and redirect the Out and Err output to it.
logArea = new LogArea();
// Out has been redirected to the logArea
Out.prln("GATE " + Main.version + " build " + Main.build + " started at " + new Date().toString());
Out.prln("and using Java " + System.getProperty("java.version") + " " + System.getProperty("java.vendor") + " on " + System.getProperty("os.name") + " " + System.getProperty("os.arch") + " " + System.getProperty("os.version") + ".");
mainTabbedPane = new XJTabbedPane(JTabbedPane.TOP);
mainTabbedPane.insertTab("Messages", null, logArea.getComponentToDisplay(), "GATE log", 0);
logHighlighter = new TabHighlighter(mainTabbedPane, logArea.getComponentToDisplay(), Color.red);
mainSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftSplit, mainTabbedPane);
mainSplit.setDividerLocation(leftSplit.getPreferredSize().width + 10);
this.getContentPane().add(mainSplit, BorderLayout.CENTER);
mainSplit.setContinuousLayout(true);
mainSplit.setOneTouchExpandable(true);
// status and progress bars
statusBar = new JLabel("Welcome to GATE!");
statusBar.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 0));
UIManager.put("ProgressBar.cellSpacing", 0);
progressBar = new JProgressBar(JProgressBar.HORIZONTAL);
progressBar.setBorder(BorderFactory.createEmptyBorder());
progressBar.setForeground(new Color(150, 75, 150));
progressBar.setStringPainted(false);
globalProgressBar = new JProgressBar(JProgressBar.HORIZONTAL);
globalProgressBar.setBorder(BorderFactory.createEmptyBorder());
globalProgressBar.setForeground(new Color(150, 75, 150));
globalProgressBar.setStringPainted(true);
JPanel southBox = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.BOTH;
gbc.anchor = GridBagConstraints.WEST;
gbc.weightx = 1;
southBox.add(statusBar, gbc);
gbc.insets = new Insets(0, 3, 0, 3);
gbc.anchor = GridBagConstraints.EAST;
gbc.weightx = 0;
southBox.add(progressBar, gbc);
southBox.add(globalProgressBar, gbc);
this.getContentPane().add(southBox, BorderLayout.SOUTH);
progressBar.setVisible(false);
globalProgressBar.setVisible(false);
// extra stuff
newResourceDialog = new NewResourceDialog(this, "Resource parameters", true);
// build the Help->About dialog
JPanel splashBox = new JPanel();
splashBox.setBackground(Color.WHITE);
splashBox.setLayout(new GridBagLayout());
GridBagConstraints constraints = new GridBagConstraints();
constraints.weightx = 1;
constraints.insets = new Insets(2, 2, 2, 2);
constraints.gridy = 0;
constraints.fill = GridBagConstraints.BOTH;
JLabel gifLbl = new JLabel(getIcon("splash"));
splashBox.add(gifLbl, constraints);
constraints.gridy = 2;
constraints.gridwidth = 2;
constraints.fill = GridBagConstraints.HORIZONTAL;
String splashHtml;
try {
splashHtml = Files.getGateResourceAsString("splash.html");
} catch (IOException e) {
splashHtml = "GATE";
log.error("Couldn't get splash.html resource.", e);
}
JLabel htmlLbl = new JLabel(splashHtml);
htmlLbl.setHorizontalAlignment(SwingConstants.CENTER);
splashBox.add(htmlLbl, constraints);
constraints.gridy = 3;
htmlLbl = new JLabel("<HTML><FONT color=\"blue\">Version <B>" + Main.version + "</B></FONT>" + ", <FONT color=\"red\">build <B>" + Main.build + "</B></FONT>" + "<P><B>JVM version</B>: " + System.getProperty("java.version") + " from " + System.getProperty("java.vendor") + "</HTML>");
constraints.fill = GridBagConstraints.HORIZONTAL;
splashBox.add(htmlLbl, constraints);
constraints.gridy = 4;
constraints.gridwidth = 2;
constraints.fill = GridBagConstraints.NONE;
final JButton okButton = new JButton("OK");
okButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
splash.setVisible(false);
}
});
okButton.setBackground(Color.white);
splashBox.add(okButton, constraints);
splash = new Splash(this, splashBox);
// make Enter and Escape keys closing the splash window
splash.getRootPane().setDefaultButton(okButton);
InputMap inputMap = ((JComponent) splash.getContentPane()).getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = ((JComponent) splash.getContentPane()).getActionMap();
inputMap.put(KeyStroke.getKeyStroke("ENTER"), "Apply");
actionMap.put("Apply", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
okButton.doClick();
}
});
inputMap.put(KeyStroke.getKeyStroke("ESCAPE"), "Cancel");
actionMap.put("Cancel", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
okButton.doClick();
}
});
// MENUS
menuBar = new JMenuBar();
JMenu fileMenu = new XJMenu("File", null, this);
fileMenu.setMnemonic(KeyEvent.VK_F);
LiveMenu newAPPMenu = new LiveMenu(LiveMenu.APP);
newAPPMenu.setText("New Application");
newAPPMenu.setIcon(getIcon("applications"));
fileMenu.add(newAPPMenu);
LiveMenu newLRMenu = new LiveMenu(LiveMenu.LR);
newLRMenu.setText("New Language Resource");
newLRMenu.setIcon(getIcon("lrs"));
fileMenu.add(newLRMenu);
LiveMenu newPRMenu = new LiveMenu(LiveMenu.PR);
newPRMenu.setText("New Processing Resource");
newPRMenu.setIcon(getIcon("prs"));
fileMenu.add(newPRMenu);
final JMenu dsMenu = new XJMenu("Datastores", "Repositories for large data", this);
dsMenu.setIcon(getIcon("datastores"));
dsMenu.add(new XJMenuItem(new NewDSAction(), this));
dsMenu.add(new XJMenuItem(new OpenDSAction(), this));
fileMenu.add(dsMenu);
fileMenu.addSeparator();
fileMenu.add(new ReadyMadeMenu());
fileMenu.add(new XJMenuItem(new LoadResourceFromFileAction(), this));
RecentAppsMenu recentAppsMenu = new RecentAppsMenu();
fileMenu.add(recentAppsMenu);
/*final JMenu loadANNIEMenu = new XJMenu("Load ANNIE System",
"Application that adds morphosyntaxic and semantic annotations", this);
loadANNIEMenu.setIcon(getIcon("annie-application"));
loadANNIEMenu.add(new XJMenuItem(new LoadANNIEWithDefaultsAction(), this));
loadANNIEMenu
.add(new XJMenuItem(new LoadANNIEWithoutDefaultsAction(), this));
fileMenu.add(loadANNIEMenu);
// LingPipe action
fileMenu.add(new XJMenuItem(new LoadApplicationAction(
"Load LingPipe System", "LingPipe", "resources/lingpipe.gapp"),
this));
// OpenNLP action
fileMenu.add(new XJMenuItem(new LoadApplicationAction(
"Load OpenNLP System", "OpenNLP", "resources/opennlp.gapp"), this));
*/
fileMenu.add(new XJMenuItem(new ManagePluginsAction(), this));
if (!Gate.runningOnMac()) {
fileMenu.addSeparator();
fileMenu.add(new XJMenuItem(new ExitGateAction(), this));
}
menuBar.add(fileMenu);
JMenu optionsMenu = new XJMenu("Options", null, this);
optionsMenu.setMnemonic(KeyEvent.VK_O);
boolean optionsMenuHasEntries = false;
optionsDialog = new OptionsDialog(MainFrame.this);
if (!Gate.runningOnMac()) {
optionsMenu.add(new XJMenuItem(new AbstractAction("Configuration") {
private static final long serialVersionUID = 1L;
{
putValue(SHORT_DESCRIPTION, "Edit GATE options");
}
@Override
public void actionPerformed(ActionEvent evt) {
optionsDialog.showDialog();
optionsDialog.dispose();
}
}, this));
optionsMenuHasEntries = true;
}
if (optionsMenuHasEntries) {
menuBar.add(optionsMenu);
}
ToolsMenu toolsMenu = new ToolsMenu("Tools", null, this);
toolsMenu.setMnemonic(KeyEvent.VK_T);
toolsMenu.add(new XJMenuItem(new NewAnnotDiffAction(), this));
try {
// Check if log4j is present on the classpath, in order to avoid failures
// in cases when running the GATE GUI in the same JVM with a system which
// uses SLF4J and the log4j bridge.
// The log4j-over-slf4j bridge does not include org.apache.log4j.Appender, so
// if the class is not present we assume the lack of a log4j jar in the classpath
// and do not populate the menu.
Class.forName("org.apache.log4j.Appender");
final JMenuItem reportClearMenuItem = new XJMenuItem(new AbstractAction("Clear Profiling History") {
{
putValue(SHORT_DESCRIPTION, "Clear profiling history otherwise the report is cumulative.");
}
@Override
public void actionPerformed(ActionEvent evt) {
// create a new log file
File logFile = new File(System.getProperty("java.io.tmpdir"), "gate-benchmark-log.txt");
logFile.deleteOnExit();
if (logFile.exists() && !logFile.delete()) {
log.info("Error when deleting the file:\n" + logFile.getAbsolutePath());
}
}
}, this);
JMenu reportMenu = new XJMenu("Profiling Reports", "Generates profiling reports from processing resources", this);
reportMenu.setIcon(getIcon("gazetteer"));
reportMenu.add(new XJMenuItem(new AbstractAction("Start Profiling Applications") {
{
putValue(SHORT_DESCRIPTION, "Toggles the profiling of processing resources");
}
// stores the value held by the benchmarking switch before we started
// this profiling run.
boolean benchmarkWasEnabled;
@Override
public void actionPerformed(ActionEvent evt) {
if (getValue(NAME).equals("Start Profiling Applications")) {
reportClearMenuItem.setEnabled(false);
// store old value of benchmark switch
benchmarkWasEnabled = Benchmark.isBenchmarkingEnabled();
Benchmark.setBenchmarkingEnabled(true);
Layout layout = new PatternLayout("%m%n");
File logFile = new File(System.getProperty("java.io.tmpdir"), "gate-benchmark-log.txt");
logFile.deleteOnExit();
Appender appender;
try {
appender = new FileAppender(layout, logFile.getAbsolutePath(), true);
} catch (IOException e) {
e.printStackTrace();
return;
}
appender.setName("gate-benchmark");
Benchmark.logger.addAppender(appender);
putValue(NAME, "Stop Profiling Applications");
} else {
// reset old value of benchmark switch - i.e. if benchmarking was
// disabled before the user selected "start profiling" then we
// disable it again now, but if it was already enabled before they
// started profiling then we assume it was turned on explicitly and
// leave it alone.
Benchmark.setBenchmarkingEnabled(benchmarkWasEnabled);
Benchmark.logger.removeAppender("gate-benchmark");
putValue(NAME, "Start Profiling Applications");
reportClearMenuItem.setEnabled(true);
}
}
}, this));
reportMenu.add(reportClearMenuItem);
reportMenu.add(new XJMenuItem(new AbstractAction("Help on this tool") {
@Override
public void actionPerformed(ActionEvent e) {
showHelpFrame("chap:profiling", "Profiling Processing Resources");
}
}, this));
reportMenu.addSeparator();
final JCheckBoxMenuItem reportZeroTimesCheckBox = new JCheckBoxMenuItem();
reportZeroTimesCheckBox.setAction(new AbstractAction("Report Zero Time Entries") {
@Override
public void actionPerformed(ActionEvent evt) {
Gate.getUserConfig().put(MainFrame.class.getName() + ".reportzerotime", reportZeroTimesCheckBox.isSelected());
}
});
reportZeroTimesCheckBox.setSelected(Gate.getUserConfig().getBoolean(MainFrame.class.getName() + ".reportzerotimes"));
ButtonGroup group = new ButtonGroup();
final JRadioButtonMenuItem reportSortExecution = new JRadioButtonMenuItem();
reportSortExecution.setAction(new AbstractAction("Sort by Execution") {
@Override
public void actionPerformed(ActionEvent evt) {
Gate.getUserConfig().put(MainFrame.class.getName() + ".reportsorttime", false);
}
});
reportSortExecution.setSelected(!Gate.getUserConfig().getBoolean(MainFrame.class.getName() + ".reportsorttime"));
group.add(reportSortExecution);
final JRadioButtonMenuItem reportSortTime = new JRadioButtonMenuItem();
reportSortTime.setAction(new AbstractAction("Sort by Time") {
@Override
public void actionPerformed(ActionEvent evt) {
Gate.getUserConfig().put(MainFrame.class.getName() + ".reportsorttime", true);
}
});
reportSortTime.setSelected(Gate.getUserConfig().getBoolean(MainFrame.class.getName() + ".reportsorttime"));
group.add(reportSortTime);
reportMenu.add(new XJMenuItem(new AbstractAction("Report on Processing Resources") {
{
putValue(SHORT_DESCRIPTION, "Report time taken by each processing resource");
}
@Override
public void actionPerformed(ActionEvent evt) {
PRTimeReporter report = new PRTimeReporter();
report.setBenchmarkFile(new File(System.getProperty("java.io.tmpdir"), "gate-benchmark-log.txt"));
report.setSuppressZeroTimeEntries(!reportZeroTimesCheckBox.isSelected());
report.setSortOrder(reportSortTime.isSelected() ? PRTimeReporter.SORT_TIME_TAKEN : PRTimeReporter.SORT_EXEC_ORDER);
try {
report.executeReport();
} catch (BenchmarkReportException e) {
e.printStackTrace();
return;
}
showHelpFrame("file://" + report.getReportFile(), "processing times report");
}
}, this));
reportMenu.add(reportZeroTimesCheckBox);
reportMenu.add(reportSortTime);
reportMenu.add(reportSortExecution);
reportMenu.addSeparator();
reportMenu.add(new XJMenuItem(new AbstractAction("Report on Documents Processed") {
{
putValue(SHORT_DESCRIPTION, "Report most time consuming documents");
}
@Override
public void actionPerformed(ActionEvent evt) {
DocTimeReporter report = new DocTimeReporter();
report.setBenchmarkFile(new File(System.getProperty("java.io.tmpdir"), "gate-benchmark-log.txt"));
String maxDocs = Gate.getUserConfig().getString(MainFrame.class.getName() + ".reportmaxdocs");
if (maxDocs != null) {
report.setMaxDocumentInReport((maxDocs.equals("All")) ? DocTimeReporter.ALL_DOCS : Integer.parseInt(maxDocs));
}
String prRegex = Gate.getUserConfig().getString(MainFrame.class.getName() + ".reportprregex");
if (prRegex != null) {
report.setPRMatchingRegex((prRegex.equals("")) ? DocTimeReporter.MATCH_ALL_PR_REGEX : prRegex);
}
try {
report.executeReport();
} catch (BenchmarkReportException e) {
e.printStackTrace();
return;
}
showHelpFrame("file://" + report.getReportFile(), "documents time report");
}
}, this));
String maxDocs = Gate.getUserConfig().getString(MainFrame.class.getName() + ".reportmaxdocs");
if (maxDocs == null) {
maxDocs = "10";
}
reportMenu.add(new XJMenuItem(new AbstractAction("Set Max Documents (" + maxDocs + ")") {
@Override
public void actionPerformed(ActionEvent evt) {
Object response = JOptionPane.showInputDialog(instance, "Set the maximum of documents to report", "Report options", JOptionPane.QUESTION_MESSAGE, null, new Object[] { "All", "10", "20", "30", "40", "50", "100" }, "10");
if (response != null) {
Gate.getUserConfig().put(MainFrame.class.getName() + ".reportmaxdocs", response);
putValue(NAME, "Set Max Documents (" + response + ")");
}
}
}, this));
String prRegex = Gate.getUserConfig().getString(MainFrame.class.getName() + ".reportprregex");
if (prRegex == null || prRegex.equals("")) {
prRegex = "All";
}
reportMenu.add(new XJMenuItem(new AbstractAction("Set PR Matching Regex (" + prRegex + ")") {
@Override
public void actionPerformed(ActionEvent evt) {
Object response = JOptionPane.showInputDialog(instance, "Set the processing resource regex filter\n" + "Leave empty to not filter", "Report options", JOptionPane.QUESTION_MESSAGE);
if (response != null) {
Gate.getUserConfig().put(MainFrame.class.getName() + ".reportprregex", response);
if (response.equals("")) {
response = "All";
}
putValue(NAME, "Set PR Matching Regex (" + response + ")");
}
}
}, this));
toolsMenu.add(reportMenu);
} catch (ClassNotFoundException e) {
log.warn("log4j.jar not found on the classpath, disabling profiling reports.");
}
toolsMenu.add(new XJMenuItem(new NewBootStrapAction(), this));
final JMenu corpusEvalMenu = new XJMenu("Corpus Benchmark", "Compares processed and human-annotated annotations", this);
corpusEvalMenu.setIcon(getIcon("corpus-benchmark"));
toolsMenu.add(corpusEvalMenu);
corpusEvalMenu.add(new XJMenuItem(new NewCorpusEvalAction(), this));
corpusEvalMenu.addSeparator();
corpusEvalMenu.add(new XJMenuItem(new GenerateStoredCorpusEvalAction(), this));
corpusEvalMenu.addSeparator();
corpusEvalMenu.add(new XJMenuItem(new StoredMarkedCorpusEvalAction(), this));
corpusEvalMenu.add(new XJMenuItem(new CleanMarkedCorpusEvalAction(), this));
corpusEvalMenu.addSeparator();
verboseModeItem = new JCheckBoxMenuItem(new VerboseModeCorpusEvalToolAction());
corpusEvalMenu.add(verboseModeItem);
toolsMenu.staticItemsAdded();
menuBar.add(toolsMenu);
JMenu helpMenu = new XJMenu("Help", null, MainFrame.this);
helpMenu.setMnemonic(KeyEvent.VK_H);
helpMenu.add(new XJMenuItem(new HelpUserGuideAction(), this));
helpMenu.add(new XJMenuItem(new HelpUserGuideInContextAction(), this));
helpMenu.add(new XJMenuItem(new AbstractAction("Keyboard Shortcuts") {
@Override
public void actionPerformed(ActionEvent e) {
showHelpFrame("sec:developer:keyboard", "shortcuts");
}
}, this));
helpMenu.addSeparator();
helpMenu.add(new XJMenuItem(new AbstractAction("Using GATE Developer") {
{
this.putValue(Action.SHORT_DESCRIPTION, "To read first");
}
@Override
public void actionPerformed(ActionEvent e) {
showHelpFrame("chap:developer", "Using GATE Developer");
}
}, this));
helpMenu.add(new XJMenuItem(new AbstractAction("Demo Movies") {
{
this.putValue(Action.SHORT_DESCRIPTION, "Movie tutorials");
}
@Override
public void actionPerformed(ActionEvent e) {
showHelpFrame("http://gate.ac.uk/demos/developer-videos/", "movies");
}
}, this));
helpMenu.add(new XJMenuItem(new HelpMailingListAction(), this));
helpMenu.addSeparator();
JCheckBoxMenuItem toggleToolTipsCheckBoxMenuItem = new JCheckBoxMenuItem(new ToggleToolTipsAction());
javax.swing.ToolTipManager toolTipManager = ToolTipManager.sharedInstance();
if (Gate.getUserConfig().getBoolean(MainFrame.class.getName() + ".hidetooltips")) {
toolTipManager.setEnabled(false);
toggleToolTipsCheckBoxMenuItem.setSelected(false);
} else {
toolTipManager.setEnabled(true);
toggleToolTipsCheckBoxMenuItem.setSelected(true);
}
helpMenu.add(toggleToolTipsCheckBoxMenuItem);
helpMenu.add(new XJMenuItem(new AbstractAction("What's New") {
{
this.putValue(Action.SHORT_DESCRIPTION, "List new features and important changes");
}
@Override
public void actionPerformed(ActionEvent e) {
showHelpFrame("chap:changes", "changes");
}
}, this));
if (!Gate.runningOnMac()) {
helpMenu.add(new XJMenuItem(new HelpAboutAction(), this));
}
menuBar.add(helpMenu);
this.setJMenuBar(menuBar);
// popups
lrsPopup = new XJPopupMenu();
LiveMenu lrsMenu = new LiveMenu(LiveMenu.LR);
lrsMenu.setText("New");
lrsPopup.add(lrsMenu);
guiRoots.add(lrsPopup);
guiRoots.add(lrsMenu);
prsPopup = new XJPopupMenu();
LiveMenu prsMenu = new LiveMenu(LiveMenu.PR);
prsMenu.setText("New");
prsPopup.add(prsMenu);
guiRoots.add(prsPopup);
guiRoots.add(prsMenu);
dssPopup = new XJPopupMenu();
dssPopup.add(new NewDSAction());
dssPopup.add(new OpenDSAction());
guiRoots.add(dssPopup);
// TOOLBAR
toolbar = new JToolBar(JToolBar.HORIZONTAL);
toolbar.setFloatable(false);
JButton button = new JButton(new LoadResourceFromFileAction());
button.setToolTipText(button.getText());
button.setText("");
toolbar.add(button);
toolbar.addSeparator();
try {
JButton annieMenu = new JButton(new LoadApplicationAction("ANNIE", "annie-application", new ResourceReference(new URI("creole://uk.ac.gate.plugins;annie;" + gate.Main.version + "/resources/" + ANNIEConstants.DEFAULT_FILE))));
annieMenu.setText("");
annieMenu.setToolTipText("Load ANNIE");
toolbar.add(annieMenu);
toolbar.addSeparator();
} catch (URISyntaxException e) {
// should be impossible
}
LiveMenu tbNewLRMenu = new LiveMenu(LiveMenu.LR);
JMenuButton menuButton = new JMenuButton(tbNewLRMenu);
menuButton.setToolTipText("New Language Resource");
menuButton.setIcon(getIcon("lrs"));
toolbar.add(menuButton);
LiveMenu tbNewPRMenu = new LiveMenu(LiveMenu.PR);
menuButton = new JMenuButton(tbNewPRMenu);
menuButton.setToolTipText("New Processing Resource");
menuButton.setIcon(getIcon("prs"));
toolbar.add(menuButton);
LiveMenu tbNewAppMenu = new LiveMenu(LiveMenu.APP);
menuButton = new JMenuButton(tbNewAppMenu);
menuButton.setToolTipText("New Application");
menuButton.setIcon(getIcon("applications"));
toolbar.add(menuButton);
toolbar.addSeparator();
JPopupMenu tbDsMenu = new JPopupMenu();
tbDsMenu.add(new NewDSAction());
tbDsMenu.add(new OpenDSAction());
menuButton = new JMenuButton(tbDsMenu);
menuButton.setToolTipText("Datastores");
menuButton.setIcon(getIcon("datastores"));
toolbar.add(menuButton);
toolbar.addSeparator();
button = new JButton(new ManagePluginsAction());
button.setToolTipText(button.getText());
button.setText("");
toolbar.add(button);
toolbar.addSeparator();
button = new JButton(new NewAnnotDiffAction());
button.setToolTipText(button.getText());
button.setText("");
toolbar.add(button);
toolbar.add(Box.createHorizontalGlue());
this.getContentPane().add(toolbar, BorderLayout.NORTH);
}
use of gate.Document in project gate-core by GateNLP.
the class CorpusQualityAssurance method readSetsTypesFeatures.
/**
* Update set lists.
* @param documentStart first document to read in the corpus,
* the first document of the corpus is 0.
*/
protected void readSetsTypesFeatures(final int documentStart) {
if (!isShowing()) {
return;
}
corpusChanged = false;
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
progressBar.setMaximum(corpus.size() - 1);
progressBar.setString("Read sets, types, features");
reloadCacheAction.setEnabled(false);
}
});
CorpusQualityAssurance.this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
Runnable runnable = new Runnable() {
@Override
public void run() {
if (docsSetsTypesFeatures.size() != corpus.getDocumentNames().size() || !docsSetsTypesFeatures.keySet().containsAll(corpus.getDocumentNames())) {
if (documentStart == 0) {
docsSetsTypesFeatures.clear();
}
TreeMap<String, TreeMap<String, TreeSet<String>>> setsTypesFeatures;
TreeMap<String, TreeSet<String>> typesFeatures;
TreeSet<String> features;
for (int i = documentStart; i < corpus.size(); i++) {
// fill in the lists of document, set, type and feature names
boolean documentWasLoaded = corpus.isDocumentLoaded(i);
Document document = corpus.get(i);
if (document != null && document.getAnnotationSetNames() != null) {
setsTypesFeatures = new TreeMap<String, TreeMap<String, TreeSet<String>>>(collator);
HashSet<String> setNames = new HashSet<String>(document.getAnnotationSetNames());
setNames.add("");
for (String set : setNames) {
typesFeatures = new TreeMap<String, TreeSet<String>>(collator);
AnnotationSet annotations = document.getAnnotations(set);
for (String type : annotations.getAllTypes()) {
features = new TreeSet<String>(collator);
for (Annotation annotation : annotations.get(type)) {
for (Object featureKey : annotation.getFeatures().keySet()) {
features.add((String) featureKey);
}
}
typesFeatures.put(type, features);
}
setsTypesFeatures.put(set, typesFeatures);
}
docsSetsTypesFeatures.put(document.getName(), setsTypesFeatures);
}
if (!documentWasLoaded) {
corpus.unloadDocument(document);
Factory.deleteResource(document);
}
final int progressValue = i + 1;
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
progressBar.setValue(progressValue);
if ((progressValue + 1) % 5 == 0) {
// update the set list every 5 documents read
updateSetList();
}
}
});
if (Thread.interrupted()) {
return;
}
}
}
updateSetList();
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
progressBar.setValue(progressBar.getMinimum());
progressBar.setString("");
CorpusQualityAssurance.this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
reloadCacheAction.setEnabled(true);
}
});
}
};
readSetsTypesFeaturesThread = new Thread(runnable, "readSetsTypesFeatures");
readSetsTypesFeaturesThread.setPriority(Thread.MIN_PRIORITY);
readSetsTypesFeaturesThread.start();
}
use of gate.Document in project gate-core by GateNLP.
the class CorpusQualityAssurance method compareAnnotation.
protected void compareAnnotation() {
int progressValuePrevious = -1;
if (readSetsTypesFeaturesThread != null && readSetsTypesFeaturesThread.isAlive()) {
// stop the thread that reads the sets, types and features
progressValuePrevious = progressBar.getValue();
readSetsTypesFeaturesThread.interrupt();
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
progressBar.setMaximum(corpus.size() - 1);
progressBar.setString("Compare annotations");
setList.setEnabled(false);
setCheck.setEnabled(false);
typeList.setEnabled(false);
typeCheck.setEnabled(false);
featureList.setEnabled(false);
featureCheck.setEnabled(false);
optionsButton.setEnabled(false);
measureTabbedPane.setEnabled(false);
measureList.setEnabled(false);
exportToHtmlAction.setEnabled(false);
reloadCacheAction.setEnabled(false);
}
});
boolean useBdm = false;
if (measuresType == FSCORE_MEASURES) {
differsByDocThenType.clear();
documentNames.clear();
for (Object measure : measureList.getSelectedValues()) {
if (((String) measure).contains("BDM")) {
useBdm = true;
break;
}
}
}
List<ClassificationMeasures> classificationMeasuresList = new ArrayList<ClassificationMeasures>();
List<OntologyMeasures> documentOntologyMeasuresList = new ArrayList<OntologyMeasures>();
List<OntologyMeasures> annotationOntologyMeasuresList = new ArrayList<OntologyMeasures>();
// for each document
for (int row = 0; row < corpus.size(); row++) {
boolean documentWasLoaded = corpus.isDocumentLoaded(row);
Document document = corpus.get(row);
documentNames.add(document.getName());
Set<Annotation> keys = new HashSet<Annotation>();
Set<Annotation> responses = new HashSet<Annotation>();
// get annotations from selected annotation sets
if (keySetName.equals("[Default set]")) {
keys = document.getAnnotations();
} else if (document.getAnnotationSetNames() != null && document.getAnnotationSetNames().contains(keySetName)) {
keys = document.getAnnotations(keySetName);
}
if (responseSetName.equals("[Default set]")) {
responses = document.getAnnotations();
} else if (document.getAnnotationSetNames() != null && document.getAnnotationSetNames().contains(responseSetName)) {
responses = document.getAnnotations(responseSetName);
}
if (!documentWasLoaded) {
// in case of datastore
corpus.unloadDocument(document);
Factory.deleteResource(document);
}
// add data to the fscore document table
if (measuresType == FSCORE_MEASURES) {
types.clear();
for (Object type : typeList.getSelectedValues()) {
types.add((String) type);
}
if (typeList.isSelectionEmpty()) {
for (int i = 0; i < typeList.getModel().getSize(); i++) {
types.add((String) typeList.getModel().getElementAt(i));
}
}
Set<String> featureSet = new HashSet<String>();
for (Object feature : featureList.getSelectedValues()) {
featureSet.add((String) feature);
}
HashMap<String, AnnotationDiffer> differsByType = new HashMap<String, AnnotationDiffer>();
AnnotationDiffer differ;
Set<Annotation> keysIter = new HashSet<Annotation>();
Set<Annotation> responsesIter = new HashSet<Annotation>();
for (String type : types) {
if (!keys.isEmpty() && !types.isEmpty()) {
keysIter = ((AnnotationSet) keys).get(type);
}
if (!responses.isEmpty() && !types.isEmpty()) {
responsesIter = ((AnnotationSet) responses).get(type);
}
differ = new AnnotationDiffer();
differ.setSignificantFeaturesSet(featureSet);
// compare
differ.calculateDiff(keysIter, responsesIter);
differsByType.put(type, differ);
}
differsByDocThenType.add(differsByType);
differ = new AnnotationDiffer(differsByType.values());
List<String> measuresRow;
if (useBdm) {
OntologyMeasures ontologyMeasures = new OntologyMeasures();
ontologyMeasures.setBdmFile(bdmFileUrl);
ontologyMeasures.calculateBdm(differsByType.values());
documentOntologyMeasuresList.add(ontologyMeasures);
measuresRow = ontologyMeasures.getMeasuresRow(measureList.getSelectedValues(), documentNames.get(documentNames.size() - 1));
} else {
measuresRow = differ.getMeasuresRow(measureList.getSelectedValues(), documentNames.get(documentNames.size() - 1));
}
documentTableModel.addRow(measuresRow.toArray());
// add data to the classification document table
} else if (measuresType == CLASSIFICATION_MEASURES && !keys.isEmpty() && !responses.isEmpty()) {
ClassificationMeasures classificationMeasures = new ClassificationMeasures();
classificationMeasures.calculateConfusionMatrix((AnnotationSet) keys, (AnnotationSet) responses, (String) typeList.getSelectedValue(), (String) featureList.getSelectedValue(), verboseOptionCheckBox.isSelected());
classificationMeasuresList.add(classificationMeasures);
List<String> measuresRow = classificationMeasures.getMeasuresRow(measure2List.getSelectedValues(), documentNames.get(documentNames.size() - 1));
document2TableModel.addRow(measuresRow.toArray());
List<List<String>> matrix = classificationMeasures.getConfusionMatrix(documentNames.get(documentNames.size() - 1));
for (List<String> matrixRow : matrix) {
while (confusionTableModel.getColumnCount() < matrix.size()) {
confusionTableModel.addColumn(" ");
}
confusionTableModel.addRow(matrixRow.toArray());
}
}
final int progressValue = row + 1;
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
progressBar.setValue(progressValue);
}
});
}
// add data to the fscore annotation table
if (measuresType == FSCORE_MEASURES) {
for (String type : types) {
ArrayList<AnnotationDiffer> differs = new ArrayList<AnnotationDiffer>();
for (HashMap<String, AnnotationDiffer> differsByType : differsByDocThenType) {
differs.add(differsByType.get(type));
}
List<String> measuresRow;
if (useBdm) {
OntologyMeasures ontologyMeasures = new OntologyMeasures();
ontologyMeasures.setBdmFile(bdmFileUrl);
ontologyMeasures.calculateBdm(differs);
annotationOntologyMeasuresList.add(ontologyMeasures);
measuresRow = ontologyMeasures.getMeasuresRow(measureList.getSelectedValues(), type);
} else {
AnnotationDiffer differ = new AnnotationDiffer(differs);
measuresRow = differ.getMeasuresRow(measureList.getSelectedValues(), type);
}
annotationTableModel.addRow(measuresRow.toArray());
}
}
// add summary rows to the fscore tables
if (measuresType == FSCORE_MEASURES) {
if (useBdm) {
OntologyMeasures ontologyMeasures = new OntologyMeasures(documentOntologyMeasuresList);
printSummary(ontologyMeasures, documentTableModel, 5, documentTableModel.getRowCount(), measureList.getSelectedValues());
ontologyMeasures = new OntologyMeasures(annotationOntologyMeasuresList);
printSummary(ontologyMeasures, annotationTableModel, 5, annotationTableModel.getRowCount(), measureList.getSelectedValues());
} else {
List<AnnotationDiffer> differs = new ArrayList<AnnotationDiffer>();
for (Map<String, AnnotationDiffer> differsByType : differsByDocThenType) {
differs.addAll(differsByType.values());
}
AnnotationDiffer differ = new AnnotationDiffer(differs);
printSummary(differ, documentTableModel, 5, documentTableModel.getRowCount(), measureList.getSelectedValues());
printSummary(differ, annotationTableModel, 5, annotationTableModel.getRowCount(), measureList.getSelectedValues());
}
// add summary rows to the classification tables
} else if (measuresType == CLASSIFICATION_MEASURES) {
ClassificationMeasures classificationMeasures = new ClassificationMeasures(classificationMeasuresList);
printSummary(classificationMeasures, document2TableModel, 3, document2TableModel.getRowCount(), measure2List.getSelectedValues());
List<List<String>> matrix = classificationMeasures.getConfusionMatrix("Whole corpus");
int insertionRow = 0;
for (List<String> row : matrix) {
while (confusionTableModel.getColumnCount() < matrix.size()) {
confusionTableModel.addColumn(" ");
}
confusionTableModel.insertRow(insertionRow++, row.toArray());
}
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
progressBar.setValue(progressBar.getMinimum());
progressBar.setString("");
setList.setEnabled(true);
setCheck.setEnabled(true);
typeList.setEnabled(true);
typeCheck.setEnabled(true);
featureList.setEnabled(true);
featureCheck.setEnabled(true);
optionsButton.setEnabled(true);
measureTabbedPane.setEnabled(true);
measureList.setEnabled(true);
exportToHtmlAction.setEnabled(true);
reloadCacheAction.setEnabled(true);
}
});
if (progressValuePrevious > -1) {
// restart the thread where it was interrupted
readSetsTypesFeatures(progressValuePrevious);
}
}
use of gate.Document in project gate-core by GateNLP.
the class DocumentExportMenu method addExporter.
private void addExporter(final DocumentExporter de) {
if (itemByResource.containsKey(de))
return;
final ResourceData rd = Gate.getCreoleRegister().get(de.getClass().getCanonicalName());
if (DocumentExportMenu.this.getItemCount() == 1) {
DocumentExportMenu.this.addSeparator();
}
JMenuItem item = DocumentExportMenu.this.add(new AbstractAction(de.getFileType() + " (." + de.getDefaultExtension() + ")", MainFrame.getIcon(rd.getIcon(), rd.getResourceClassLoader())) {
@Override
public void actionPerformed(ActionEvent ae) {
List<List<Parameter>> params = rd.getParameterList().getRuntimeParameters();
final FeatureMap options = Factory.newFeatureMap();
final File selectedFile = getSelectedFile(params, de, options);
if (selectedFile == null)
return;
Runnable runnable = new Runnable() {
public void run() {
if (handle.getTarget() instanceof Document) {
long start = System.currentTimeMillis();
listener.statusChanged("Saving as " + de.getFileType() + " to " + selectedFile.toString() + "...");
try {
de.export((Document) handle.getTarget(), selectedFile, options);
} catch (IOException e) {
e.printStackTrace();
}
long time = System.currentTimeMillis() - start;
listener.statusChanged("Finished saving as " + de.getFileType() + " into " + " the file: " + selectedFile.toString() + " in " + ((double) time) / 1000 + "s");
} else {
// corpus
if (de instanceof CorpusExporter) {
long start = System.currentTimeMillis();
listener.statusChanged("Saving as " + de.getFileType() + " to " + selectedFile.toString() + "...");
try {
((CorpusExporter) de).export((Corpus) handle.getTarget(), selectedFile, options);
} catch (IOException e) {
e.printStackTrace();
}
long time = System.currentTimeMillis() - start;
listener.statusChanged("Finished saving as " + de.getFileType() + " into " + " the file: " + selectedFile.toString() + " in " + ((double) time) / 1000 + "s");
} else {
// not a CorpusExporter
try {
File dir = selectedFile;
// create the top directory if needed
if (!dir.exists()) {
if (!dir.mkdirs()) {
JOptionPane.showMessageDialog(MainFrame.getInstance(), "Could not create top directory!", "GATE", JOptionPane.ERROR_MESSAGE);
return;
}
}
MainFrame.lockGUI("Saving...");
Corpus corpus = (Corpus) handle.getTarget();
// iterate through all the docs and save
// each of
// them
Iterator<Document> docIter = corpus.iterator();
boolean overwriteAll = false;
int docCnt = corpus.size();
int currentDocIndex = 0;
Set<String> usedFileNames = new HashSet<String>();
while (docIter.hasNext()) {
boolean docWasLoaded = corpus.isDocumentLoaded(currentDocIndex);
Document currentDoc = docIter.next();
URL sourceURL = currentDoc.getSourceUrl();
String fileName = null;
if (sourceURL != null) {
fileName = sourceURL.getPath();
fileName = Files.getLastPathComponent(fileName);
}
if (fileName == null || fileName.length() == 0) {
fileName = currentDoc.getName();
}
// makes sure that the filename does not
// contain
// any
// forbidden character
fileName = fileName.replaceAll("[\\/:\\*\\?\"<>|]", "_");
if (fileName.toLowerCase().endsWith("." + de.getDefaultExtension())) {
fileName = fileName.substring(0, fileName.length() - de.getDefaultExtension().length() - 1);
}
if (usedFileNames.contains(fileName)) {
// name clash -> add unique ID
String fileNameBase = fileName;
int uniqId = 0;
fileName = fileNameBase + "-" + uniqId++;
while (usedFileNames.contains(fileName)) {
fileName = fileNameBase + "-" + uniqId++;
}
}
usedFileNames.add(fileName);
if (!fileName.toLowerCase().endsWith("." + de.getDefaultExtension()))
fileName += "." + de.getDefaultExtension();
File docFile = null;
boolean nameOK = false;
do {
docFile = new File(dir, fileName);
if (docFile.exists() && !overwriteAll) {
// ask the user if we can overwrite
// the file
Object[] opts = new Object[] { "Yes", "All", "No", "Cancel" };
MainFrame.unlockGUI();
int answer = JOptionPane.showOptionDialog(MainFrame.getInstance(), "File " + docFile.getName() + " already exists!\n" + "Overwrite?", "GATE", JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE, null, opts, opts[2]);
MainFrame.lockGUI("Saving...");
switch(answer) {
case 0:
{
nameOK = true;
break;
}
case 1:
{
nameOK = true;
overwriteAll = true;
break;
}
case 2:
{
// user said NO, allow them to
// provide
// an
// alternative name;
MainFrame.unlockGUI();
fileName = (String) JOptionPane.showInputDialog(MainFrame.getInstance(), "Please provide an alternative file name", "GATE", JOptionPane.QUESTION_MESSAGE, null, null, fileName);
if (fileName == null) {
handle.processFinished();
return;
}
MainFrame.lockGUI("Saving");
break;
}
case 3:
{
// user gave up; return
handle.processFinished();
return;
}
}
} else {
nameOK = true;
}
} while (!nameOK);
// save the file
try {
// do the actual exporting
de.export(currentDoc, docFile, options);
} catch (Exception ioe) {
MainFrame.unlockGUI();
JOptionPane.showMessageDialog(MainFrame.getInstance(), "Could not create write file:" + ioe.toString(), "GATE", JOptionPane.ERROR_MESSAGE);
ioe.printStackTrace(Err.getPrintWriter());
return;
}
listener.statusChanged(currentDoc.getName() + " saved");
// loaded
if (!docWasLoaded) {
corpus.unloadDocument(currentDoc);
Factory.deleteResource(currentDoc);
}
handle.progressChanged(100 * currentDocIndex++ / docCnt);
}
// while(docIter.hasNext())
listener.statusChanged("Corpus Saved");
handle.processFinished();
} finally {
MainFrame.unlockGUI();
}
}
}
}
};
Thread thread = new Thread(Thread.currentThread().getThreadGroup(), runnable, "Document Exporter Thread");
thread.setPriority(Thread.MIN_PRIORITY);
thread.start();
}
});
itemByResource.put(de, item);
}
use of gate.Document in project gate-core by GateNLP.
the class DocumentExportMenu method getSelectedFile.
private File getSelectedFile(List<List<Parameter>> params, DocumentExporter de, FeatureMap options) {
File selectedFile = null;
Document document = (handle.getTarget() instanceof Document ? (Document) handle.getTarget() : null);
// are we looking for a file or a directory?
boolean singleFile = (document != null) || (de instanceof CorpusExporter);
if (document != null && document.getSourceUrl() != null) {
String fileName = "";
try {
fileName = document.getSourceUrl().toURI().getPath().trim();
} catch (URISyntaxException e) {
fileName = document.getSourceUrl().getPath().trim();
}
if (fileName.equals("") || fileName.equals("/")) {
if (document.getNamedAnnotationSets().containsKey("Original markups") && !document.getAnnotations("Original markups").get("title").isEmpty()) {
// use the title annotation if any
try {
fileName = document.getContent().getContent(document.getAnnotations("Original markups").get("title").firstNode().getOffset(), document.getAnnotations("Original markups").get("title").lastNode().getOffset()).toString();
} catch (InvalidOffsetException e) {
e.printStackTrace();
}
} else {
fileName = document.getSourceUrl().toString();
}
// cleans the file name
fileName = fileName.replaceAll("/", "_");
} else {
// replaces the extension with the default
fileName = fileName.replaceAll("\\.[a-zA-Z]{1,4}$", "." + de.getDefaultExtension());
}
// cleans the file name
fileName = fileName.replaceAll("[^/a-zA-Z0-9._-]", "_");
fileName = fileName.replaceAll("__+", "_");
// adds the default extension if not present
if (!fileName.endsWith("." + de.getDefaultExtension())) {
fileName += "." + de.getDefaultExtension();
}
selectedFile = new File(fileName);
}
if (params == null || params.isEmpty()) {
XJFileChooser fileChooser = MainFrame.getFileChooser();
fileChooser.resetChoosableFileFilters();
fileChooser.setFileFilter(de.getFileFilter());
fileChooser.setMultiSelectionEnabled(false);
fileChooser.setDialogTitle("Save as " + de.getFileType());
fileChooser.setFileSelectionMode(singleFile ? JFileChooser.FILES_ONLY : JFileChooser.DIRECTORIES_ONLY);
if (selectedFile != null) {
fileChooser.ensureFileIsVisible(selectedFile);
fileChooser.setSelectedFile(selectedFile);
}
if (fileChooser.showSaveDialog(MainFrame.getInstance()) != JFileChooser.APPROVE_OPTION)
return null;
selectedFile = fileChooser.getSelectedFile();
} else {
if (!dialog.show(de, params, singleFile, selectedFile != null ? selectedFile.getAbsolutePath() : ""))
return null;
options.putAll(dialog.getSelectedParameters());
selectedFile = new File(dialog.getSelectedFileName());
}
return selectedFile;
}
Aggregations