docs: public ByteBuffer asFlatBuffers(long graphId, @NonNull ExecutorConfiguration configuration) {
          Nd4j.getExecutioner().commit();
          val bufferBuilder = new FlatBufferBuilder(1024);
          val idCounter = new AtomicInteger(0);
  
          val flatVariables = new ArrayList<Integer>();
          val flatOffsets = new ArrayList<Integer>();
          val flatNodes = new ArrayList<Integer>();
  
          // first of all we build VariableSpace dump
          val variableList = new ArrayList<SDVariable>(variables());
          val reverseMap = new LinkedHashMap<String, Integer>();
          val forwardMap = new LinkedHashMap<String, Integer>();
          val framesMap = new LinkedHashMap<String, Integer>();
  
          int idx = 0;
          val idxForOps = new IdentityHashMap<DifferentialFunction,Integer>();
          List<SDVariable> allVars = variables();
          for (SDVariable variable : allVars) {
              INDArray arr = variable.getArr();
              log.trace("Exporting variable: [{}]", variable.getVarName());
  
              //If variable is the output of some op - let's use the ONE index for exporting, and properly track the output
              // numbers. For example, unstack(x) -> y0, y1, y2 -> the y's should be say (3,0), (3,1), (3,2) NOT (4,0), (5,0), (6,0)
              String varName = variable.getVarName();
              int varIdx;
              int outputNum;
              if(variables.get(varName).getOutputOfOp() != null){
                  //This variable is the output of a node
                  DifferentialFunction df = ops.get(variables.get(varName).getOutputOfOp()).getOp();
                  if(!idxForOps.containsKey(df)){
                      varIdx = idCounter.incrementAndGet();
                      idxForOps.put(df, varIdx);
                  } else {
                      varIdx = idxForOps.get(df);
                  }
                  String[] outNames = df.outputVariablesNames();
                  outputNum = ArrayUtils.indexOf(outNames, varName);
                  Preconditions.checkState(outputNum >= 0, "Variable name \"%s\" not found in list of outputs: %s", varName, outNames);
              } else {
                  varIdx = idCounter.incrementAndGet();
                  outputNum = 0;
              }
  
  
              reverseMap.put(variable.getVarName(), varIdx);
              log.trace("Adding [{}] as [{}]", variable.getVarName(), varIdx);
  
              int shape = 0;
              int name = bufferBuilder.createString(variable.getVarName());
              int array = arr == null ? 0 : arr.toFlatArray(bufferBuilder);
              int id = IntPair.createIntPair(bufferBuilder, varIdx, outputNum);
              byte varType = (byte)variable.getVariableType().ordinal();
  
              if (variable.getVariableType() == VariableType.PLACEHOLDER) {
                  val shp = variable.getShape();
                  shape = FlatVariable.createShapeVector(bufferBuilder, shp);
              }
  
              int flatVariable = FlatVariable.createFlatVariable(bufferBuilder, id, name,  FlatBuffersMapper.getDataTypeAsByte(variable.dataType()), shape, array, -1, varType);
              flatVariables.add(flatVariable);
          }
  
          //add functions
          for(SameDiffOp op : ops.values()){
              DifferentialFunction func = op.getOp();
              Integer fnId = idxForOps.get(func);
              flatNodes.add(asFlatNode(func, bufferBuilder, variableList, reverseMap, forwardMap, framesMap, idCounter, fnId));
          }
  
          // we're dumping scopes now
          for (Map.Entry<String, SameDiff> scope : sameDiffFunctionInstances.entrySet()) {
              if(scope.getKey().equalsIgnoreCase("grad")){
                  //Skip the gradient function for export
                  continue;
              }
  
              flatNodes.add(asFlatNode(scope.getKey(), scope.getValue(), bufferBuilder));
              val currVarList = new ArrayList<SDVariable>(scope.getValue().variables());
              // converting all ops from node
              for (val node : scope.getValue().variables()) {
                  INDArray arr = node.getArr();
                  if (arr == null) {
                      continue;
                  }
  
                  int name = bufferBuilder.createString(node.getVarName());
                  int array = arr.toFlatArray(bufferBuilder);
                  int id = IntPair.createIntPair(bufferBuilder, ++idx, 0);
  
                  val pair = parseVariable(node.getVarName());
                  reverseMap.put(pair.getFirst(), idx);
  
                  log.trace("Adding [{}] as [{}]", pair.getFirst(), idx);
  
                  byte varType = (byte)node.getVariableType().ordinal();
                  int flatVariable = FlatVariable.createFlatVariable(bufferBuilder, id, name, FlatBuffersMapper.getDataTypeAsByte(arr.dataType()),0, array, -1, varType);
                  flatVariables.add(flatVariable);
              }
  
              //add functions
              for(SameDiffOp op : scope.getValue().ops.values()){
                  DifferentialFunction func = op.getOp();
                  flatNodes.add(asFlatNode(func, bufferBuilder, currVarList, reverseMap, forwardMap, framesMap, idCounter, null));
              }
          }
  
          int outputsOffset = FlatGraph.createVariablesVector(bufferBuilder, Ints.toArray(flatOffsets));
          int variablesOffset = FlatGraph.createVariablesVector(bufferBuilder, Ints.toArray(flatVariables));
          int nodesOffset = FlatGraph.createNodesVector(bufferBuilder, Ints.toArray(flatNodes));
  
          int numPlaceholders = 0;
          for(SDVariable v : variables()){
              if(v.isPlaceHolder()){
                  numPlaceholders++;
              }
          }
  
          int[] placeholderOffsets = new int[numPlaceholders];
          if(numPlaceholders > 0){
              int i=0;
              for(SDVariable v : variables()){
                  if(!v.isPlaceHolder())
                      continue;
                  placeholderOffsets[i++] = bufferBuilder.createString(v.getVarName());
              }
          }
          int placeholdersOffset = FlatGraph.createPlaceholdersVector(bufferBuilder, placeholderOffsets);
  
          List<String> lossVars = getLossVariables();
          int[] lossVarOffsets = new int[lossVars == null ? 0 : lossVars.size()];
          for( int i=0; i<lossVarOffsets.length; i++ ){
              lossVarOffsets[i] = bufferBuilder.createString(lossVars.get(i));
          }
          int lossVarOffset = FlatGraph.createLossVariablesVector(bufferBuilder, lossVarOffsets);
  
          int fg = FlatGraph.createFlatGraph(bufferBuilder, graphId, variablesOffset, nodesOffset, outputsOffset,
                  configuration.getFlatConfiguration(bufferBuilder), placeholdersOffset, lossVarOffset);
          bufferBuilder.finish(fg);
  
          synchronized (this) {
              for(Map.Entry<String,Integer> e : reverseMap.entrySet()){
                  this.variables.get(e.getKey()).setVariableIndex(e.getValue());
              }
          }
  
          return bufferBuilder.dataBuffer();
      }