Archiv der Kategorie: DXL

IBM Doors DXL: Versioned Links – Experimente mit BaselineSets, BaselineSetDefinitions

Intention

Allgemein

Für den Doors-Spezialisten erscheint das Thema der „Versioned Links“ mit Sicherheit trivial, ich hingegen habe desöfteren Probleme zu verstehen, wann sich ein „Versioned Link“ bildet. Daher habe ich mir ein Test-Szenario überlegt, anhand dessen ich das Verhalten von „Versioned Links“ näher analysieren möchte.

Was ist ein „Versioned Link“?

Einfach gesagt ist ein „Versioned Link“ ein Link, der auf eine Baseline eines Moduls ( einen eingefrorenen Stand) und nicht auf die „Current Version“ (die akutelle Arbeitsversion) des Moduls zeigt.

Wo ist also mein Problem?

Wer den Mechanismus des Link-Ziehens kennt, der weiß, dass es keine Möglichkeit gibt einen solchen Link bewusst auf eine Baseline zu ziehen.

zustandAinDoors

Desweiteren beziehen sich die Link-Module, über die man ebenfalls iterieren kann, um Quell- und Ziel-Objekte zu ermitteln, ausschließlich auf current LinkModules. Was passiert wenn ein Link-Modul gelöscht wird? Existiert nach dem Löschen der Satisfy-Beziehung (des Satisfy-Linkmoduls) in den alten Baselines immer noch?

Der folgende Code gibt die Baselines von Link-Modulen aus. Bei mir handelt es sich um hohe Versionszahlen größer als 200, die nicht mit den formellen/herkömmlichen Modul-Baselines in Verbindung gebracht werden können. Es ist also nicht ganz korrekt, das Link-Module keine Baselines haben, sie sind nur leider für den Endanwender unbrauchbar… oder kennt jemand einen Anwendungsfall wo er sie bisher nutzten konnte?

string nSatisfiesLinkModule = "/NDS/90 Administration/Satisfies"; 
Module SatisfiesLinkModule = read(nSatisfiesLinkModule, false); 
Baseline b = null;
int i = 0;

for b in SatisfiesLinkModule do 
{ 
    print i ") ";
    print(major b)"."(minor b)(suffix b)" "(annotation b)"\n" 
    i++;
} 

Wann entstehen „Versioned Links“?

„Versioned Links“ entstehen dann, wenn ein current Quell-Modul, welches noch nicht ins letzte  BaselineSet gestellt wurde, einen Outgoing-Link auf ein Ziel-Modul, welches gerade ins BaselineSet gestellt wurde, hat.

versioned_links1

(Zustand A: Quellmodul noch nicht im Baseline Set)

Dies bedeutet, dass der Auslöser für die Duplikation eine Modul-Baseline des Source-Moduls ist und nicht etwas auf Objekt-Ebene ausgelöst wird.

Wird anschließend eine Baseline für das Quell-Modul erstellt, wandern die Links in das gebaselinte Quell-Modul und die Duplikation im „Current Module“ verschwindet wieder.

versioned_links2

(Zustand B: Quellmodul wandert mit duplizierten Links ins BS)

Anmerkung: Den Zustand A sieht man i.d.R. nur in current Modules, die noch nicht ins letzte BaselineSet aufgenommen wurden.

Warum existieren „Versioned Links“?

Ich glaube fast, dass die Existenz von „Versioned Links“ vorwiegend der Tatsache geschuldet ist, dass die Links im Quell-Modul gespeichert werden und anschließend durch eine Art „Verschieben“ dem Baseline-Modul/der Snapshot-Kopie zugewiesen werden. Wenn das so ist, wäre der Zweck dieser Funktion nicht die Erfüllung von Nutzer-Anforderungen oder User-Stories, sondern lediglich einem technischem Zweck geschuldet.

Oder ist es für das Vorstellungsvermögen des Nutzers einfacher sich vorzustellen, wie eine Kopie des Quellmoduls (nämlich die Baseline) langsam mit den duplizierten, verankerten Links ins Baseline Set wandert?

Sorgen „Versioned Links“ im Zustand A für die Korrektheit/Versionssicherheit von Daten?

Wenn nun das Quellmodul, was z.B. eine Design Spezifikaton ist, Links auf die Current-Version und die gebaselinte Version hat, würde durch Veränderung in der Current-Version (also in den Requirements) nicht sichergestellt sein dass das Design noch stimmt. Die Aufgabe könnten Suspect Links erfüllen.

