# Contacts Service API example

This section presents the full source code of a working sample widget for the Contacts Service. You can download the `wgz` package for this widget from section Example widgets.

For general information about creating widgets, see section Widget component files.

For widget development and debugging purposes, this example writes its output to `c:\data\jslog_widget.log` using `console.info`. For instructions on how to enable logging in the Web browser for S60, see section JavaScript console.

### Info.plist

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Nokia//DTD PLIST 1.0//EN" "http://www.nokia.com/NOKIA_COM_1/DTDs/plist-1.0.dtd">
    <plist version="1.0">
    <dict>
      <key>DisplayName</key>
      <string>ContactSample</string>
      <key>Identifier</key>
      <string>com.nokia.widget.sapi.contact.sample</string>
      <key>Version</key>
      <string>1.0</string>
      <key>MainHTML</key>
      <string>contact-sample.html</string>
    </dict>
    </plist>

### contact-sample.html

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
        <script type="text/javascript" src="js/common.js"></script>
        <script type="text/javascript" src="js/contact-sample.js"></script>
      </head>
      <body id='docBody' bgcolor="#ddeeff" onload="setup()" style=width:100%;height:100%;>
        <form name="frm">
          <h3>Contact API Sample Widget</h3>
          Async<input type="checkbox" id="async_check" onClick="check_async()">
          Cancel<input type="checkbox" id="cancel_check" onClick="check_cancel()"><br/>
          <hr>
          <input type="button" onclick="addContact('img1')" value="AddContact"><img id="img1" src="pic/blank.png" width="25" height="25" align="center"><br>
          <input type="button" onclick="delContact('img2')" value="DeleteContact"><img id="img2" src="pic/blank.png" width="25" height="25" align="center"><br>
          <input type="button" onclick="getContactList('img3')" value="GetContactList"><img id="img3" src="pic/blank.png" width="25" height="25" align="center"><br>
          <input type="button" onclick="importContact('img4')" value="ImportContact"><img id="img4" src="pic/blank.png" width="25" height="25" align="center"><br>
          <input type="button" onclick="exportContact('img5')" value="ExportContact"><img id="img5" src="pic/blank.png" width="25" height="25" align="center"><br>
          <hr>
          <input type="button" onclick="addGroup('img6')" value="AddGroup"><img id="img6" src="pic/blank.png" width="25" height="25" align="center"><br>
          <input type="button" onclick="delGroup('img7')" value="DeleteGroup"><img id="img7" src="pic/blank.png" width="25" height="25" align="center"><br>
          <input type="button" onclick="getGroupList('img8')" value="GetGroupList"><img id="img8" src="pic/blank.png" width="25" height="25" align="center"><br>
          <input type="button" onclick="organiseGroup('img9')" value="OrganiseGroup"><img id="img9" src="pic/blank.png" width="25" height="25" align="center"><br>
          <hr>
          <div class='contactsample' id='contactsample' bgcolor="#ddeeff" style=width:100%;height:100%;overflow:auto></div>
        </form>
      </body>
    </html>

