Exemplo n.º 1
0
  public AttributeControllerImpl() {
    projectController = Lookup.getDefault().lookup(ProjectController.class);
    projectController.addWorkspaceListener(
        new WorkspaceListener() {

          public void initialize(Workspace workspace) {
            AttributeModel m = workspace.getLookup().lookup(AttributeModel.class);
            if (m == null) {
              workspace.add(new IndexedAttributeModel());
            }
          }

          public void select(Workspace workspace) {}

          public void unselect(Workspace workspace) {}

          public void close(Workspace workspace) {}

          public void disable() {}
        });
    if (projectController.getCurrentProject() != null) {
      for (Workspace workspace :
          projectController
              .getCurrentProject()
              .getLookup()
              .lookup(WorkspaceProvider.class)
              .getWorkspaces()) {
        AttributeModel m = workspace.getLookup().lookup(AttributeModel.class);
        if (m == null) {
          workspace.add(new IndexedAttributeModel());
        }
      }
    }
  }
Exemplo n.º 2
0
  @Override
  public void process() {
    if (containers.length > 1) {
      throw new RuntimeException("This processor can only handle single containers");
    }
    ContainerUnloader container = containers[0];

    // Workspace
    ProjectController pc = Lookup.getDefault().lookup(ProjectController.class);
    if (workspace == null) {
      workspace = pc.newWorkspace(pc.getCurrentProject());
      pc.openWorkspace(workspace);
    }
    processConfiguration(container, workspace);

    if (container.getSource() != null) {
      pc.setSource(workspace, container.getSource());
    }

    process(container, workspace);

    // Clean
    workspace = null;
    graphModel = null;
    containers = null;
    progressTicket = null;
  }
  public void script() {
    // Init a project - and therefore a workspace
    ProjectController pc = Lookup.getDefault().lookup(ProjectController.class);
    pc.newProject();
    Workspace workspace = pc.getCurrentWorkspace();

    // Get controllers and models
    ImportController importController = Lookup.getDefault().lookup(ImportController.class);

    // Import file
    Container container;
    try {
      File file =
          new File(
              getClass().getResource("/org/gephi/toolkit/demos/resources/polblogs.gml").toURI());
      container = importController.importFile(file);
      container.getLoader().setEdgeDefault(EdgeDefault.DIRECTED); // Force DIRECTED
      container.setAllowAutoNode(false); // Don't create missing nodes
    } catch (Exception ex) {
      ex.printStackTrace();
      return;
    }

    // Append imported data to GraphAPI
    importController.process(container, new DefaultProcessor(), workspace);

    // List node columns
    AttributeController ac = Lookup.getDefault().lookup(AttributeController.class);
    AttributeModel model = ac.getModel();
    for (AttributeColumn col : model.getNodeTable().getColumns()) {
      System.out.println(col);
    }

    // Add boolean column
    AttributeColumn testCol = model.getNodeTable().addColumn("test", AttributeType.BOOLEAN);

    // Write values to nodes
    GraphModel graphModel = Lookup.getDefault().lookup(GraphController.class).getModel();
    for (Node n : graphModel.getGraph().getNodes()) {
      n.getNodeData().getAttributes().setValue(testCol.getIndex(), Boolean.TRUE);
    }

    // Iterate values - fastest
    AttributeColumn sourceCol = model.getNodeTable().getColumn("source");
    for (Node n : graphModel.getGraph().getNodes()) {
      System.out.println(n.getNodeData().getAttributes().getValue(sourceCol.getIndex()));
    }

    // Iterate values - normal
    for (Node n : graphModel.getGraph().getNodes()) {
      System.out.println(n.getNodeData().getAttributes().getValue("source"));
    }
  }
  public StatisticsControllerImpl() {
    statisticsBuilders =
        Lookup.getDefault().lookupAll(StatisticsBuilder.class).toArray(new StatisticsBuilder[0]);

    // Workspace events
    ProjectController pc = Lookup.getDefault().lookup(ProjectController.class);
    pc.addWorkspaceListener(
        new WorkspaceListener() {

          @Override
          public void initialize(Workspace workspace) {
            if (workspace.getLookup().lookup(StatisticsModelImpl.class) == null) {
              workspace.add(new StatisticsModelImpl());
            }
          }

          @Override
          public void select(Workspace workspace) {
            model = workspace.getLookup().lookup(StatisticsModelImpl.class);
            if (model == null) {
              model = new StatisticsModelImpl();
              workspace.add(model);
            }
          }

          @Override
          public void unselect(Workspace workspace) {}

          @Override
          public void close(Workspace workspace) {}

          @Override
          public void disable() {
            model = null;
          }
        });

    if (pc.getCurrentWorkspace() != null) {
      model = pc.getCurrentWorkspace().getLookup().lookup(StatisticsModelImpl.class);
      if (model == null) {
        model = new StatisticsModelImpl();
        pc.getCurrentWorkspace().add(model);
      }
    }
  }
