diff --git a/src/org/ntlab/deltaExtractor/DeltaExtractorJSON.java b/src/org/ntlab/deltaExtractor/DeltaExtractorJSON.java index d0f63f1..c850afe 100644 --- a/src/org/ntlab/deltaExtractor/DeltaExtractorJSON.java +++ b/src/org/ntlab/deltaExtractor/DeltaExtractorJSON.java @@ -71,9 +71,12 @@ // �I�u�W�F�N�g���Ăяo���̂Ƃ��݈̂�U�폜���A�Ăяo�����̒T���𑱂���ۂɕ��������� removeList.add(thisObjectId); // ��ň�U�AthisObject ����菜�� isTrackingThis = true; // �Ăяo�����T���O�ɕ��� + // �I�u�W�F�N�g���Ăяo���̂Ƃ���1�i��3�̋t�j + aliasCollector.addAlias(new Alias(Alias.AliasType.RECEIVER, 0, childMethodExecution.getThisObjId(), tracePoint.duplicate())); + } else if (!childMethodExecution.isConstructor()) { + // �I�u�W�F�N�g�ԌĂяo���ŌĂяo���悪�R���X�g���N�^�łȂ��ꍇ��2�i��3�̋t�j + aliasCollector.addAlias(new Alias(Alias.AliasType.RECEIVER, 0, childMethodExecution.getThisObjId(), tracePoint.duplicate())); } - - aliasCollector.addAlias(new Alias(Alias.AliasType.RECEIVER, 0, childMethodExecution.getThisObjId(), tracePoint.duplicate())); } if (childMethodExecution != null) { @@ -92,6 +95,11 @@ removeList.add(childMethodExecution.getThisObjId()); existsInFields++; removeList.add(thisObjectId); // ��ň�U�AthisObject ����菜�� + if (!thisObjectId.equals(childMethodExecution.getThisObjId())) { + // �Ăяo���悪�R���X�g���N�^�ŁA�I�u�W�F�N�g�ԌĂяo���̎���3�i��1�A��2�̋t�j +// aliasList.put(childMethodExecution.getThisObjId(), new Alias(Alias.AliasType.RECEIVER, 0, childMethodExecution.getThisObjId(), tracePoint.duplicate())); + aliasList.put(childMethodExecution.getThisObjId(), new Alias(Alias.AliasType.CONSTRACTOR_INVOCATION, 0, childMethodExecution.getThisObjId(), tracePoint.duplicate())); + } } } diff --git a/src/org/ntlab/deltaViewer/CollaborationViewer.java b/src/org/ntlab/deltaViewer/CollaborationViewer.java index 1db4730..a4978e8 100644 --- a/src/org/ntlab/deltaViewer/CollaborationViewer.java +++ b/src/org/ntlab/deltaViewer/CollaborationViewer.java @@ -112,7 +112,7 @@ } } doAnimation(curFrame, numFrame); - } else if (curFrameAlias != null && numFrameAlias == null) { + } else if (curFrameAlias != null && numFrameAlias == null && curFrameAlias.getTimeStamp() < relatedPoints.get(relatedPoints.size() - 1).getStatement().getTimeStamp()) { System.out.println("\r\nLast Animation."); doLastAnimation(numFrame, relatedPoints.get(relatedPoints.size() - 1)); } else { diff --git a/src/org/ntlab/deltaViewer/DeltaViewerSample.java b/src/org/ntlab/deltaViewer/DeltaViewerSample.java index efe0dea..26238cd 100644 --- a/src/org/ntlab/deltaViewer/DeltaViewerSample.java +++ b/src/org/ntlab/deltaViewer/DeltaViewerSample.java @@ -10,7 +10,7 @@ // Build a frame, create a graph, and add the graph to the frame so you can actually see the graph. MagnetRONFrame frame = new MagnetRONFrame(); frame.setVisible(true); - frame.startAll(); +// frame.startAll(); } } diff --git a/src/org/ntlab/deltaViewer/MagnetRONFrame.java b/src/org/ntlab/deltaViewer/MagnetRONFrame.java index 6aa0cdb..42a3f13 100644 --- a/src/org/ntlab/deltaViewer/MagnetRONFrame.java +++ b/src/org/ntlab/deltaViewer/MagnetRONFrame.java @@ -3,9 +3,15 @@ import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.HeadlessException; +import java.io.BufferedReader; import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; import java.util.AbstractMap; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -19,8 +25,13 @@ import org.ntlab.deltaExtractor.ExtractedStructure; import org.ntlab.deltaExtractor.IAliasCollector; import org.ntlab.deltaExtractor.IAliasTracker; +import org.ntlab.featureExtractor.ExpectedExtracts; +import org.ntlab.featureExtractor.ExpectedFeatures; +import org.ntlab.featureExtractor.ExpectedLeftCurlyBraket; +import org.ntlab.featureExtractor.ExpectedRightCurlyBraket; import org.ntlab.featureExtractor.Extract; import org.ntlab.featureExtractor.Feature; +import org.ntlab.featureExtractor.MagnetronParser; import org.ntlab.trace.MethodExecution; import org.ntlab.trace.ObjectReference; import org.ntlab.trace.Reference; @@ -107,7 +118,24 @@ @Override public List open(File file) { - return null; + try { + BufferedReader reader = new BufferedReader(new FileReader(file)); + Map magnetJson = MagnetronParser.doParse(reader); + reader.close(); + if (magnetJson.get("trace") != null) { + trace = new TraceJSON(file.getParent() + "\\" + magnetJson.get("trace")); + s = new DeltaExtractorJSON(trace); + if (magnetJson.get("features") != null) { + features = (List) magnetJson.get("features"); + menuBar.updateExtractsMenu(features); + } + } + } catch (IOException e) { + e.printStackTrace(); + } catch (ExpectedLeftCurlyBraket | ExpectedRightCurlyBraket | ExpectedFeatures | ExpectedExtracts e) { + e.printStackTrace(); + } + return features; } @Override @@ -120,6 +148,7 @@ private Entry extractMulti(Feature feature) { CollaborationObjectCallGraph cocg = null; CollaborationAliasCollector cac = null; + Map> newToOldMethodExecMap = new HashMap<>(); for(Extract extract: feature.getExtracts()) { Map.Entry extracted = extract(extract); @@ -128,12 +157,16 @@ } else { cocg.merge(extracted.getKey()); } + IAliasCollector ac = extracted.getValue(); + DeltaAliasCollector dac = (DeltaAliasCollector) ac; + newToOldMethodExecMap.putAll(dac.shrink()); if (cac == null) { - cac = new CollaborationAliasCollector(extracted.getValue()); + cac = new CollaborationAliasCollector(dac); } else { - cac.merge(extracted.getValue()); + cac.merge(dac); } } + cocg.shrinkAll(newToOldMethodExecMap); return new AbstractMap.SimpleEntry(cocg, cac); } @@ -180,7 +213,7 @@ } private Entry extract(Extract extract) { - if (extract.getType() == Extract.CONTAINER_COMPONENT || extract.getType() == Extract.CONTAINER_COMPONENT_COLLECTION) { + if (extract.getType().equals(Extract.CONTAINER_COMPONENT) || extract.getType().equals(Extract.CONTAINER_COMPONENT_COLLECTION)) { HashMap threads = trace.getAllThreads(); List eList = new ArrayList<>(); @@ -197,7 +230,7 @@ for (ThreadInstance thread: threads.values()) { TracePoint tp = thread.getRoot().get(thread.getRoot().size() - 1).getExitPoint(); Reference reference = new Reference(extract.getSrcId(), extract.getDstId(), extract.getSrcClass(), extract.getDstClass()); - if (extract.getType() == Extract.CONTAINER_COMPONENT_COLLECTION) { + if (extract.getType().equals(Extract.CONTAINER_COMPONENT_COLLECTION)) { reference.setCollection(true); } // reference.setArray(true); @@ -321,7 +354,7 @@ // } long time = System.nanoTime(); - if (argsMap.get(argsKey)[5] == Extract.CONTAINER_COMPONENT || argsMap.get(argsKey)[5] == Extract.CONTAINER_COMPONENT_COLLECTION) { + if (argsMap.get(argsKey)[5].equals(Extract.CONTAINER_COMPONENT) || argsMap.get(argsKey)[5].equals(Extract.CONTAINER_COMPONENT_COLLECTION)) { HashMap threads = trace.getAllThreads(); List eList = new ArrayList<>(); @@ -338,7 +371,7 @@ for (ThreadInstance thread: threads.values()) { TracePoint tp = thread.getRoot().get(thread.getRoot().size() - 1).getExitPoint(); Reference reference = new Reference(argsMap.get(argsKey)[0], argsMap.get(argsKey)[1], argsMap.get(argsKey)[2], argsMap.get(argsKey)[3]); - if (argsMap.get(argsKey)[5] == Extract.CONTAINER_COMPONENT_COLLECTION) { + if (argsMap.get(argsKey)[5].equals(Extract.CONTAINER_COMPONENT_COLLECTION)) { reference.setCollection(true); } // reference.setArray(true); diff --git a/src/org/ntlab/deltaViewer/MagnetRONMenuBar.java b/src/org/ntlab/deltaViewer/MagnetRONMenuBar.java index 83f370f..1e330cc 100644 --- a/src/org/ntlab/deltaViewer/MagnetRONMenuBar.java +++ b/src/org/ntlab/deltaViewer/MagnetRONMenuBar.java @@ -1,23 +1,31 @@ package org.ntlab.deltaViewer; +import java.util.List; + import javax.swing.JMenu; import javax.swing.JMenuBar; +import org.ntlab.actions.ExtractAction; import org.ntlab.actions.OpenAction; import org.ntlab.actions.StartAnimationAction; import org.ntlab.actions.StopAnimationAction; import org.ntlab.actions.ZoomInAction; import org.ntlab.actions.ZoomOutAction; +import org.ntlab.featureExtractor.Feature; import org.ntlab.actions.ZoomActualAction; public class MagnetRONMenuBar extends JMenuBar { + private MagnetRONFrame magnetRON; + private JMenu extractsMenu; public MagnetRONMenuBar(MagnetRONFrame magnetRON) { super(); + this.magnetRON = magnetRON; + JMenu fileMenu = add(new JMenu("�t�@�C��")); fileMenu.add(new OpenAction(magnetRON)); - JMenu extractsMenu = add(new JMenu("�@�\���o")); + extractsMenu = add(new JMenu("�@�\���o")); JMenu animationSettingMenu = add(new JMenu("�A�j���[�V�����ݒ�")); @@ -31,5 +39,11 @@ animationMenu.add(new StopAnimationAction(magnetRON)); } + public void updateExtractsMenu(List features) { + extractsMenu.removeAll(); + for (Feature feature: features) { + extractsMenu.add(new ExtractAction(feature, magnetRON)); + } + } } diff --git a/src/org/ntlab/deltaViewer/MagnetRONViewer.java b/src/org/ntlab/deltaViewer/MagnetRONViewer.java index 597bbea..19d0852 100644 --- a/src/org/ntlab/deltaViewer/MagnetRONViewer.java +++ b/src/org/ntlab/deltaViewer/MagnetRONViewer.java @@ -81,6 +81,13 @@ public mxGraphComponent getGraphComponent() { return mxgraphComponent; } + + public void clear() { + objectToVertexMap.clear(); + methodExecToVertexMap.clear(); + edgeMap.clear(); + mxgraph.removeCells(mxgraph.getSelectionModel().getCells(), false); + } abstract public void initAnimation(); diff --git a/src/org/ntlab/featureExtractor/ExpectedExtracts.java b/src/org/ntlab/featureExtractor/ExpectedExtracts.java new file mode 100644 index 0000000..120cdea --- /dev/null +++ b/src/org/ntlab/featureExtractor/ExpectedExtracts.java @@ -0,0 +1,5 @@ +package org.ntlab.featureExtractor; + +public class ExpectedExtracts extends Exception { + +} diff --git a/src/org/ntlab/featureExtractor/ExpectedFeatures.java b/src/org/ntlab/featureExtractor/ExpectedFeatures.java new file mode 100644 index 0000000..82f6a84 --- /dev/null +++ b/src/org/ntlab/featureExtractor/ExpectedFeatures.java @@ -0,0 +1,5 @@ +package org.ntlab.featureExtractor; + +public class ExpectedFeatures extends Exception { + +} diff --git a/src/org/ntlab/featureExtractor/ExpectedLeftCurlyBraket.java b/src/org/ntlab/featureExtractor/ExpectedLeftCurlyBraket.java new file mode 100644 index 0000000..b1fd16f --- /dev/null +++ b/src/org/ntlab/featureExtractor/ExpectedLeftCurlyBraket.java @@ -0,0 +1,5 @@ +package org.ntlab.featureExtractor; + +public class ExpectedLeftCurlyBraket extends Exception { + +} diff --git a/src/org/ntlab/featureExtractor/ExpectedRightCurlyBraket.java b/src/org/ntlab/featureExtractor/ExpectedRightCurlyBraket.java new file mode 100644 index 0000000..389aacd --- /dev/null +++ b/src/org/ntlab/featureExtractor/ExpectedRightCurlyBraket.java @@ -0,0 +1,5 @@ +package org.ntlab.featureExtractor; + +public class ExpectedRightCurlyBraket extends Exception { + +} diff --git a/src/org/ntlab/featureExtractor/MagnetronParser.java b/src/org/ntlab/featureExtractor/MagnetronParser.java new file mode 100644 index 0000000..350c40b --- /dev/null +++ b/src/org/ntlab/featureExtractor/MagnetronParser.java @@ -0,0 +1,201 @@ +package org.ntlab.featureExtractor; + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +public class MagnetronParser { + public static Map doParse(BufferedReader reader) throws IOException, ExpectedLeftCurlyBraket, ExpectedRightCurlyBraket, ExpectedFeatures, ExpectedExtracts { + return parseMagnetron(reader); + } + + private static Map parseMagnetron(BufferedReader reader) throws IOException, ExpectedLeftCurlyBraket, ExpectedRightCurlyBraket, ExpectedFeatures, ExpectedExtracts { + Map magnet = new HashMap<>(); + String line = skipBlankLines(null, reader); + if (line == null || !line.startsWith("{")) { + throw new ExpectedLeftCurlyBraket(); + } + line = line.substring(1); + line = parseKeyValue(line, reader, magnet); // Trace file name + if (line == null || !line.startsWith(",")) throw new ExpectedFeatures(); + line = line.substring(1); + + String keys[] = new String[1]; + line = parseKey(line, reader, keys); // Features in the trace file + if (line == null || !keys[0].equals("features")) new ExpectedFeatures(); + List freatures = new ArrayList<>(); + line = parseFeatures(line, reader, freatures); + magnet.put("features", freatures); + return magnet; + } + + private static String parseFeatures(String residual, BufferedReader reader, List freatures) throws IOException, ExpectedLeftCurlyBraket, ExpectedRightCurlyBraket, ExpectedExtracts { + residual = skipBlankLines(residual, reader); + if (residual == null || !residual.startsWith("[")) { + throw new ExpectedLeftCurlyBraket(); + } + residual = residual.substring(1); + do { + residual = parseFeature(residual, reader, freatures); + residual = skipBlankLines(residual, reader); + if (residual.startsWith(",")) { + residual = residual.substring(1); + continue; + } + } while (!residual.startsWith("]")); + return residual.substring(1); + } + + private static String parseFeature(String residual, BufferedReader reader, List freatures) throws IOException, ExpectedLeftCurlyBraket, ExpectedRightCurlyBraket, ExpectedExtracts { + residual = skipBlankLines(residual, reader); + if (residual == null || !residual.startsWith("{")) { + throw new ExpectedLeftCurlyBraket(); + } + residual = residual.substring(1); + + Feature feature = new Feature(); + Map keyValue = new HashMap<>(); + residual = parseKeyValue(residual, reader, keyValue); // Feature name + feature.setName((String) keyValue.get("feature")); + + if (residual == null || !residual.startsWith(",")) throw new ExpectedExtracts(); + residual = residual.substring(1); + + String keys[] = new String[1]; + residual = parseKey(residual, reader, keys); // Features in the trace file + if (residual == null || !keys[0].equals("extracts")) new ExpectedExtracts(); + List extracts = new ArrayList<>(); + residual = parseExtracts(residual, reader, extracts); + feature.setExtracts(extracts); + freatures.add(feature); + + residual = skipBlankLines(residual, reader); + if (residual == null || !residual.startsWith("}")) { + throw new ExpectedRightCurlyBraket(); + } + return residual.substring(1); + } + + private static String parseExtracts(String residual, BufferedReader reader, List extracts) throws IOException, ExpectedLeftCurlyBraket, ExpectedRightCurlyBraket { + residual = skipBlankLines(residual, reader); + if (residual == null || !residual.startsWith("[")) { + throw new ExpectedLeftCurlyBraket(); + } + residual = residual.substring(1); + do { + residual = parseExtract(residual, reader, extracts); + residual = skipBlankLines(residual, reader); + if (residual.startsWith(",")) { + residual = residual.substring(1); + continue; + } + } while (!residual.startsWith("]")); + return residual.substring(1); + } + + private static String parseExtract(String residual, BufferedReader reader, List extracts) throws IOException, ExpectedLeftCurlyBraket, ExpectedRightCurlyBraket { + residual = skipBlankLines(residual, reader); + if (residual == null || !residual.startsWith("{")) { + throw new ExpectedLeftCurlyBraket(); + } + + Map object = new HashMap<>(); + residual = parseObject(residual, reader, object); + Map srcObject = (Map) object.get("src"); + Map dstObject = (Map) object.get("dst"); + int order = Integer.parseInt((String) object.get("order")); + Extract extract = new Extract( + (String) srcObject.get("id"), + (String) srcObject.get("class"), + (String) dstObject.get("id"), + (String) dstObject.get("class"), + (String) object.get("type"), + order); + extracts.add(extract); + return residual; + } + + private static String parseObject(String residual, BufferedReader reader, Mapobject) throws IOException, ExpectedLeftCurlyBraket, ExpectedRightCurlyBraket { + residual = skipBlankLines(residual, reader); + if (residual == null || !residual.startsWith("{")) { + throw new ExpectedLeftCurlyBraket(); + } + residual = residual.substring(1); + do { + residual = parseKeyValue(residual, reader, object); + if (residual == null) throw new ExpectedRightCurlyBraket(); + residual = skipBlankLines(residual, reader); + if (residual.startsWith(",")) { + residual = residual.substring(1); + continue; + } + } while (!residual.startsWith("}")); + return residual.substring(1); + } + + private static String parseKey(String residual, BufferedReader reader, String[] keys) throws IOException, ExpectedLeftCurlyBraket, ExpectedRightCurlyBraket { + String line = skipBlankLines(residual, reader); + if (line == null) return null; + line = line.trim(); + if (!line.startsWith("\"")) return null; + String strings[] = line.split("\""); + if (strings.length < 1) return null; + String key = strings[1]; + if (line.indexOf(":") < 0) return null; + residual = line.substring(line.indexOf(":") + 1); + keys[0] = key; + return residual; + } + + private static String parseKeyValue(String residual, BufferedReader reader, Map object) throws IOException, ExpectedLeftCurlyBraket, ExpectedRightCurlyBraket { + String keys[] = new String[1]; + residual = parseKey(residual, reader, keys); + if (residual == null) return null; + Object[] values = new Object[1]; + residual = parseValue(residual, reader, values); + object.put(keys[0], values[0]); + return residual; + } + + private static String parseValue(String residual, BufferedReader reader, Object[] values) throws IOException, ExpectedLeftCurlyBraket, ExpectedRightCurlyBraket { + String line = skipBlankLines(residual, reader); + line = line.trim(); + if (line.startsWith("\"")) { + line = line.substring(1); + values[0] = line.substring(0, line.indexOf("\"")); + residual = line.substring(line.indexOf("\"") + 1); + } else if (line.startsWith("{")) { + Mapobject = new HashMap<>(); + residual = parseObject(line, reader, object); + values[0] = object; + } else if (line.startsWith("[")) { + // To Do + } else if (line.startsWith("null")) { + residual = line.substring(4); + values[0] = null; + } else { + // To Do + } + return residual; + } + + private static String skipBlankLines(String residual, BufferedReader reader) throws IOException { + String line = residual; + if (line == null || line.equals("")) { + do { + line = reader.readLine(); + if (line == null) break; + line = line.trim(); + } while (line.equals("")); + } else { + line = line.trim(); + } + return line; + } +} diff --git a/src/org/ntlab/featureExtractor/WrongExtractFormat.java b/src/org/ntlab/featureExtractor/WrongExtractFormat.java new file mode 100644 index 0000000..a898c2e --- /dev/null +++ b/src/org/ntlab/featureExtractor/WrongExtractFormat.java @@ -0,0 +1,5 @@ +package org.ntlab.featureExtractor; + +public class WrongExtractFormat extends Exception { + +} diff --git a/traces/ArgoUML.magnet b/traces/ArgoUML.magnet new file mode 100644 index 0000000..c03f2f4 --- /dev/null +++ b/traces/ArgoUML.magnet @@ -0,0 +1,63 @@ +{ + "trace": "ArgoUMLBenchmarkWithMoreStandardClasses.trace", + "features": [ + { + "feature": "ArgoUML�폜�@�\", + "extracts": [ + { + "src": { + "class": "public void org.argouml.uml.diagram.ui.ActionRemoveFromDiagram.actionPerformed(", + "id": null + }, + "dst": { + "class": "org.argouml.uml.diagram.static_structure.ui.FigClass", + "id": null + }, + "type": "This-Another", + "order": "0" + }, + { + "src": { + "class": "java.util.Vector", + "id": "450474599" + }, + "dst": { + "class": "org.argouml.uml.diagram.static_structure.ui.FigClass", + "id": "1675174935" + }, + "type": "Container-Component(Collection)", + "order": "0" + } + ] + }, + { + "feature": "ArgoUML�I���@�\", + "extracts": [ + { + "src": { + "class": "java.util.ArrayList", + "id": "125345735" + }, + "dst": { + "class": "org.argouml.uml.diagram.static_structure.ui.SelectionClass", + "id": "1672744985" + }, + "type": "Container-Component(Collection)", + "order": "0" + }, + { + "src": { + "class": "org.argouml.uml.diagram.static_structure.ui.SelectionClass", + "id": "1672744985" + }, + "dst": { + "class": "org.argouml.uml.diagram.static_structure.ui.FigClass", + "id": "1675174935" + }, + "type": "Container-Component", + "order": "0" + } + ] + } + ] +} \ No newline at end of file diff --git a/traces/JHotDraw.magnet b/traces/JHotDraw.magnet new file mode 100644 index 0000000..ca10024 --- /dev/null +++ b/traces/JHotDraw.magnet @@ -0,0 +1,87 @@ +{ + "trace": "jHotDrawBenchmarkWithMoreStandardClasses.trace", + "features": [ + { + "feature": "JHotDraw�}�`�ړ��@�\", + "extracts": [ + { + "src": { + "class": "java.util.HashSet", + "id": "176893671" + }, + "dst": { + "class": "org.jhotdraw.draw.RectangleFigure", + "id": "1952912699" + }, + "type": "Container-Component(Collection)", + "order": "0" + } + ] + }, + { + "feature": "JHotDraw�I���@�\", + "extracts": [ + { + "src": { + "class": "org.jhotdraw.draw.tool.DefaultDragTracker", + "id": "758826749" + }, + "dst": { + "class": "org.jhotdraw.draw.RectangleFigure", + "id": "1952912699" + }, + "type": "Container-Component", + "order": "1" + }, + { + "src": { + "class": "java.util.HashSet", + "id": "1378082106" + }, + "dst": { + "class": "org.jhotdraw.draw.RectangleFigure", + "id": "1952912699" + }, + "type": "Container-Component(Collection)", + "order": "0" + }, + { + "src": { + "class": "org.jhotdraw.draw.tool.DelegationSelectionTool", + "id": "599587451" + }, + "dst": { + "class": "org.jhotdraw.draw.tool.DefaultDragTracker", + "id": "758826749" + }, + "type": "Container-Component", + "order": "1" + }, + { + "src": { + "class": "java.util.LinkedHashSet", + "id": "1787265837" + }, + "dst": { + "class": "org.jhotdraw.draw.RectangleFigure", + "id": "1952912699" + }, + "type": "Container-Component(Collection)", + "order": "0" + }, + { + "src": { + "class": "org.jhotdraw.draw.tool.DefaultDragTracker", + "id": "758826749" + }, + "dst": { + "class": "org.jhotdraw.draw.DefaultDrawingEditor", + "id": "1859859960" + }, + "type": "Container-Component", + "order": "3" + } + ] + } + ] +} \ No newline at end of file