Daher lautet meine Antwort:

Nein (OXI)! „Versioned Links“ im Zustand A können nicht für die Korrektheit der verlinkten Daten sorgen. Meines Erachtens wäre es sinnvoller, wenn dass Source-Modul nur dann auf die Baseline zeigt, wenn das Source-Module seit der Target-Baseline nicht verändert wurde.
–> Wenn sich das „Current Ziel-Modul“ (z.B. die Software Requirements) seitdem geändert hat, so dass sich das Design ändern würde, stellt sich die Frage wieso das „Current Quell-Modul“ (z.B. das Software Design) auf geänderte Requirements zeigt.
Falls es geändert wurde, kann es auf die Current-Version des Ziel-Moduls zeigen… oder auch nicht, da ja noch nicht das ganze Modul geändert wurde…

Test Szenario

Test Beschreibung

Es soll nun getestet werden, wie der Zustand A (Link-Duplikation) bei Modulen, die ausschließlich Quellen, Modulen die ausschließlich Senken und Zwischenmodulen beim Verfolgen von Links darstellt.

Test Aufbau

Ich habe 11 Module auf 4 verschiedenen Ebenen erstellt, die ich mit willkürlichen Link-Typen miteinander verlinkt habe.

Anschließend habe ich eine Baseline Set Definition erstellt, die alle 11 Module beinhaltet und 4 Module (E1I1, E2I3, E3I1, E4I1) bereits in das BaselineSet gestellt (in der Grafik unten rot umrahmt).

TraceabilityTest

Das Baseline Set existiert in der Version 2.0:

tool_baselines

Test Durchführung

Die untenstehende Tabelle geht von current Quell-Modulen bei Outgoing-Links, und current Ziel-Modulen bei Incoming-Links aus.

D.h. bei Incoming-Links ist die Spalte Ziel-Modul das geöffnete Modul, bei dem das Phänomen der gespaltenen Links im Zustand A auftritt, bei Outgoing-Links ist das Quell-Modul der Ort, in dem das Phänomen der gespaltenen Links auftritt.

Auswertung1

Es ergibt sich darauf die folgende Wahrheitstabelle:

Auswertung2

Ergebnis

Der Zustand A von „Versioned Links“ tritt bei Outgoing Links im current Quellmodul auf, wenn das Quellmodul nicht im Baseline Set ist und das Zielmodul im Baseline Set ist.
Der Zustand A von „Versioned Links“ tritt bei Incoming Links im current Zielmodul auf, wenn das Quellmodul im Baseline Set ist, aber das Zielmodul nicht im Baseline Set.
Der Zustand A von „Versioned Links“ tritt auch in Baseline Modulen auf, wenn diese durch die Duplikation auf current Module zeigt.

Navigation mit DXL durch Versioned Links

Um ALLE Links eines Moduls, auch die Current- und Baseline-Versionen für ein Objekt zu bekommen, nutzt man den „ALL“ Quantor in der For-Schleife

Module m=current;
Link lnk;
Object o;
int numLinks=0;

for o in m do
{
  for lnk in all(o->"*") do
  {
    numLinks++;
  }
}  
print "There are " numLinks " outgoing links from this module.";

IBM DOORS DXL: Zurücksetzen mehrere Werte auf ihre gebaselinte Version

Problem

Mehrere Werte in einem Current Modul sollen auf ihre Werte in der letzten Baseline zurückgesetze werden.

Ansatz

* Einlesen der letzen Baseline.
* Filterung der betroffenen Objekte
** Hier Bsp. h.newValue==“Internal“ && h.attrName == „BB_Type“ && h.author==“karpbjde“ && h.date „“==“03/27/15 11:33:58“

Lösung

History h;
Module m = current;
Object o, baselineObject;

// Anstelle von getMostRecentBaseline(m) kann die Baseline auch definiert werden 
Baseline b = getMostRecentBaseline(m) 
Module mostRecentBaseline = load(m, b, false)