Exemplo n.º 5
0
 public synchronized AttributeModel getModel() {
   Workspace workspace = projectController.getCurrentWorkspace();
   if (workspace != null) {
     AttributeModel model = workspace.getLookup().lookup(AttributeModel.class);
     if (model != null) {
       return model;
     }
     model = new IndexedAttributeModel();
     workspace.add(model);
     return model;
   }
   return null;
 }
Exemplo n.º 6
0
  public TimelineControllerImpl() {
    listeners = new ArrayList<TimelineModelListener>();

    // Workspace events
    ProjectController pc = Lookup.getDefault().lookup(ProjectController.class);
    dynamicController = Lookup.getDefault().lookup(DynamicController.class);

    pc.addWorkspaceListener(
        new WorkspaceListener() {

          @Override
          public void initialize(Workspace workspace) {}

          @Override
          public void select(Workspace workspace) {
            model = workspace.getLookup().lookup(TimelineModelImpl.class);
            if (model == null) {
              model = new TimelineModelImpl(dynamicController.getModel(workspace));
              workspace.add(model);
            }
            attributeModel =
                Lookup.getDefault().lookup(AttributeController.class).getModel(workspace);
            setup();
          }

          @Override
          public void unselect(Workspace workspace) {
            unsetup();
          }

          @Override
          public void close(Workspace workspace) {}

          @Override
          public void disable() {
            model = null;
            attributeModel = null;
            fireTimelineModelEvent(
                new TimelineModelEvent(TimelineModelEvent.EventType.MODEL, null, null));
          }
        });

    if (pc.getCurrentWorkspace() != null) {
      model = pc.getCurrentWorkspace().getLookup().lookup(TimelineModelImpl.class);
      if (model == null) {
        model = new TimelineModelImpl(dynamicController.getModel(pc.getCurrentWorkspace()));
        pc.getCurrentWorkspace().add(model);
      }
      attributeModel =
          Lookup.getDefault().lookup(AttributeController.class).getModel(pc.getCurrentWorkspace());
      setup();
    }
  }