### common.js

    // common.js
    //
    // This file contains some utility functions

    // Check the error code and show the information to users
    function checkError(message, resultList, divId, imgId)
    {
      var errCode = resultList.ErrorCode;
      var msg = "";

      if (errCode) {
        msg = message + "<BR>" + "Failed Error: " + errCode + "<BR>";
        if(resultList.ErrorMessage != undefined)
          msg += "Error Message: " + resultList.ErrorMessage;
        showIMG(imgId,"no");
      } else {
        showIMG(imgId,"yes");
      }

      //print error message
      if(divId != null && divId != undefined)
        document.getElementById(divId).innerHTML = msg;
      console.info(msg);

      return errCode;
    }

    // Build the message by reading a iteratorable list in a recursive manner
    function showIterableList(iterator)
    {
      var msg = "";
      try
      {
        iterator.reset();
        var item;
        while (( item = iterator.getNext()) != undefined ){
          msg += showObject( item );
        }
      }
      catch(e)
      {
        alert('<showIterableList> ' + e);
      }
      return msg;
    }

    // Build the message by reading a JS object in a recursive manner
    function showObject( obj )
    {
      var txt = "";
      try {
        if ( typeof obj != 'object' )
          return "" + obj + '<BR/>';
        else {
          for(var key in obj) {
            txt +=  key + ":";
            txt += showObject( obj[key] );
            txt += '<BR/>';
          }
          txt += '<BR/>';
        }
      }
      catch (e)
      {
        alert("showObject: " + e);
      }
      return txt;
    }

    // Show the image to indicate the test result
    function showIMG(imgId, isOK)
    {
      if(imgId == null || imgId == undefined)
        return;

      if(isOK == "yes")
        document.getElementById(imgId).src = "pic/yes.png";
      else if(isOK == "no")
        document.getElementById(imgId).src = "pic/no.png";
      else
        document.getElementById(imgId).src = "pic/blank.png";
    }

    // Show elements in object by using 'alert'
    function testObject(obj)
    {
      var msg = "";
      for(var key in obj) {
        msg = msg + ":" + key + "=" + obj[key];
      }
      alert(msg);
    }

    // Test whether the input is numeric
    function IsNumeric(sText)
    {
      var ValidChars = "0123456789.";
      var IsNumber=true;
      var Char;

      for (i = 0; i < sText.length && IsNumber == true; i++)
      {
        Char = sText.charAt(i);
        if (ValidChars.indexOf(Char) == -1)
        {
          IsNumber = false;
        }
      }
      return IsNumber;
    }