for baselineObject in mostRecentBaseline  do
{
  for h in baselineObject do
  {
    HistoryType hisType = h.type;

    if(hisType==modifyObject)
    {
	if(h.newValue=="Internal" && h.attrName == "BB_Type" && h.author=="karpbjde" && h.date ""=="03/27/15 11:33:58")
	{
           for o in m do
           {
             if(identifier(baselineObject) "" == identifier(o) "")
             {
                 print "Set " identifier(baselineObject) "\t" h.author "\t" h.date " to " h.oldValue "\n";
                 o."BB_Type" = h.oldValue;
                 break;
	      }
	    }
	}
      }
   }
}

IBM Doors DXL: Anzahl der OLE Objekte in einem Modul

Problem

Die Anzahl der OLE Objekte in einem Modul soll ermittelt werden. Außerdem ermittelt das Skript noch welche Typen einer Enumeration „BB_TYPE“ auftreten.

Ansatz

* Verwendung der Funktion oleCount (Ein Objekt kann im Objekt Text mehrere OLE Objekte haben).
* Verwendung einer Skip Liste (HashMap) um die Types zu ermitteln, die auftreten können (ein Type ist eine Attribut-Enumeration)

Lösung – Solution

int oleCountInModule=0;
int internalCount=0;
Skip typeCollection = create;


void checkOLEcount(Object o, string attributeName) 
{ 
    int n = oleCount(o.attributeName);
    oleCountInModule=oleCountInModule+n;
    

    if(n>0 && o."BB_Type" "" != "Internal" && o."BB_Type" "" != "ChangeHistory")
    {
       put(typeCollection , o."BB_Type" "", o."BB_Type" "")
    }

} 

Module m = current;
Object o;

for o in m do
{
	checkOLEcount(o, "Object Text") 
}

print "OLE Count in Module: " oleCountInModule " / davon " internalCount " internal\n";

for myIterator in typeCollection do 
{
   string keyValue = (string key(typeCollection ));
   string currentObject = "";

   if(find(typeCollection , keyValue, currentObject))
   {
       // Just put the column names here.. it will work
       print currentObject "\n"
   }
}

IBM DOORS DXL: List all Files in File System Directory from folder / Dateien in Verzeichnis auflisten

Problem

In iteration through all files in a file system directory shall be performed.
Alle Dateien in einem Verzeichnis sollen aufgelistet werden

Ansatz – Approach

Iterate all files of a file System Directory.
Verwenden des directory Schlüsselwortes

Lösung – Solution

string x = "c:\\" 
string file 
for file in directory x do { 
   print file "\n" 
} 

IBM Doors DXL: OLE Objekte als Bild exportieren

Problem

Alle OLE Objekte eines Moduls sollen als Bild exportiert werden

Ansatz

Verwenden der exportPicture Funktion

Lösung

Module m = current;
Object o;
string attributeName="Object Text";
string baseFileName ="";

EmbeddedOleObject ole

for o in m do
{
    int i = 1 
    string errmess = null
    RichText rtf
    string s = richTextWithOle o.attributeName    
    i = 1
    for rtf in s do
    {
       if (rtf.isOle)
       {
	     baseFileName = identifier(o) "";
           ole = rtf.getEmbeddedOle
           string filename = baseFileName "-rtfloop-" i ".png"
           print "Exporting " filename "\n" 
           errmess = exportPicture(ole,filename  , formatPNG)  
           if (!null errmess)
           {
               print "ERROR: " errmess "\n"   
           }  
        i++
       }   
    }
}

Bei Verwendung dieses Patterns können die Objekte auch wieder so importiert werden:

#include "\\\\bbmag2k\\exchange\\doors\\dxl\\strings.inc";       

Module m = current;
Object o;

string x = "h:\\pics" 
string file 
for file in directory x do { 
   if(matches("IDS-", file))
   {
      string objectIdentifier=file[0:indexOfFrom(file,"-",2)-1] "";
      string aufkommen=replace(file[lastIndexOf(file,"-")+1:length(file)], ".png", "") "";
      print objectIdentifier " " aufkommen "\n";
      // oleInsert
   }
} 

IBM Doors DXL: Automatisch Links erstellen / erzeugen

Problem

Ein Kollege hat die Links in ein Kommentarfeld geschrieben. Diese Links sollen nun automatisiert ausgelesen und erstellt werden.

Ansatz

Zwei verschachtelte Schleifen
– Schleife 1: Sucht nacht Kommentaren und nutzt sie als Object Identifier
– Schleife 2: Sucht das Objekt im zu verlinkendem Modul