Exemplo n.º 7
0
  public void script() {

    NetworkLayer nl = MultiLayerNetwork.getSelected();

    if (pc == null) pc = Lookup.getDefault().lookup(ProjectController.class);

    // Init a project - and therefore a workspace
    Project pro = pc.getCurrentProject();

    if (pro == null) {
      pc.newProject();
      pro = pc.getCurrentProject();
    }

    Workspace workspace = pc.newWorkspace(pro);

    // Get controllers and models
    ImportController importController = Lookup.getDefault().lookup(ImportController.class);
    GraphModel graphModel =
        Lookup.getDefault().lookup(GraphController.class).getGraphModel(workspace);
    //        AttributeModel attributeModel =
    // Lookup.getDefault().lookup(AttributeController.class).getModel();

    // Import database
    EdgeListHiveDatabaseImpl db = new EdgeListHiveDatabaseImpl();

    db.setDBName("default"); // !!!
    db.setHost("127.0.0.1");
    //       db.setHost( HadoopClusterDefaults.HIVE_SERVER_IP );
    db.setPort(10000); // !!!

    db.setUsername("kamir");
    db.setPasswd("8cwrr");

    db.setSQLDriver(new HiveJDBCDriver());

    String tab = "edgelist_es_de_erfurt2";

    db.setNodeQuery(
        "SELECT UNIQUE( " + tab + ".source ) AS id, " + tab + ".source AS label FROM " + tab);
    db.setEdgeQuery(
        "SELECT "
            + tab
            + ".source AS source, "
            + tab
            + ".target AS target "
            + tab
            + ".q0 AS weight FROM "
            + tab);

    ImporterEdgeList edgeListImporter = new ImporterEdgeList();

    Container container = null;

    String url = SQLUtils.getUrl(db.getSQLDriver(), db.getHost(), db.getPort(), db.getDBName());

    System.out.println(url);

    javax.swing.JOptionPane.showMessageDialog(null, "Go ... Hive! \n> " + url);

    try {
      container = importController.importDatabase(db, edgeListImporter);

      //            container.setAllowAutoNode(false);      //Don't create missing nodes
      container.getLoader().setEdgeDefault(EdgeDirectionDefault.UNDIRECTED); // Force UNDIRECTED

      // Append imported data to GraphAPI
      importController.process(container, new DefaultProcessor(), workspace);
    } catch (Exception ex) {
      ex.printStackTrace();
    } finally {
      if (container != null) System.out.println(container.getReport().getText());
    }

    // See if graph is well imported
    UndirectedGraph graph = graphModel.getUndirectedGraph();
    System.out.println("Nodes: " + graph.getNodeCount());
    System.out.println("Edges: " + graph.getEdgeCount());

    // Layout - 100 Yifan Hu passes
    //        YifanHuLayout layout = new YifanHuLayout(null, new StepDisplacement(1f));
    //        layout.setGraphModel(graphModel);
    //        layout.resetPropertiesValues();
    //        layout.initAlgo();
    //        for (int i = 0; i < 100 && layout.canAlgo(); i++) {
    //            layout.goAlgo();
    //        }
    //        layout.endAlgo();

  }
  private void finishImport(Container[] containers) {
    Report finalReport = new Report();
    for (Container container : containers) {
      if (container.verify()) {
        Report report = container.getReport();
        report.close();
        finalReport.append(report);
      } else {
        // TODO
      }
    }
    finalReport.close();

    // Report panel
    ReportPanel reportPanel = new ReportPanel();
    reportPanel.setData(finalReport, containers);
    DialogDescriptor dd =
        new DialogDescriptor(
            reportPanel, NbBundle.getMessage(DesktopImportControllerUI.class, "ReportPanel.title"));
    Object response = DialogDisplayer.getDefault().notify(dd);
    reportPanel.destroy();
    finalReport.clean();
    for (Container c : containers) {
      c.getReport().clean();
    }
    if (!response.equals(NotifyDescriptor.OK_OPTION)) {
      return;
    }
    final Processor processor = reportPanel.getProcessor();

    // Project
    Workspace workspace = null;
    ProjectController pc = Lookup.getDefault().lookup(ProjectController.class);
    ProjectControllerUI pcui = Lookup.getDefault().lookup(ProjectControllerUI.class);
    if (pc.getCurrentProject() == null) {
      pcui.newProject();
      workspace = pc.getCurrentWorkspace();
    }

    // Process
    final ProcessorUI pui = getProcessorUI(processor);
    final ValidResult validResult = new ValidResult();
    if (pui != null) {
      try {
        final JPanel panel = pui.getPanel();
        if (panel != null) {
          SwingUtilities.invokeAndWait(
              new Runnable() {
                @Override
                public void run() {
                  String title =
                      NbBundle.getMessage(
                          DesktopImportControllerUI.class,
                          "DesktopImportControllerUI.processor.ui.dialog.title");

                  pui.setup(processor);
                  final DialogDescriptor dd2 = new DialogDescriptor(panel, title);
                  if (panel instanceof ValidationPanel) {
                    ValidationPanel vp = (ValidationPanel) panel;
                    vp.addChangeListener(
                        new ChangeListener() {
                          @Override
                          public void stateChanged(ChangeEvent e) {
                            dd2.setValid(!((ValidationPanel) e.getSource()).isProblem());
                          }
                        });
                    dd2.setValid(!vp.isProblem());
                  }
                  Object result = DialogDisplayer.getDefault().notify(dd2);
                  if (result.equals(NotifyDescriptor.CANCEL_OPTION)
                      || result.equals(NotifyDescriptor.CLOSED_OPTION)) {
                    validResult.setResult(false);
                  } else {
                    pui.unsetup(); // true
                    validResult.setResult(true);
                  }
                }
              });
        }
      } catch (InterruptedException ex) {
        Exceptions.printStackTrace(ex);
      } catch (InvocationTargetException ex) {
        Exceptions.printStackTrace(ex);
      }
    }
    if (validResult.isResult()) {
      controller.process(containers, processor, workspace);

      // StatusLine notify
      StatusDisplayer.getDefault()
          .setStatusText(
              NbBundle.getMessage(
                  DesktopImportControllerUI.class,
                  "DesktopImportControllerUI.status.multiImportSuccess",
                  containers.length));
    }
  }
