@Override
  public void execute(GraphModel graphModel, AttributeModel attributeModel) {
    // Graph graph = graphModel.getGraphVisible();
    HierarchicalGraph graph = null;
    // get visible graph
    if (directed) {
      graph = graphModel.getHierarchicalDirectedGraphVisible();
    } else {
      graph = graphModel.getHierarchicalUndirectedGraphVisible();
    }

    // lock graph
    graph.readLock();
    try {
      Progress.start(progressTicket, graph.getNodeCount());
      // all coefficients
      nodeCoefficients = new double[graph.getNodeCount()];

      // attribute column
      AttributeTable nodeTable = attributeModel.getNodeTable();
      AttributeColumn clusteringColumn = nodeTable.getColumn("newClusteringCoefficient");
      if (clusteringColumn == null) {
        clusteringColumn =
            nodeTable.addColumn(
                "newClusteringCoefficient",
                "Local Clustering Coefficient",
                AttributeType.DOUBLE,
                AttributeOrigin.COMPUTED,
                0.0);
      }

      int i = 0;
      // for each node
      for (Node e : graph.getNodes()) {
        // compute coefficient
        double coeficient = 0.0;
        double denominator = (graph.getDegree(e) * (graph.getDegree(e) - 1));
        if (!directed) {
          denominator /= 2;
        }
        double numerator = 0.0;
        // get neighbors as list
        List<Node> n2 = Arrays.asList(graph.getNeighbors(e).toArray());
        List<Node> neighbors2 = new ArrayList<Node>(n2);
        for (Node neighbor1 : graph.getNeighbors(e)) {
          neighbors2.remove(neighbor1);
          // count edges betwwen neighbors
          for (Node neighbor2 : neighbors2) {
            if (graph.getEdge(neighbor1, neighbor2) != null
                || graph.getEdge(neighbor2, neighbor1) != null) {
              numerator++;
            }
          }
        }
        // compute coefficient
        if (denominator > 0) {
          coeficient = numerator / denominator;
        } else {
          coeficient = 0.0;
        }
        averageCoefficient += coeficient;
        nodeCoefficients[i] = coeficient;
        i++;
        // set attribute
        AttributeRow row = (AttributeRow) e.getNodeData().getAttributes();
        row.setValue(clusteringColumn, coeficient);
        Progress.progress(progressTicket);
        if (cancel) {
          break;
        }
      }
      if (graph.getNodeCount() > 0) {
        averageCoefficient = averageCoefficient / graph.getNodeCount();
      }

      graph.readUnlockAll();
    } catch (Exception e) {
      e.printStackTrace();
      // Unlock graph
      graph.readUnlockAll();
    }
  }
  public void updateWorld() {
    // System.out.println("update world");
    cacheMarker++;

    GraphModel graphModel = controller.getModel();
    if (graphModel == null) {
      engine.worldUpdated(cacheMarker);
      return;
    }
    if (gm != null && gm != graphModel) {
      reset();
    }
    gm = graphModel;
    HierarchicalGraph graph;
    if (graphModel.isDirected()) {
      undirected = false;
      graph = graphModel.getHierarchicalDirectedGraphVisible();
    } else if (graphModel.isUndirected()) {
      undirected = true;
      graph = graphModel.getHierarchicalUndirectedGraphVisible();
    } else if (graphModel.isMixed()) {
      undirected = false;
      graph = graphModel.getHierarchicalMixedGraphVisible();
    } else {
      undirected = false;
      graph = graphModel.getHierarchicalDirectedGraphVisible();
    }

    if (dynamicModel == null) {
      DynamicController dynamicController = Lookup.getDefault().lookup(DynamicController.class);
      dynamicModel = dynamicController.getModel();
    }

    graphView = graph.getView().getViewId();

    ModelClass[] object3dClasses = engine.getModelClasses();

    graph.readLock();

    ModelClass nodeClass = object3dClasses[AbstractEngine.CLASS_NODE];
    if (nodeClass.isEnabled()
        && (graph.getNodeVersion() > nodeVersion || modeManager.requireModeChange())) {
      updateNodes(graph);
      nodeClass.setCacheMarker(cacheMarker);
    }

    ModelClass edgeClass = object3dClasses[AbstractEngine.CLASS_EDGE];
    if (edgeClass.isEnabled()
        && (graph.getEdgeVersion() > edgeVersion || modeManager.requireModeChange())) {
      updateEdges(graph);
      updateMetaEdges(graph);
      edgeClass.setCacheMarker(cacheMarker);
      if (!undirected && vizConfig.isShowArrows()) {
        object3dClasses[AbstractEngine.CLASS_ARROW].setCacheMarker(cacheMarker);
      }
    }

    ModelClass potatoClass = object3dClasses[AbstractEngine.CLASS_POTATO];
    if (potatoClass.isEnabled()
        && (graph.getNodeVersion() > nodeVersion || modeManager.requireModeChange())) {
      updatePotatoes(graph);
      potatoClass.setCacheMarker(cacheMarker);
    }

    nodeVersion = graph.getNodeVersion();
    edgeVersion = graph.getEdgeVersion();

    graph.readUnlock();

    engine.worldUpdated(cacheMarker);
  }
  public boolean execute() {
    attributeModel = workspace.getLookup().lookup(AttributeModel.class);
    graphModel = workspace.getLookup().lookup(GraphModel.class);
    HierarchicalGraph graph = null;
    if (exportVisible) {
      graph = graphModel.getHierarchicalGraphVisible();
    } else {
      graph = graphModel.getHierarchicalGraph();
    }
    Progress.start(progress);
    graph.readLock();

    // Options
    if (normalize) {
      calculateMinMax(graph);
    }

    // Calculate progress units count
    int max = 0;
    if (exportHierarchy) {
      for (Node n : graph.getNodesTree()) {
        max++;
      }
      for (Edge e : graph.getEdgesTree()) {
        max++;
      }
    } else {
      max = graph.getNodeCount();
      for (Edge e : graph.getEdgesAndMetaEdges()) {
        max++;
      }
    }
    Progress.switchToDeterminate(progress, max);

    try {
      XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
      outputFactory.setProperty("javax.xml.stream.isRepairingNamespaces", Boolean.FALSE);

      XMLStreamWriter xmlWriter = outputFactory.createXMLStreamWriter(writer);
      xmlWriter = new IndentingXMLStreamWriter(xmlWriter);

      xmlWriter.writeStartDocument("UTF-8", "1.0");
      xmlWriter.setPrefix("", GEXF_NAMESPACE);
      xmlWriter.writeStartElement(GEXF_NAMESPACE, GEXF);
      xmlWriter.writeNamespace("", GEXF_NAMESPACE);
      xmlWriter.writeAttribute(GEXF_VERSION, "1.1");

      if (exportColors || exportPosition || exportSize) {
        xmlWriter.writeNamespace(VIZ, VIZ_NAMESPACE);
      }
      xmlWriter.writeAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
      xmlWriter.writeAttribute("xsi:schemaLocation", GEXF_NAMESPACE_LOCATION);

      if (exportDynamic) {
        DynamicController dynamicController = Lookup.getDefault().lookup(DynamicController.class);
        dynamicModel = dynamicController != null ? dynamicController.getModel(workspace) : null;
        visibleInterval =
            dynamicModel == null
                ? null
                : exportVisible
                    ? dynamicModel.getVisibleInterval()
                    : new TimeInterval(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
      }

      writeMeta(xmlWriter);
      writeGraph(xmlWriter, graph);

      xmlWriter.writeEndElement();
      xmlWriter.writeEndDocument();
      xmlWriter.close();

    } catch (Exception e) {
      graph.readUnlockAll();
      if (e instanceof RuntimeException) {
        throw (RuntimeException) e;
      }
      throw new RuntimeException(e);
    }

    graph.readUnlock();

    Progress.finish(progress);
    return !cancel;
  }