Lösung

// trim() used... 
// String Functions: https://www.capri-soft.de/blog/?p=832
#include "\\\\bbmag2k\\exchange\\doors\\dxl\\strings.inc";       		

Module m = current;
Module crs = read("/MultiProductData/30 Component/COMP-LA/CRS-LA",true);
current = m;

Object o,o2;
Link newLink;

for o in m do
{
 string toObject = o."BB_Comments" "";

 if (trim(toObject)!="")
 {
  for o2 in crs do 
  {
    if(identifier(o2) "" == toObject)
    {
      print identifier(o) " -> " toObject "\n";
      newLink = o -> "/MultiProductData/90 Administration/Specifies" -> o2;
    }
  }
 }
}

IBM Doors DXL: Attribut eines verlinkten Objektes Ausgeben

Problem

Es soll eine LayoutDXL Spalte erzeugt werden, die ein Attribut aus einem verlinktem Requirement (Im V-Model z.B. obendrüber also hier Outlink) ausgibt.

Ansatz

* Öffnen des Moduls
* Nutzen der obj Referenz für das Objekt in der aktuellen Zeile
* Link Modul spezifizieren

Lösung

Module rsModule = read("/pathTo/RS", false);

Link lnk;
Object trg;
string lnkMod;
string strSat = "/pathToLinkModules/Satisfies";

for lnk in obj->"*" do 
{
  lnkMod= fullName module(lnk);
  
  if(!null lnkMod)
  {
	  if(lnkMod == strSat)
	  {
	      Object trg = target(lnk);
	      display trg."BB_PlannedRelease" "";
	  }
  }
}

IBM Doors DXL: Import from Sparx Systems Enterprise Architect

Problem

To refresh all UML Diagrams within an Formal Doors Module, a script is needed that imports all actual versions of a UML Diagram.

Approach

* Copy the GUID of the Diagram / Note
** right-click the project menu on the right side.
** Select „Copy Reference -> Copy Node GUID to clipboard“
* If not done before, create an Module attribute (here ATTRIBUT_WITH_GUID)
* Paste the GUID to the place in your doors module, where the diagram should be created

Solution

// Recommended as module plugin
/**
 * Run through all objects of the current module 
 * and watch for the attribute ATTRIBUT_WITH_GUID.
 * If it is not empty, fetch the diagram/note
 * from this attribute an load it into the 
 * Object Text of Sparx Systems Enterprise Architect
 */

Object o
Filter currentFilter, f
Module m
DB updateWin

string guid
string projectPath = "DP_ENTARCHITECT --- DBType=1;" //-
"Connect=Provider=SQLOLEDB.1;Integrated Security=SSPI;" //-
"Persist Security Info=False;Initial Catalog=DBNAME;" //-
"Data Source=EA_DB_SERVER"

OleAutoObj eaProject, eaRepository, diaObj, actObj
OleAutoArgs autoArgs = create
string diagramName, elementNotes

void establishInterface()
{
 eaProject = oleGetAutoObject("EA.Project")
 if(null(eaProject))
 { 
   eaProject = oleCreateAutoObject("EA.Project")
 }

 if(null(eaProject))
 {
   ack "Creating OLE-Object 'EA.Project' not possible."
   progressStop
   halt
 }

 eaRepository = oleGetAutoObject("EA.Project")

 if(null(eaRepository))
 {
   eaRepository = oleCreateAutoObject("EA.Repository")
 }

 if(null(eaRepository))
 {
   ack "Creating OLE-Object 'EA.Repository' not possible."
  progressStop
  halt
 }

 put(autoArgs,projectPath)
 oleMethod(eaRepository,"OpenFile",autoArgs)
 clear(autoArgs)
}

void closeInterface()
{
  oleMethod(eaRepository,"CloseFile",autoArgs)
  oleMethod(eaRepository,"Exit",autoArgs)
	
  delete(autoArgs)
}