Exemplo n.º 9
0
  public void process() {
    // Workspace
    ProjectController pc = Lookup.getDefault().lookup(ProjectController.class);
    if (workspace == null) {
      workspace = pc.newWorkspace(pc.getCurrentProject());
      pc.openWorkspace(workspace);
    }
    if (container.getSource() != null) {
      pc.setSource(workspace, container.getSource());
    }

    // Architecture
    GraphModel graphModel = Lookup.getDefault().lookup(GraphController.class).getModel(workspace);

    HierarchicalGraph graph = null;
    switch (container.getEdgeDefault()) {
      case DIRECTED:
        graph = graphModel.getHierarchicalDirectedGraph();
        break;
      case UNDIRECTED:
        graph = graphModel.getHierarchicalUndirectedGraph();
        break;
      case MIXED:
        graph = graphModel.getHierarchicalMixedGraph();
        break;
      default:
        graph = graphModel.getHierarchicalMixedGraph();
        break;
    }
    GraphFactory factory = graphModel.factory();

    // Attributes - Creates columns for properties
    attributeModel = Lookup.getDefault().lookup(AttributeController.class).getModel(workspace);
    attributeModel.mergeModel(container.getAttributeModel());

    // Dynamic
    if (container.getTimeFormat() != null) {
      DynamicController dynamicController = Lookup.getDefault().lookup(DynamicController.class);
      if (dynamicController != null) {
        dynamicController.setTimeFormat(container.getTimeFormat());
      }
    }

    int nodeCount = 0;
    // Create all nodes
    for (NodeDraftGetter draftNode : container.getNodes()) {
      Node n = factory.newNode(draftNode.isAutoId() ? null : draftNode.getId());
      flushToNode(draftNode, n);
      draftNode.setNode(n);
      nodeCount++;
    }

    // Push nodes in data structure
    for (NodeDraftGetter draftNode : container.getNodes()) {
      Node n = draftNode.getNode();
      NodeDraftGetter[] parents = draftNode.getParents();
      if (parents != null) {
        for (int i = 0; i < parents.length; i++) {
          Node parent = parents[i].getNode();
          graph.addNode(n, parent);
        }
      } else {
        graph.addNode(n);
      }
    }

    // Create all edges and push to data structure
    int edgeCount = 0;
    for (EdgeDraftGetter edge : container.getEdges()) {
      Node source = edge.getSource().getNode();
      Node target = edge.getTarget().getNode();
      Edge e = null;
      switch (container.getEdgeDefault()) {
        case DIRECTED:
          e =
              factory.newEdge(
                  edge.isAutoId() ? null : edge.getId(), source, target, edge.getWeight(), true);
          break;
        case UNDIRECTED:
          e =
              factory.newEdge(
                  edge.isAutoId() ? null : edge.getId(), source, target, edge.getWeight(), false);
          break;
        case MIXED:
          e =
              factory.newEdge(
                  edge.isAutoId() ? null : edge.getId(),
                  source,
                  target,
                  edge.getWeight(),
                  edge.getType().equals(EdgeType.UNDIRECTED) ? false : true);
          break;
      }

      flushToEdge(edge, e);
      edgeCount++;
      graph.addEdge(e);
    }
    workspace = null;
  }
