@NotNull
 public static IpnbFile parseIpnbFile(
     @NotNull final CharSequence fileText, @NotNull final VirtualFile virtualFile)
     throws IOException {
   final String path = virtualFile.getPath();
   IpnbFileRaw rawFile = gson.fromJson(fileText.toString(), IpnbFileRaw.class);
   if (rawFile == null) {
     int nbformat = isIpythonNewFormat(virtualFile) ? 4 : 3;
     return new IpnbFile(Collections.emptyMap(), nbformat, Lists.newArrayList(), path);
   }
   List<IpnbCell> cells = new ArrayList<IpnbCell>();
   final IpnbWorksheet[] worksheets = rawFile.worksheets;
   if (worksheets == null) {
     for (IpnbCellRaw rawCell : rawFile.cells) {
       cells.add(rawCell.createCell());
     }
   } else {
     for (IpnbWorksheet worksheet : worksheets) {
       final List<IpnbCellRaw> rawCells = worksheet.cells;
       for (IpnbCellRaw rawCell : rawCells) {
         cells.add(rawCell.createCell());
       }
     }
   }
   return new IpnbFile(rawFile.metadata, rawFile.nbformat, cells, path);
 }
  @Nullable
  public static String newDocumentText(@NotNull final IpnbFilePanel ipnbPanel) {
    final IpnbFile ipnbFile = ipnbPanel.getIpnbFile();
    if (ipnbFile == null) return null;
    for (IpnbEditablePanel panel : ipnbPanel.getIpnbPanels()) {
      if (panel.isModified()) {
        panel.updateCellSource();
      }
    }

    final IpnbFileRaw fileRaw = new IpnbFileRaw();
    fileRaw.metadata = ipnbFile.getMetadata();
    if (ipnbFile.getNbformat() == 4) {
      for (IpnbCell cell : ipnbFile.getCells()) {
        fileRaw.cells.add(IpnbCellRaw.fromCell(cell, ipnbFile.getNbformat()));
      }
    } else {
      final IpnbWorksheet worksheet = new IpnbWorksheet();
      worksheet.cells.clear();
      for (IpnbCell cell : ipnbFile.getCells()) {
        worksheet.cells.add(IpnbCellRaw.fromCell(cell, ipnbFile.getNbformat()));
      }
      fileRaw.worksheets = new IpnbWorksheet[] {worksheet};
    }
    final StringWriter stringWriter = new StringWriter();
    final JsonWriter writer = new JsonWriter(stringWriter);
    writer.setIndent(" ");
    gson.toJson(fileRaw, fileRaw.getClass(), writer);
    return stringWriter.toString();
  }
    @Override
    public IpnbCellRaw deserialize(
        JsonElement json, Type typeOfT, JsonDeserializationContext context)
        throws JsonParseException {
      final JsonObject object = json.getAsJsonObject();
      final IpnbCellRaw cellRaw = new IpnbCellRaw();
      final JsonElement cell_type = object.get("cell_type");
      if (cell_type != null) {
        cellRaw.cell_type = cell_type.getAsString();
      }
      final JsonElement count = object.get("execution_count");
      if (count != null) {
        cellRaw.execution_count = count.isJsonNull() ? null : count.getAsInt();
      }
      final JsonElement metadata = object.get("metadata");
      if (metadata != null) {
        cellRaw.metadata = gson.fromJson(metadata, Map.class);
      }
      final JsonElement level = object.get("level");
      if (level != null) {
        cellRaw.level = level.getAsInt();
      }

      final JsonElement outputsElement = object.get("outputs");
      if (outputsElement != null) {
        final JsonArray outputs = outputsElement.getAsJsonArray();
        cellRaw.outputs = Lists.newArrayList();
        for (JsonElement output : outputs) {
          cellRaw.outputs.add(gson.fromJson(output, CellOutputRaw.class));
        }
      }
      cellRaw.source = getStringOrArray("source", object);
      cellRaw.input = getStringOrArray("input", object);
      final JsonElement language = object.get("language");
      if (language != null) {
        cellRaw.language = language.getAsString();
      }
      final JsonElement number = object.get("prompt_number");
      if (number != null) {
        cellRaw.prompt_number = number.getAsInt();
      }
      return cellRaw;
    }
 public static IpnbCellRaw fromCell(@NotNull final IpnbCell cell, int nbformat) {
   final IpnbCellRaw raw = new IpnbCellRaw();
   if (cell instanceof IpnbEditableCell) {
     raw.metadata = ((IpnbEditableCell) cell).getMetadata();
   }
   if (cell instanceof IpnbMarkdownCell) {
     raw.cell_type = "markdown";
     raw.source = ((IpnbMarkdownCell) cell).getSource();
   } else if (cell instanceof IpnbCodeCell) {
     raw.cell_type = "code";
     final ArrayList<CellOutputRaw> outputRaws = new ArrayList<CellOutputRaw>();
     for (IpnbOutputCell outputCell : ((IpnbCodeCell) cell).getCellOutputs()) {
       outputRaws.add(CellOutputRaw.fromOutput(outputCell, nbformat));
     }
     raw.outputs = outputRaws;
     final Integer promptNumber = ((IpnbCodeCell) cell).getPromptNumber();
     if (nbformat == 4) {
       raw.execution_count = promptNumber != null && promptNumber >= 0 ? promptNumber : null;
       raw.source = ((IpnbCodeCell) cell).getSource();
     } else {
       raw.prompt_number = promptNumber != null && promptNumber >= 0 ? promptNumber : null;
       raw.language = ((IpnbCodeCell) cell).getLanguage();
       raw.input = ((IpnbCodeCell) cell).getSource();
     }
   } else if (cell instanceof IpnbRawCell) {
     raw.cell_type = "raw";
     raw.source = ((IpnbRawCell) cell).getSource();
   } else if (cell instanceof IpnbHeadingCell) {
     raw.cell_type = "heading";
     raw.source = ((IpnbHeadingCell) cell).getSource();
     raw.level = ((IpnbHeadingCell) cell).getLevel();
   }
   return raw;
 }