void updateObjects()
{
 int progessbarStep = 0
 bool diagramCopied
 string fileName

 for o in m do
 {
  guid = o."BB_ImageFileName"
  diagramCopied = false
	
  if(guid != "" && guid[0:0] == "{")
  {
   progressMessage("Updating " identifier(o))
   put(autoArgs, guid)
		
   /**************************************************
    * Gets a pointer to a diagram using an absolute 
    * reference number (local ID). This is usually 
    * found using the DiagramID property of an 
    * element, and stored for later use to open a diagram 
    * without using the 
    * collection GetAt() function.
    **************************************************/
    oleMethod(eaRepository, "GetDiagramByGuid", autoArgs, diaObj)
		
    /*************************************************
     * An Element is the main modeling unit. 
     * It corresponds to (for example) a Class, 
     * Use Case, Node or Component. 
     * You create new elements by adding to the 
     * Package Elements collection. 
     * Once you have created an element, you can add it
     * to the DiagramObject 
     * Class of a diagram to include it in the diagram.
     ****************************************************/
     oleMethod(eaRepository, "GetElementByGuid", autoArgs, actObj)
     clear(autoArgs)
		
     // Wenn das Diagramm mit der GUID nicht gefunden wurde
     if(null(diaObj))
     {
      // ... und auch kein Element mit der GUID gefunden wurde
      if(null(actObj))
      {
         ack "GUID " guid " of object " identifier(o) "" //-
            " not found in EA as diagram or element."
      }
      else
      {
        // Es wurde kein Diagramm, aber ein Element 
        // mit der GUID gefunden
        oleGet(actObj, "Notes", elementNotes)
        if(null(elementNotes))
        {
          ack "Getting Notes of GUID " guid " failed."
        }
        else
        {
	 o."Object Text" = elementNotes
	 progressStep(++progessbarStep)
        }
      }
    }
    else // Es wurde ein Diagramm mit der GUID gefunden
    {					
      /***************************************************
       *  EA.Project.PutDiagramImageOnClipboard: 
       *  ======================================
       *  Copies an image of the specified diagram to the 
       *  clipboard.
       *	
       *  Parameters:
       *	•	DiagramGUID: String - the GUID 
       *        (in XML format) 
       *        of the diagram 
       *        to copy
       *	•	Type: Long - the file type
       *		•	If Type = 0 then it is a metafile
       *		•	If Type = 1 then it is a Device 
       *            Independent Bitmap
       *
       *****************************************************/
       put(autoArgs, guid)
       put(autoArgs, 0)				
       oleMethod(eaProject, "PutDiagramImageOnClipboard", autoArgs, 
	             diagramCopied)
       clear(autoArgs)
		
       if(diagramCopied)
       {
         while(oleDelete(o));
         if(olePaste(o))					
         {
	       oleSetMaxWidth(o."Object Text", 400)
	        progressStep(++progessbarStep)
         }
         else
         {
	       ack "Pasting from clipboard of GUID " guid " failed."
         }
       }
       else
       {
         ack "Copying to clipboard of GUID " guid " failed."
       }
     }
	 diaObj = null
     actObj = null
   }
  }
}

void main(DB updateWin)
{
  int accepted, rejected

  currentFilter = current	
  f = contains(attribute("ATTRIBUT_WITH_GUID"),"{", false)
  set(m, f, accepted, rejected)
  unApplyFiltering(m)
  progressStart(updateWin, "Executing update", "Processing...", accepted)
  establishInterface()
  updateObjects()
  if(!null(currentFilter)) set(m, currentFilter, accepted, rejected)
  closeInterface()
  progressStop
  refresh(m)
  hide(updateWin)
  destroy(updateWin)
  updateWin = null
}

m = current
if(null(m))
{
  ack "Update can only be started within a module."
}
else
{
 if(isEdit(m))
 {
   updateWin = create("Update EA ", styleCentered|styleFloating)
   label(updateWin, "Do you wish to update?")
   ok(updateWin, main)
   show updateWin
 }
 else
 {
  ack "Module must be opend in 'Exclusive Edit'."
 }
}

IBM Doors DXL: Browse Triggers on module

Problem

When there are triggers on a module it often is not visible to administrators and other users that can perform DXL operations.

Approach

A menu point as module add in should be generated. Copy the following script to the moduleaddins directory of your doors installation.

Solution

// This is necessary that it works
/*******************************************************
 * Author: Björn Karpenstein
 * Date:   2014-10-01
 * 
 * This script lists all triggers of the module
 ******************************************************/
pragma runLim, 0;

string lstArray [] = {}; 
 
DB mainWindow;
DBE textBox;
DBE textList;

void listAllTriggerForMod (Module mod) 
{
  string theResult="";
  Trigger t;
  int i = 0;
  for t in mod do 
  {
    insert(textList, i, name(t) "", iconNone);
    i++;
  }
}