Exemplo n.º 10
0
  public PreviewUIControllerImpl() {
    listeners = new ArrayList<PropertyChangeListener>();
    ProjectController pc = Lookup.getDefault().lookup(ProjectController.class);
    graphController = Lookup.getDefault().lookup(GraphController.class);
    pc.addWorkspaceListener(
        new WorkspaceListener() {

          public void initialize(Workspace workspace) {
            workspace.add(new PreviewUIModelImpl());
            enableRefresh();
          }

          public void select(Workspace workspace) {
            // Make sure AttributeModel is created before graph model:
            Lookup.getDefault().lookup(AttributeController.class).getModel();

            graphModel = graphController.getModel();
            graphModel.addGraphListener(PreviewUIControllerImpl.this);

            model = workspace.getLookup().lookup(PreviewUIModelImpl.class);
            if (model == null) {
              model = new PreviewUIModelImpl();
              workspace.add(model);
            }
            fireEvent(SELECT, model);
          }

          public void unselect(Workspace workspace) {
            if (graphModel != null) {
              graphModel.removeGraphListener(PreviewUIControllerImpl.this);
              graphModel = null;
            }
            fireEvent(UNSELECT, model);
          }

          public void close(Workspace workspace) {}

          public void disable() {
            if (graphModel != null) {
              graphModel.removeGraphListener(PreviewUIControllerImpl.this);
              graphModel = null;
            }
            fireEvent(SELECT, null);
            model = null;
          }
        });
    if (pc.getCurrentWorkspace() != null) {
      model = pc.getCurrentWorkspace().getLookup().lookup(PreviewUIModelImpl.class);
      if (model == null) {
        model = new PreviewUIModelImpl();
        pc.getCurrentWorkspace().add(model);
      }
      graphModel = graphController.getModel();
      graphModel.addGraphListener(this);
    }

    previewController = Lookup.getDefault().lookup(PreviewController.class);

    // Register editors
    // Overriding default Preview API basic editors that don't support CustomEditor
    PropertyEditorManager.registerEditor(EdgeColor.class, EdgeColorPropertyEditor.class);
    PropertyEditorManager.registerEditor(
        DependantOriginalColor.class, DependantOriginalColorPropertyEditor.class);
    PropertyEditorManager.registerEditor(DependantColor.class, DependantColorPropertyEditor.class);
  }
 @Override
 public void actionPerformed(ActionEvent e) {
   ProjectController pc = Lookup.getDefault().lookup(ProjectController.class);
   pc.newWorkspace(project);
 }
Exemplo n.º 12
0
  @Test
  public void testPNG() {
    try {

      // Init a project - and therefore a workspace
      ProjectController pc = Lookup.getDefault().lookup(ProjectController.class);
      pc.newProject();
      Workspace workspace = pc.getCurrentWorkspace();

      // Append container to graph structure
      String sample = "/org/gephi/desktop/welcome/samples/Les Miserables.gexf";
      final InputStream stream = WelcomeTopComponent.class.getResourceAsStream(sample);
      ImportController importController = Lookup.getDefault().lookup(ImportController.class);
      FileImporter fileImporter = importController.getFileImporter(".gexf");
      Container container = importController.importFile(stream, fileImporter);

      importController.process(container, new DefaultProcessor(), workspace);

      // Add self loop
      GraphController graphController = Lookup.getDefault().lookup(GraphController.class);
      Graph graph = graphController.getModel().getGraph();
      Node node = graph.getNode(12);
      System.out.println("Self loop " + node.getNodeData().getLabel());
      graph.addEdge(graphController.getModel().factory().newEdge(node, node, 31, true));

      // Set label edges
      for (Edge edge : graphController.getModel().getGraph().getEdges()) {
        edge.getEdgeData().setLabel("Label test");
      }

      // svg document

      // attribute ???
      AttributeController attributeController =
          Lookup.getDefault().lookup(AttributeController.class);
      AttributeModel attributeModel = null;

      // preview
      PreviewController previewController = Lookup.getDefault().lookup(PreviewController.class);
      PreviewModel previewModel = previewController.getModel(workspace);
      PreviewProperties previewProperties = previewModel.getProperties();
      previewController.refreshPreview(workspace);

      previewModel.getProperties().putValue("width", 1000);
      previewModel.getProperties().putValue("height", 1000);
      ProcessingTarget target =
          (ProcessingTarget)
              previewController.getRenderTarget(RenderTarget.PROCESSING_TARGET, workspace);

      previewProperties.putValue(LegendModel.LEGEND_PROPERTIES, new LegendModel(workspace));

      LegendModel legendManager = previewProperties.getValue(LegendModel.LEGEND_PROPERTIES);
      Integer itemIndex = legendManager.getCurrentIndex();

      // creating item
      Item item = addGroupsItem(itemIndex, graph, attributeModel);
      //            Item item = addTextItem(itemIndex, graph, attributeModel);

      // add item
      LegendController.getInstance().addItemToLegendModel(workspace, item);

      // render
      previewController.refreshPreview(workspace);
      previewController.render(target);

      File fileToSave = new File("/Volumes/edubecks/edubecks/Untitled.png");
      OutputStream fos = new FileOutputStream(fileToSave);
      Writer writer = new OutputStreamWriter(fos, "UTF-8");

      //            // saving
      //            int width = 1000;
      //            int height = 1000;
      //            PGraphicsJava2D pg2 = (PGraphicsJava2D) target.getGraphics();
      //            BufferedImage img = new BufferedImage(width, height,
      // BufferedImage.TYPE_INT_ARGB);
      //
      //            System.out.println("@Var: pg2.pixels: "+pg2.pixels);
      //            img.setRGB(0, 0, width, height, pg2.pixels, 0, width);
      //            ImageIO.write(img, "png", fileToSave);
      //            stream.close();

      PNGExporter pngExporter = new PNGExporter();
      //            pngExporter.setHeight(2000);
      //            pngExporter.setWidth(2000);
      pngExporter.setWorkspace(workspace);
      pngExporter.setOutputStream(fos);
      pngExporter.execute();

    } catch (Exception e) {
      Exceptions.printStackTrace(e);
    }
  }