### contact-sample.js

    // contact-sample.js
    //
    // In this sample Contact and Group will be added, deleted, and listed from
    // default database; Contact will be imported and exported; Group will be
    // organised; Also, async operation will be canceled
    //

    //SAPI Error Codes
    // 0    - Success
    // 1000 - InvalidServiceArgument
    // 1001 - UnknownArgumentName
    // 1002 - BadArgumentType
    // 1003 - MissingArgument
    // 1004 - ServiceNotSupported
    // 1005 - ServiceInUse
    // 1006 - ServiceNotReady
    // 1007 - NoMemory
    // 1008 - HardwareNotAvailable
    // 1009 - ServerBusy
    // 1010 - EntryExists
    // 1011 - AccessDenied
    // 1012 - NotFound
    // 1013 - UnknownFormat
    // 1014 - GeneralError
    // 1015 - CancelSuccess
    // 1016 - ServiceTimedOut
    // 1017 - PathNotFound

    // declare the service object
    var so;

    // async Test Mode
    var asyncMode;

    // cancel Test Mode
    var cancelMode;

    // imgid for callback1 function
    var imgid_callback1;

    // imgid for callback2 function
    var imgid_callback2;

    // imgid for callback3 function
    var imgid_callback3;

    // imgid for callback4 function
    var imgid_callback4;

    // imgid for callback5 function
    var imgid_callback5;

    // imgid for callback6 function
    var imgid_callback6;

    // imgid for callback7 function
    var imgid_callback7;

    // id of the div used to display information
    const DIV_ID = 'contactsample';

    // Called from onload()
    function setup()
    {
      try {
        so = device.getServiceObject("Service.Contact", "IDataSource");
        console.info("setup: so: %s", so);
      }
      catch (e) {
        alert('<setup> ' +e);
      }
    }

    // Async checkbox handler
    function check_async() {
      var asyncChk = document.getElementById("async_check");
      asyncMode = asyncChk.checked;
      if (!asyncMode) {
        var cancelChk = document.getElementById("cancel_check");
        cancelChk.checked = false;
        cancelChk = false;
      }
    }

    // cancel checkbox handler
    function check_cancel() {
      var cancelChk = document.getElementById("cancel_check");
      cancelMode = cancelChk.checked;

      // if cancel checkbox is selected, the async checkbox should be
      // selected automatically
      if(cancelMode) {
        var asyncChk = document.getElementById("async_check");
        asyncChk.checked = true;
        asyncMode = true;
      }
    }

    // Add Contact
    function addContact(imgId) {

      var last = new Object();
      last.Label = "Last name";
      last.Value = "Shen";

      var first = new Object();
      first.Label = "First name";
      first.Value = "Yi";

      var contactdata = new Object();
      contactdata.LastName = last;
      contactdata.FirstName = first;

      var criteria = new Object();
      criteria.Type = "Contact";
      criteria.Data = contactdata;

      try {
        var result;
        if (!asyncMode && !cancelMode) { // sync
          result = so.IDataSource.Add(criteria);
          checkError("IDataSource::addContact",result,DIV_ID,imgId);
        } else if (asyncMode && !cancelMode) {// async
          // set the image id for callback1 function
          imgid_callback1 = imgId;
          result = so.IDataSource.Add(criteria, callback1);
          if(!checkError("IDataSource::addContactAsync",result,DIV_ID,imgId)) {
            showIMG(imgId,"");
          }
        } else if (cancelMode){ // cancel
          // set the image id for callback1 function
          imgid_callback1 = imgId;
          result = so.IDataSource.Add(criteria, callback1);
          if(!checkError("IDataSource::cancelAddContactAsync",result,DIV_ID,imgId)) {
            showIMG(imgId,"");
            var criteria2 = new Object();
            criteria2.TransactionID = result.TransactionID;
            var result2 =so.IDataSource.Cancel(criteria2);
            checkError("IDataSource::cancelAddContactAsync",result2,DIV_ID,imgId);
          }
        }
      }
      catch (e) {
        showIMG(imgId,"no");
        alert ("addContact: " + e);
      }
    }

    // Delete Contact
    function delContact(imgId) {

      // using the getFirstId to get the Contact Id
      // it is impossible to ask user to type the Contact Id because
      // the id is in binary and hard to be displayed by javascritp

      var contactId = getFirstId("Contact");
      if(contactId == null) {
        alert("No contact exists!");
        return;
      }

      var contactdata = new Object();
      contactdata.IdList = new Array();
      contactdata.IdList[0] = contactId;

      var criteria = new Object();
      criteria.Type = "Contact";
      criteria.Data = contactdata;

      try {
        var result;
        if (!asyncMode && !cancelMode) { // sync
          result = so.IDataSource.Delete(criteria);
          checkError("IDataSource::delContact",result,DIV_ID,imgId);
        } else if (asyncMode && !cancelMode) {// async
          // set the image id for callback2 function
          imgid_callback2 = imgId;
          result = so.IDataSource.Delete(criteria, callback2);
          if(!checkError("IDataSource::delContactAsync",result,DIV_ID,imgId)) {
            showIMG(imgId,"");
          }
        } else if (cancelMode){ // cancel
          // set the image id for callback2 function
          imgid_callback2 = imgId;
          result = so.IDataSource.Delete(criteria, callback2);
          if(!checkError("IDataSource::cancelDelContactAsync",result,DIV_ID,imgId)) {
            showIMG(imgId,"");
            var criteria2 = new Object();
            criteria2.TransactionID = result.TransactionID;
            var result2 =so.IDataSource.Cancel(criteria2);
            checkError("IDataSource::cancelDelContactAsync",result2,DIV_ID,imgId);
          }
         }
      }
      catch (e) {
        showIMG(imgId,"no");
        alert ("delContact: " + e);
      }
    }

    // Show Contact List
    // find the property names in AddContact()
    // Note, the contact id cannot be display correctly by javascript because
    // it is a binary number
    function showContactList(iterator) {
      var msg = "";
      try
      {
        iterator.reset();
        var item;
        while (( item = iterator.getNext()) != undefined ){
          var lastName = item['LastName'];
          var firstName = item['FirstName'];
          msg += lastName['Label'] + ":" + lastName['Value'] + "<br>";
          msg += firstName['Label'] + ":" + firstName['Value'] + "<br>";
          msg += "<br>";
        }
      }
      catch(e)
      {
        alert('<showContacList> ' + e);
      }
      return msg;
    }

    // Get the first Id
    function getFirstId(type) {

      var criteria = new Object();
      criteria.Type = type;

      var result;
      var firstId = null;
      result = so.IDataSource.GetList(criteria);
      if(!result.ErrorCode) {
        var iterator = result.ReturnValue;
        var item = iterator.getNext();
        firstId = item['id'];
      }

      return firstId;
    }

    // Get Contact List
    function getContactList(imgId) {

      var criteria = new Object();
      criteria.Type = "Contact";

      try {
        var result;
        if (!asyncMode && !cancelMode) { // sync
          result = so.IDataSource.GetList(criteria);
          if(!checkError("IDataSource::getContactList",result,DIV_ID,imgId)) {
            document.getElementById(DIV_ID).innerHTML = showContactList(result.ReturnValue);
          }
        } else if (asyncMode && !cancelMode) {// async
          // set the image id for callback7 function
          imgid_callback7 = imgId;
          result = so.IDataSource.GetList(criteria, callback7);
          if(!checkError("IDataSource::getContactListAsync",result,DIV_ID,imgId)) {
            showIMG(imgId,"");
          }
        } else if (cancelMode){ // cancel
          // set the image id for callback7 function
          imgid_callback7 = imgId;
          result = so.IDataSource.GetList(criteria, callback7);
          if(!checkError("IDataSource::cancelGetContactListAsync",result,DIV_ID,imgId)) {
            showIMG(imgId,"");
            var criteria2 = new Object();
            criteria2.TransactionID = result.TransactionID;
            var result2 =so.IDataSource.Cancel(criteria2);
            checkError("IDataSource::cancelGetContactListAsync",result2,DIV_ID,imgId);
          }
        }
      }
      catch (e) {
        showIMG(imgId,"no");
        alert ("getContactList: " + e);
      }
    }

    // Import Contact
    function importContact(imgId) {

      var impFileName = prompt("Please enter the file name", "contact-export.txt");
      if (impFileName == "")
        return;

      var contactdata = new Object();
      contactdata.SourceFile = impFileName;

      var criteria = new Object();
      criteria.Type = "Contact";
      criteria.Data = contactdata;

      try {
        var result;
        if (!asyncMode && !cancelMode) { // sync
          result = so.IDataSource.Import(criteria);
          checkError("IDataSource::Import",result,DIV_ID,imgId);
        } else if (asyncMode && !cancelMode) {// async
          // set the image id for callback4 function
          imgid_callback4 = imgId;
          result = so.IDataSource.Import(criteria, callback4);
          if(!checkError("IDataSource::ImportAsync",result,DIV_ID,imgId)) {
            showIMG(imgId,"");
          }
        } else if (cancelMode){ // cancel
          // set the image id for callback4 function
          imgid_callback4 = imgId;
          result = so.IDataSource.Import(criteria, callback4);
          if(!checkError("IDataSource::cancelImportAsync",result,DIV_ID,imgId)) {
            showIMG(imgId,"");
            var criteria2 = new Object();
            criteria2.TransactionID = result.TransactionID;
            var result2 =so.IDataSource.Cancel(criteria2);
            checkError("IDataSource::cancelImportAsync",result2,DIV_ID,imgId);
          }
        }
      }
      catch (e) {
        showIMG(imgId,"no");
        alert ("importContact: " + e);
      }
    }

    // Export Contact
    function exportContact(imgId) {

      // using the getFirstId to get the Contact Id
      // it is impossible to ask user to type the Contact Id because
      // the id is in binary and hard to be displayed by javascritp

      var contactId = getFirstId("Contact");
      if(contactId == null) {
        alert("No contact exists!");
        return;
      }

      var expFileName = prompt("Please enter the file name", "contact-export.txt");
      if (expFileName == "" || expFileName == null)
        return;

      var contactdata = new Object();
      contactdata.id = contactId;
      contactdata.DestinationFile = expFileName;

      var criteria = new Object();
      criteria.Type = "Contact";
      criteria.Data = contactdata;

      try {
        var result;
        if (!asyncMode && !cancelMode) { // sync
          result = so.IDataSource.Export(criteria);
          checkError("IDataSource::Export",result,DIV_ID,imgId);
        } else if (asyncMode && !cancelMode) {// async
          // set the image id for callback5 function
          imgid_callback5 = imgId;
          result = so.IDataSource.Export(criteria, callback5);
          if(!checkError("IDataSource::ExportAsync",result,DIV_ID,imgId)) {
            showIMG(imgId,"");
          }
        } else if (cancelMode){ // cancel
          // set the image id for callback5 function
          imgid_callback5 = imgId;
          result = so.IDataSource.Export(criteria, callback5);
          if(!checkError("IDataSource::cancelExportAsync",result,DIV_ID,imgId)) {
            showIMG(imgId,"");
            var criteria2 = new Object();
            criteria2.TransactionID = result.TransactionID;
            var result2 =so.IDataSource.Cancel(criteria2);
            checkError("IDataSource::cancelExportAsync",result2,DIV_ID,imgId);
          }
       }
      }
      catch (e) {
        showIMG(imgId,"no");
        alert ("exportContact: " + e);
      }
    }

    // Add Group
    function addGroup(imgId) {

      var groupdata = new Object();
      groupdata.GroupLabel = "TestGroupName"

      var criteria = new Object();
      criteria.Type = "Group";
      criteria.Data = groupdata;

      try {
        var result;
        if (!asyncMode && !cancelMode) { // sync
          result = so.IDataSource.Add(criteria);
          checkError("IDataSource::addGroup",result,DIV_ID,imgId);
        } else if (asyncMode && !cancelMode) {// async
          // set the image id for callback1 function
          imgid_callback1 = imgId;
          result = so.IDataSource.Add(criteria, callback1);
          if(!checkError("IDataSource::addGroupAsync",result,DIV_ID,imgId)) {
            showIMG(imgId,"");
          }
        } else if (cancelMode){ // cancel
          // set the image id for callback1 function
          imgid_callback1 = imgId;
          result = so.IDataSource.Add(criteria, callback1);
          if(!checkError("IDataSource::cancelAddGroupAsync",result,DIV_ID,imgId)) {
            showIMG(imgId,"");
            var criteria2 = new Object();
            criteria2.TransactionID = result.TransactionID;
            var result2 =so.IDataSource.Cancel(criteria2);
            checkError("IDataSource::cancelAddGroupAsync",result2,DIV_ID,imgId);
          }
        }
      }
      catch (e) {
        showIMG(imgId,"no");
        alert ("addGroup: " + e);
      }
    }

    // Delete Group
    function delGroup(imgId) {

      // using the getFirstId to get the Group Id
      // it is impossible to ask user to type the Group Id because
      // the id is in binary and hard to be displayed by javascritp

      var groupId = getFirstId("Group");
      if(groupId == null) {
        alert("No Group exists!");
        return;
      }

      var groupdata = new Object();
      groupdata.IdList = new Array();
      groupdata.IdList[0] = groupId;

      var criteria = new Object();
      criteria.Type = "Group";
      criteria.Data = groupdata;

      try {
        var result;
        if (!asyncMode && !cancelMode) { // sync
          result = so.IDataSource.Delete(criteria);
          checkError("IDataSource::delGroup",result,DIV_ID,imgId);
        } else if (asyncMode && !cancelMode) {// async
          // set the image id for callback2 function
          imgid_callback2 = imgId;
          result = so.IDataSource.Delete(criteria, callback2);
          if(!checkError("IDataSource::delGroupAsync",result,DIV_ID,imgId)) {
            showIMG(imgId,"");
          }
        } else if (cancelMode){ // cancel
          // set the image id for callback2 function
          imgid_callback2 = imgId;
          result = so.IDataSource.Delete(criteria, callback2);
          if(!checkError("IDataSource::cancelDelGroupAsync",result,DIV_ID,imgId)) {
            showIMG(imgId,"");
            var criteria2 = new Object();
            criteria2.TransactionID = result.TransactionID;
            var result2 =so.IDataSource.Cancel(criteria2);
            checkError("IDataSource::cancelDelGroupAsync",result2,DIV_ID,imgId);
          }
        }
      }
      catch (e) {
        showIMG(imgId,"no");
        alert ("delGroup: " + e);
      }
    }

    // Show Group List
    // find the property names in AddGroup()
    // Note, the group id cannot be display correctly by javascript because
    // it is a binary number
    function showGroupList(iterator) {
      var msg = "";
      try {
        iterator.reset();
        var item;
        while (( item = iterator.getNext()) != undefined ){
          msg += item['GroupLabel'] + "<br>";
          var groupList = item['Contents'];
          if(groupList == null || groupList == undefined)
            msg += "No group member.<br>";
          else {
            var i = 0;
            for (var key in groupList)
              i++;
            msg += "There are " + i +" contacts in this group.<br>";
          }
          msg += "<br>";
        }
      }
      catch(e)
      {
        alert('<showGroupList> ' + e);
      }
      return msg;
    }

    // Get Group
    function getGroupList(imgId) {

      var criteria = new Object();
      criteria.Type = "Group";

      try {
        var result;
        if (!asyncMode && !cancelMode) { // sync
          result = so.IDataSource.GetList(criteria);
          if(!checkError("IDataSource::getGroupList",result,DIV_ID,imgId)) {
            document.getElementById(DIV_ID).innerHTML = showGroupList(result.ReturnValue);
          }
        } else if (asyncMode && !cancelMode) {// async
          // set the image id for callback3 function
          imgid_callback3 = imgId;
          result = so.IDataSource.GetList(criteria, callback3);
          if(!checkError("IDataSource::getGroupListAsync",result,DIV_ID,imgId)) {
            showIMG(imgId,"");
          }
        } else if (cancelMode){ // cancel
          // set the image id for callback3 function
          imgid_callback3 = imgId;
          result = so.IDataSource.GetList(criteria, callback3);
          if(!checkError("IDataSource::cancelGetGroupListAsync",result,DIV_ID,imgId)) {
            showIMG(imgId,"");
            var criteria2 = new Object();
            criteria2.TransactionID = result.TransactionID;
            var result2 =so.IDataSource.Cancel(criteria2);
            checkError("IDataSource::cancelGetGroupListAsync",result2,DIV_ID,imgId);
          }
        }
      }
      catch (e) {
        showIMG(imgId,"no");
        alert ("getGroupList: " + e);
      }
    }

    // Organise Group
    function organiseGroup(imgId) {

      // using the getFirstId to get the Group Id
      // it is impossible to ask user to type the Group Id because
      // the id is in binary and hard to be displayed by javascritp

      var groupId = getFirstId("Group");
      if(groupId == null) {
        alert("No Group exists!");
        return;
      }

      // using the getFirstId to get the Contact Id
      // it is impossible to ask user to type the Contact Id because
      // the id is in binary and hard to be displayed by javascritp

      var contactId = getFirstId("Contact");
      if(contactId == null) {
        alert("No contact exists!");
        return;
      }

      //"Associate"
      //"Disassociate"
      var msg = "Please enter the operation type ['Associate' or 'Disassociate']";
      var optype = prompt(msg, "Associate");
      if (optype == "" || optype == null)
        return;

      var groupdata = new Object();
      groupdata.id = groupId;
      groupdata.IdList = new Array();
      groupdata.IdList[0] = contactId;

      var criteria = new Object();
      criteria.Type = "Group";
      criteria.Data = groupdata;
      criteria.OperationType = optype;

      try {
        var result;
        if (!asyncMode && !cancelMode) { // sync
          result = so.IDataSource.Organise(criteria);
          checkError("IDataSource::organiseGroup",result,DIV_ID,imgId);
        } else if (asyncMode && !cancelMode) {// async
          // set the image id for callback6 function
          imgid_callback6 = imgId;
          result = so.IDataSource.Organise(criteria, callback6);
          if(!checkError("IDataSource::organiseGroupAsync",result,DIV_ID,imgId)) {
            showIMG(imgId,"");
          }
        } else if (cancelMode){ // cancel
          // set the image id for callback6 function
          imgid_callback6 = imgId;
          result = so.IDataSource.Organise(criteria, callback6);
          if(!checkError("IDataSource::cancelOrganiseGroupAsync",result,DIV_ID,imgId)) {
            showIMG(imgId,"");
            var criteria2 = new Object();
            criteria2.TransactionID = result.TransactionID;
            var result2 =so.IDataSource.Cancel(criteria2);
            checkError("IDataSource::cancelOrganiseGroupAsync",result2,DIV_ID,imgId);
          }
        }
      }
      catch (e) {
        showIMG(imgId,"no");
        alert ("organiseGroup: " + e);
      }
    }

    // This is the asynchronous callback handler
    function callback1(transId, eventCode, result)
    {
      console.info("addAsync: transId: %d  eventCode: %d result.ErrorCode: %d", transId, eventCode, result.ErrorCode);
      checkError("IDataSource::addAsync",result,DIV_ID,imgid_callback1);
    }

    // This is the asynchronous callback handler
    function callback2(transId, eventCode, result)
    {
      console.info("delAsync: transId: %d  eventCode: %d result.ErrorCode: %d", transId, eventCode, result.ErrorCode);
      checkError("IDataSource::delAsync",result,DIV_ID,imgid_callback2);
    }

    // This is the asynchronous callback handler
    function callback3(transId, eventCode, result)
    {
      console.info("getListAsync: transId: %d  eventCode: %d result.ErrorCode: %d", transId, eventCode, result.ErrorCode);
      if(!checkError("IDataSource::getListAsync",result,DIV_ID,imgid_callback3)) {
        document.getElementById(DIV_ID).innerHTML = showGroupList(result.ReturnValue);
      }
    }

    // This is the asynchronous callback handler
    function callback4(transId, eventCode, result)
    {
      console.info("importAsync: transId: %d  eventCode: %d result.ErrorCode: %d", transId, eventCode, result.ErrorCode);
      checkError("IDataSource::importAsync",result,DIV_ID,imgid_callback4);
    }

    // This is the asynchronous callback handler
    function callback5(transId, eventCode, result)
    {
      console.info("exportAsync: transId: %d  eventCode: %d result.ErrorCode: %d", transId, eventCode, result.ErrorCode);
      checkError("IDataSource::exportAsync",result,DIV_ID,imgid_callback5);
    }

    // This is the asynchronous callback handler
    function callback6(transId, eventCode, result)
    {
      console.info("organiseAsync: transId: %d  eventCode: %d result.ErrorCode: %d", transId, eventCode, result.ErrorCode);
      checkError("IDataSource::organiseAsync",result,DIV_ID,imgid_callback6);
    }

    // This is the asynchronous callback handler
    function callback7(transId, eventCode, result)
    {
      console.info("getListAsync: transId: %d  eventCode: %d result.ErrorCode: %d", transId, eventCode, result.ErrorCode);
      if(!checkError("IDataSource::getListAsync",result,DIV_ID,imgid_callback7)) {
        document.getElementById(DIV_ID).innerHTML = showContactList(result.ReturnValue);
      }
    }