string getSourceForTriggerName (string theTrigger) 
{
  string sourceCode = "";
  Trigger t;
  for t in current Module do 
  {
    if(name(t) "" == theTrigger)
    {
      sourceCode = dxl(t) "";
    }		
  }
	
  return sourceCode;
}

void doDeselect(DBE dbe, int idx)
{
  //infoBox "You deselected " dbe[idx] "";
} 


void doActivate(DBE dbe, int idx)
{
  // infoBox "You activated " dbe[idx] "";	
}

void doSelect(DBE dbe, int idx)
{
  string triggerName = getColumnValue(textList,idx,0);
  set(textBox, getSourceForTriggerName(triggerName));	
} 

void main(void)
{
  User currentUser = find();
  bool mayDXL = currentUser.mayEditDXL;
  if (!mayDXL)
  {
   // Show error box and inform user. Stop execution of script.
   errorBox "You are not allowed to run/edit DXL code!";
   halt;
  }		
	
  mainWindow = create("List all triggers");
	
  textList = listView(mainWindow, 0, 310, 20, lstArray);		
  textBox = text(mainWindow, "", "", 400, false);
	
  textList->"right"->"unattached";
  textBox->"left"->"flush"->textList;
  textBox->"top"->"aligned"->textList;	

  realize(mainWindow);			
	
  insertColumn(textList, 0, "Trigger Name", 300, iconNone);
	
  set(textList,doSelect,doDeselect,doActivate);		
  listAllTriggerForMod(current);
	
  // set(textBox, listAllTriggerForMod(current));
  show(mainWindow);	
}

main();

IBM Doors DXL: A Layout DXL column that shows the differences to a previous baseline

Problem

A Layout DXL Column script should show the differences to another baseline

Approach

  • Right-click column header
  • Select „New“
  • Choose „Layout DXL“  radio button
  • Click on the browser button
  • Click on New
  • Insert the script below
  • Be aware to have all line breaks in the code like below

Replace {baselineToCompare} to the major version that you want to compare with the current version.

Solution

// This script shall be replace {baselineToCompare}
/**************************************************
 * Author: Björn Karpenstein
 * Date:   2014-10-09
 *
 * This is a layout DXL to show the differences from 
 * the current version to another baseline. 
 **************************************************/
Baseline oldBaseline = baseline({baselineToCompare}, 0,"");

Buffer bBefore = create;
Buffer bAfter = create;
Buffer result = create;
AttrDef ad;

Module oldModule = load(module(obj), oldBaseline, false)
Module currModule = current
showDeletedObjects(true)
int i = obj."Absolute Number"
Object oldObject = object(i, oldModule)

void compareColumn(string columnName)
{
  ad = find(oldModule, columnName);
		
  if(!null(ad) && !null(oldObject))
  {
    bBefore = oldObject.columnName;
  }
  else bBefore = "";
		
  ad = find(currModule, columnName)

  if(!null(ad))
  {
    bAfter = obj.columnName;
  }
  else bAfter = "";
		
  bAfter = obj.columnName;

  if( bBefore != bAfter )
  {
    diff(result, bBefore, bAfter);
    displayRichWithColor("{\\b " columnName " CHANGED}");
    displayRichWithColor(stringOf(result));
  }
}
				
if(null(oldObject))
{
  displayRichWithColor("{\\b NEW}");
  if(isDeleted(obj)) displayRichWithColor("{\\b DELETED}");
}
else
{			
  if(isDeleted(obj) && !isDeleted(oldObject))
  {
    displayRichWithColor("{\\b DELETED}");
  }
  else
  {
    if(!isDeleted(obj) && isDeleted(oldObject))
    {
      displayRichWithColor("{\\b UNDELETED}");
    }
  
    // Here you can add the 
    // module attributes to compare	
		
    /*** BB_ReqStatus ***/		
    compareColumn("BB_ReqStatus");
	
    /*** BB_Type ***/
    compareColumn("BB_Type");

    /*** Last Modified On ***/
    compareColumn("Last Modified On");
		
    /*** Object Heading ***/
    compareColumn("Object Heading");

    /*** Object Text ***/
    compareColumn("Object Text");
  }
}
		
delete bBefore;
delete bAfter;
delete result;