Exemplo n.º 13
0
  private void doPoetGraph(String path, String poet) {
    System.out.println(poet);
    ProjectController pc = Lookup.getDefault().lookup(ProjectController.class);
    pc.newProject();
    Workspace workspace = pc.getCurrentWorkspace();
    GraphModel graphModel = Lookup.getDefault().lookup(GraphController.class).getModel();
    UndirectedGraph directedGraph = graphModel.getUndirectedGraph();

    ExportController ec = Lookup.getDefault().lookup(ExportController.class);

    ArrayList<String> queue = new ArrayList<String>();
    ArrayList<Integer> depthqueue = new ArrayList<Integer>();
    queue.add(poet);
    depthqueue.add(0);
    int depth = 0;
    int nodecount = 0;

    while (queue.size() != 0 && depth < 3 && nodecount < 20) {
      String name = queue.remove(0);
      depth = depthqueue.remove(0);

      Node n = directedGraph.getNode(name);
      if (n == null) {
        n = graphModel.factory().newNode(name);
        n.getNodeData().setLabel(name);
        directedGraph.addNode(n);
        nodecount++;
      }

      Iterator<String> it = edges.get(poet).keySet().iterator();
      while (it.hasNext()) {
        String to = it.next();
        Node slave = directedGraph.getNode(to);
        if (slave == null) {
          slave = graphModel.factory().newNode(to);
          slave.getNodeData().setLabel(to);
          directedGraph.addNode(slave);
        }
        Edge e = graphModel.factory().newEdge(n, slave, edges.get(poet).get(to) * 15, false);
        directedGraph.addEdge(e);
        queue.add(to);
        depthqueue.add(depth + 1);
      }
    }

    // Preview
    PreviewModel previewModel = Lookup.getDefault().lookup(PreviewController.class).getModel();
    previewModel.getProperties().putValue(PreviewProperty.SHOW_NODE_LABELS, Boolean.TRUE);
    previewModel.getProperties().putValue(PreviewProperty.EDGE_COLOR, new EdgeColor(Color.BLUE));
    previewModel.getProperties().putValue(PreviewProperty.EDGE_THICKNESS, new Float(0.005f));
    previewModel
        .getProperties()
        .putValue(PreviewProperty.NODE_LABEL_COLOR, new DependantOriginalColor(Color.RED));
    previewModel
        .getProperties()
        .putValue(
            PreviewProperty.NODE_LABEL_FONT,
            previewModel
                .getProperties()
                .getFontValue(PreviewProperty.NODE_LABEL_FONT)
                .deriveFont(12));

    YifanHuLayout layout = new YifanHuLayout(null, new StepDisplacement(1f));
    layout.setGraphModel(graphModel);
    layout.resetPropertiesValues();
    layout.setOptimalDistance(120f);

    layout.initAlgo();
    for (int i = 0; i < 100 && layout.canAlgo(); i++) {
      layout.goAlgo();
    }

    try {
      ec.exportFile(new File(path + poet + ".svg"));
    } catch (IOException ex) {
      ex.printStackTrace();
      return;
    }
  }