public GenericField createGenericField(RightNowCustomObjectFieldAttribute attribute, object value)
        {
            GenericField genericField = new GenericField();

            genericField.name      = attribute.Name;
            genericField.DataValue = new DataValue();

            ItemsChoiceType fieldType = ItemsChoiceType.StringValue;

            if (attribute.FieldType != null)
            {
                fieldType = attribute.FieldType;
            }

            if (fieldType == ItemsChoiceType.NamedIDValue)
            {
                NamedID accountID = new NamedID();
                accountID.ID = new ID();
                long id = 0;
                Int64.TryParse(value.ToString(), out id);
                accountID.ID.id              = id;
                accountID.ID.idSpecified     = true;
                genericField.DataValue.Items = new object[] { accountID };
            }
            else
            {
                genericField.DataValue.Items = new object[] { value };
            }
            //genericField.dataType = (ConnectService.DataTypeEnum)fieldType;
            genericField.DataValue.ItemsElementName = new ItemsChoiceType[] { fieldType };
            return(genericField);
        }
Пример #2
0
    private Contact Contactinfo()
    {
        Contact    newContact = new Contact();
        PersonName personName = new PersonName();

        personName.First = "conatctname";
        personName.Last  = "conatctlastname";
        newContact.Name  = personName;
        Email[] emailArray = new Email[1];
        emailArray[0]                 = new Email();
        emailArray[0].action          = ActionEnum.add;
        emailArray[0].actionSpecified = true;
        emailArray[0].Address         = "*****@*****.**";
        NamedID addressType   = new NamedID();
        ID      addressTypeID = new ID();

        addressTypeID.id               = 1;
        addressType.ID                 = addressTypeID;
        addressType.ID.idSpecified     = true;
        emailArray[0].AddressType      = addressType;
        emailArray[0].Invalid          = false;
        emailArray[0].InvalidSpecified = true;
        newContact.Emails              = emailArray;
        return(newContact);
    }
        internal static AnalyticsReportFilter GetStringAnalyticsReportFilter(string Name, String searchPhrase, int searchOperator, bool specifyAttributes, bool specifyDatatype, bool specifyOperator)
        {
            //Assigning the filter as defined on the RightNow Analytics Report
            AnalyticsReportFilter filter = new AnalyticsReportFilter();

            if (specifyAttributes)
            {
                AnalyticsReportFilterAttributes attribute = new AnalyticsReportFilterAttributes();
                attribute.Editable = false;
                attribute.Required = false;
                filter.Attributes  = attribute;
            }

            if (specifyDatatype)
            {
                NamedID datatype = new NamedID();
                datatype.Name   = Name.GetType().ToString();
                filter.DataType = datatype;
            }

            filter.Name = Name;
            if (specifyOperator)
            {
                filter.Operator = new NamedID {
                    ID = new ID {
                        id = searchOperator, idSpecified = true
                    }
                }
            }
            ;
            filter.Values = new String[] { searchPhrase };

            return(filter);
        }
        /// <summary>
        /// Create Named ID type Data Value for NamedID as input
        /// </summary>
        /// <param name="namedvalue"></param>
        /// <returns></returns>
        private DataValue createNamedID(NamedID namedvalue)
        {
            DataValue dv = new DataValue();

            dv.Items            = new Object[] { namedvalue };
            dv.ItemsElementName = new ItemsChoiceType[] { ItemsChoiceType.NamedIDValue };
            return(dv);
        }
        internal static NamedID CreateNamedID(string name)
        {
            var result = new NamedID
            {
                Name = name
            };

            return(result);
        }
Пример #6
0
        private void updateIncidents(int incidentContactId)
        {
            // query incidents ids with the _socialChannelAccountId
            String query = "select I.ID from Incident I where I.CustomFields.Accelerator.srm_social_channel_account_id=" + _socialChannelAccountId;

            String[] rowData = null;

            rowData = ConfigurationSetting.rnSrv.queryData(query);

            if (rowData.Length == 0)
            {
                return;
            }

            RNObject[] updateIncidents = new RNObject[rowData.Length];
            int        i = 0;
            UpdateProcessingOptions updateProcessingOptions = new UpdateProcessingOptions();

            updateProcessingOptions.SuppressExternalEvents = false;
            updateProcessingOptions.SuppressRules          = false;
            foreach (String incidentIdString in rowData)
            {
                Incident incidentToUpdate   = new Incident();
                ID       incidentToUpdateId = new ID();
                incidentToUpdateId.id          = Convert.ToInt32(incidentIdString);
                incidentToUpdateId.idSpecified = true;

                incidentToUpdate.ID = incidentToUpdateId;

                NamedID contactIdNamedID =
                    new NamedID
                {
                    ID = new ID
                    {
                        id          = incidentContactId,
                        idSpecified = true
                    }
                };

                incidentToUpdate.PrimaryContact         = new IncidentContact();
                incidentToUpdate.PrimaryContact.Contact = contactIdNamedID;
                updateIncidents[i] = incidentToUpdate;
                i++;
                ConfigurationSetting.logWrap.DebugLog(logMessage: String.Format(Properties.Resources.UpdateIncidentMessage, incidentToUpdateId.id, incidentContactId));
            }

            ClientInfoHeader clientInfoHeader = new ClientInfoHeader();

            clientInfoHeader.AppID = "Update incidents";

            ConfigurationSetting.client.Update(clientInfoHeader, updateIncidents, updateProcessingOptions);
        }
        internal static NamedID CreateNamedID(long id)
        {
            var result = new NamedID
            {
                ID = new ID
                {
                    idSpecified = true,
                    id          = id
                },
            };

            return(result);
        }
        /// <summary>
        /// Create Named ID type data value for Name
        /// </summary>
        /// <param name="name"></param>
        /// <returns> DataValue</returns>
        private DataValue createNamedIDDataValueForName(string name)
        {
            NamedID namedID = new NamedID();

            namedID.Name = name;

            DataValue dv = new DataValue();

            dv.Items            = new Object[] { namedID };
            dv.ItemsElementName = new ItemsChoiceType[] { ItemsChoiceType.NamedIDValue };

            return(dv);
        }
Пример #9
0
        /// <summary>
        /// Create a generic namedID field
        /// </summary>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static GenericField CreateGenericNamedIDField(string name, NamedID value)
        {
            GenericField f = new GenericField();

            f.dataType          = DataTypeEnum.NAMED_ID;
            f.dataTypeSpecified = true;
            f.name                       = name;
            f.DataValue                  = new DataValue();
            f.DataValue.Items            = new object[1];
            f.DataValue.Items[0]         = value;
            f.DataValue.ItemsElementName = new ItemsChoiceType[] { ItemsChoiceType.NamedIDValue };

            return(f);
        }
        /// <summary>
        /// Create Named ID type data value
        /// </summary>
        /// <param name="idVal"></param>
        /// <returns> DataValue</returns>
        private DataValue createNamedIDDataValue(long idVal)
        {
            ID id = new ID();

            id.id          = idVal;
            id.idSpecified = true;

            NamedID namedID = new NamedID();

            namedID.ID = id;

            DataValue dv = new DataValue();

            dv.Items            = new Object[] { namedID };
            dv.ItemsElementName = new ItemsChoiceType[] { ItemsChoiceType.NamedIDValue };

            return(dv);
        }
        public void DestroyReasoncodes(long config)
        {
            List <RNObject> destroyfields = new List <RNObject>();

            List <ScreenPopOptions> profiledata = new List <ScreenPopOptions>(GetObjects <ScreenPopOptions>(string.Format(" where ScreenPopConfigID={0}", config)));

            foreach (ScreenPopOptions rn in profiledata)
            {
                _icGenericObject            = new GenericObject();
                _rnObjType.Namespace        = OracleCtiObjectStrings.ScreenPopPackageName;
                _rnObjType.TypeName         = OracleCtiObjectStrings.ScreenPopOptions;
                _icGenericObject.ObjectType = _rnObjType;
                NamedID relationid = new NamedID();
                ID      incID      = new ID();
                incID.id          = config;
                incID.idSpecified = true;
                relationid.ID     = incID;

                ID rowid = new ID();
                rowid.id            = rn.ID;
                rowid.idSpecified   = true;
                _icGenericObject.ID = rowid;

                List <GenericField> gfs = new List <GenericField>();
                //gfs.Add(createGenericField("AgentEntityID", ItemsChoiceType.NamedIDValue, relationid));
                _icGenericObject.GenericFields = gfs.ToArray();
                destroyfields.Add(_icGenericObject);
            }

            if (destroyfields.Count() > 0)
            {
                DestroyProcessingOptions drop = new DestroyProcessingOptions();
                drop.SuppressExternalEvents = false;
                drop.SuppressRules          = false;
                DestroyRequest  destroyReq = new DestroyRequest(getClientInfoHeader(), destroyfields.ToArray(), drop);
                DestroyResponse destroyRes = getChannel().Destroy(destroyReq);
            }
        }
Пример #12
0
 private Contact populateContactInfo(string fname,string lname,string email)
 {
     Contact newContact = new Contact();
     PersonName personName = new PersonName();
     personName.First = fname;
     personName.Last = lname;
     newContact.Name = personName;
     Email[] emailArray = new Email[1];
     emailArray[0] = new Email();
     emailArray[0].action = ActionEnum.add;
     emailArray[0].actionSpecified = true;
     emailArray[0].Address = email;
     NamedID addressType = new NamedID();
     ID addressTypeID = new ID();
     addressTypeID.id = 1;
     addressType.ID = addressTypeID;
     addressType.ID.idSpecified = true;
     emailArray[0].AddressType = addressType;
     emailArray[0].Invalid = false;
     emailArray[0].InvalidSpecified = true;
     newContact.Emails = emailArray;
     return newContact;
 }
        internal static AnalyticsReportFilter GetDateTimeRangeAnalyticsReportFilter(string Name, DateTime fromDateTime, DateTime toDateTime, bool specifyAttributes, bool specifyDatatype, bool specifyOperator, bool appendEndingZ)
        {
            //Assigning the filter as defined on the RightNow Analytics Report
            AnalyticsReportFilter filter = new AnalyticsReportFilter();

            if (specifyAttributes)
            {
                AnalyticsReportFilterAttributes attribute = new AnalyticsReportFilterAttributes();
                attribute.Editable = false;
                attribute.Required = false;
                filter.Attributes  = attribute;
            }

            if (specifyDatatype)
            {
                NamedID datatype = new NamedID();
                datatype.Name   = "Date Time";
                filter.DataType = datatype;
            }

            filter.Name = Name;
            if (fromDateTime > DateTime.MinValue && toDateTime > DateTime.MinValue)
            {
                if (specifyDatatype)
                {
                    filter.Operator = new NamedID {
                        ID = new ID {
                            id = ANALYTICS_FILTER_RANGE, idSpecified = true
                        }
                    }
                }
                ;
                if (appendEndingZ)
                {
                    filter.Values = new[] { fromDateTime.ToString("s") + "Z", toDateTime.ToString("s") + "Z" }
                }
                ;
                else
                {
                    filter.Values = new[] { fromDateTime.ToString("s"), toDateTime.ToString("s") }
                };
            }
            else
            {
                if (fromDateTime > DateTime.MinValue)
                {
                    if (specifyDatatype)
                    {
                        filter.Operator = new NamedID {
                            ID = new ID {
                                id = ANALYTICS_FILTER_GREATER_THAN_OR_EQUAL, idSpecified = true
                            }
                        }
                    }
                    ;
                    if (appendEndingZ)
                    {
                        filter.Values = new[] { fromDateTime.ToString("s") + "Z" }
                    }
                    ;
                    else
                    {
                        filter.Values = new[] { fromDateTime.ToString("s") }
                    };
                }
                else if (toDateTime > DateTime.MinValue)
                {
                    if (specifyDatatype)
                    {
                        filter.Operator = new NamedID {
                            ID = new ID {
                                id = ANALYTICS_FILTER_LESS_THAN_OR_EQUAL, idSpecified = true
                            }
                        }
                    }
                    ;
                    if (appendEndingZ)
                    {
                        filter.Values = new[] { toDateTime.ToString("s") + "Z" }
                    }
                    ;
                    else
                    {
                        filter.Values = new[] { toDateTime.ToString("s") }
                    };
                }
            }

            return(filter);
        }
Пример #14
0
        /*  this method is called from framework to show the report row (data)
         *  It combines the incident report (ConfigurationSetting.incidentsByContactReportID)
         *  and the ServiceRequest.LookupSRbyContactPartyID(contactPartyID)
         *  Currently this list is only showing certain fields (because of combining 2 lists with common fields)
         *  The Right Now incidents by a contact report is hidden, meaning the Report control of a contact
         *  workspace tab is based on the EBS Service Request List Table report definition
         *  Also, do not change the default column heading of Right Now incidents by a contact report
         *  (they are hard coded to uppercase). Because they are hidden anyway.
         *  The EBS Service Request List Table report definition column headings can be changed and those are
         *  the ones being displayed.
         */
        public override IList <IReportRow> GetRows(IList <string> columns, IReportFilterNode filterNode)
        {
            IList <IReportRow> reportRows = new List <IReportRow>();
            IRecordContext     _context   = ((EBSVirtualReportTablesPackage)this.Parent)._globalContext.AutomationContext.CurrentWorkspace;

            if (_context == null)
            {
                return(reportRows);
            }

            IContact contactRecord = _context.GetWorkspaceRecord(RightNow.AddIns.Common.WorkspaceRecordType.Contact) as IContact;

            /* report framework refresh every 30 sec (default) even though the tab is not active
             * so need to check contactRecord for null (when the editor is different)
             */
            if (contactRecord == null)
            {
                return(reportRows);
            }

            int contactPartyID = 0;

            // get the ebs contact party custom attribute on the contact workspace
            contactPartyID = getContactPartyIdCustomAttr(contactRecord);

            // following to get the rNow incidents report and filter is the rNow contactID
            AnalyticsReport reportIncident = new AnalyticsReport();
            ID rId = new ID();

            rId.id            = ConfigurationSetting.incidentsByContactReportID;
            rId.idSpecified   = true;
            reportIncident.ID = rId;
            byte[] outByte = new byte[1000];

            AnalyticsReportFilter[] filter = new AnalyticsReportFilter[3];
            filter[0] = new AnalyticsReportFilter();

            String[] filterString = new String[1];
            filterString[0]  = "" + contactRecord.ID;
            filter[0].Values = filterString;
            filter[0].Name   = "Contact"; // incidents by a contact, thus Contact filter

            NamedID datatype = new NamedID();

            datatype.Name      = "Integer";
            filter[0].DataType = datatype;

            reportIncident.Filters = filter;

            ClientInfoHeader _cih = new ClientInfoHeader();

            _cih.AppID = "Accelerator Report Add-In";

            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Start();
            CSVTableSet tableSet = ConfigurationSetting.client.RunAnalyticsReport(
                _cih, reportIncident, 100, 0, "\t", false, false, out outByte
                );

            stopwatch.Stop();
            string logMessage = "Called RightNowSyncPortClient.RunAnalyticsReport." +
                                "reportID: " + ConfigurationSetting.incidentsByContactReportID;

            ConfigurationSetting.logWrap.DebugLog(0, contactRecord.ID, logMessage: logMessage, timeElapsed: (int)stopwatch.ElapsedMilliseconds);

            CSVTable[] csvTables = tableSet.CSVTables;
            CSVTable   table     = csvTables[0];

            string[] rowData             = table.Rows;
            int      rNowIncidentCount   = table.Rows.Length;
            int      srVirtualTableCount = this.Columns.Count;

            string[] colHeadingIncidentReport = table.Columns.Split('\t');

            foreach (String commaRow in table.Rows)
            {
                ReportDataRow reportDataRow = new ReportDataRow(srVirtualTableCount);
                string[]      colValue      = commaRow.Split('\t');

                // the report output is stored as <columnHeading, value>
                Dictionary <string, string> dictRow = new Dictionary <string, string>();
                int i = 0;
                foreach (string val in colValue)
                {   /* make the column heading upper case (because the custom attribute heading
                     * in the report designer sometime all in lower case, sometime the reverse)
                     */
                    dictRow.Add(colHeadingIncidentReport[i].ToUpper(), val);
                    i++;
                }

                addRnowIncidentRow(ref columns, ref reportDataRow, ref reportRows, dictRow);
            }

            if (contactPartyID > 0)
            {
                ServiceRequest[] sRs = ServiceRequest.LookupSRbyContactPartyID(contactPartyID, 0, contactRecord.ID);

                foreach (ServiceRequest req in sRs)
                {
                    ReportDataRow reportDataRow = new ReportDataRow(this.Columns.Count);
                    if (req != null) // live ebs row 316 of 319 of contact 4431 return null
                    {
                        addEBSsrRow(ref columns, ref reportDataRow, ref reportRows, req);
                    }
                }
            }
            return(reportRows);
        }
Пример #15
0
        /*  this method is called from framework to show the report row (data)
         *  refer to QA 140910-000144 for the story
         *  It combines the incident report (ConfigurationSetting.incidentsByContactReportID)
         *  and the ServiceRequest.LookupSRbyContactPartyID(contactPartyID)
         *  Currently this list is only showing certain fields (because of combining 2 lists with common fields)
         *  The Right Now incidents by a contact report is hidden, meaning the Report control of a contact
         *  workspace tab is based on the Siebel Service Request List Table report definition
         *  Also, do not change the default column heading of Right Now incidents by a contact report
         *  (they are hard coded to uppercase). Because they are hidden anyway.
         *  The Siebel Service Request List Table report definition column headings can be changed and those are
         *  the ones being displayed.
         */
        public override IList<IReportRow> GetRows(IList<string> columns, IReportFilterNode filterNode)
        {
            IList<IReportRow> reportRows = new List<IReportRow>();
            IRecordContext _context = ((SiebelVirtualReportTablesPackage)this.Parent)._globalContext.AutomationContext.CurrentWorkspace;

            if (_context == null)
                return reportRows;

            IContact contactRecord = _context.GetWorkspaceRecord(RightNow.AddIns.Common.WorkspaceRecordType.Contact) as IContact;

             /* if auto refresh every x sec is enabled even though the tab is not active
             * so need to check contactRecord for null (when the editor is different)
             */
            if (contactRecord == null)
                return reportRows;

            string contactPartyID = null;
            // get the ebs contact party custom attribute on the contact workspace
            contactPartyID = getContactPartyIdCustomAttr(contactRecord);

            // following to get the rNow incidents report and filter is the rNow contactID
            AnalyticsReport reportIncident = new AnalyticsReport();
            ID rId = new ID();
            rId.id = ConfigurationSetting.incidentsByContactReportID;
            rId.idSpecified = true;
            reportIncident.ID = rId;
            byte[] outByte = new byte[1000];

            AnalyticsReportFilter[] filter = new AnalyticsReportFilter[3];
            filter[0] = new AnalyticsReportFilter();

            String[] filterString = new String[1];
            filterString[0] = "" + contactRecord.ID;
            filter[0].Values = filterString;
            filter[0].Name = "Contact"; // incidents by a contact, thus Contact filter

            NamedID datatype = new NamedID();
            datatype.Name = "Integer";
            filter[0].DataType = datatype;

            reportIncident.Filters = filter;

            ClientInfoHeader _cih = new ClientInfoHeader();
            _cih.AppID = "Accelerator Report Add-In";
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            CSVTableSet tableSet = ConfigurationSetting.client.RunAnalyticsReport(
              _cih, reportIncident, 100, 0, "\t", false, false, out outByte
                );
            stopwatch.Stop();
            string logMessage = "Called RightNowSyncPortClient.RunAnalyticsReport." +
                "reportID: " + ConfigurationSetting.incidentsByContactReportID;
            ConfigurationSetting.logWrap.DebugLog(0, contactRecord.ID, logMessage: logMessage, timeElapsed: (int)stopwatch.ElapsedMilliseconds);

            CSVTable[] csvTables = tableSet.CSVTables;
            CSVTable table = csvTables[0];
            string[] rowData = table.Rows;
            int rNowIncidentCount = table.Rows.Length;
            int srVirtualTableCount = this.Columns.Count;
            string[] colHeadingIncidentReport = table.Columns.Split('\t');

            foreach (String commaRow in table.Rows)
            {
                ReportDataRow reportDataRow = new ReportDataRow(srVirtualTableCount);
                string[] colValue = commaRow.Split('\t');

                // the report output is stored as <columnHeading, value>
                Dictionary<string, string> dictRow = new Dictionary<string, string>();
                int i = 0;
                foreach (string val in colValue)
                {   /* make the column heading upper case (because the custom attribute heading
                     * in the report designer sometime all in lower case, sometime the reverse)
                     */
                    dictRow.Add(colHeadingIncidentReport[i].ToUpper(), val);
                    i++;
                }

                addRnowIncidentRow(ref columns, ref reportDataRow, ref reportRows, dictRow);
            }

            if (contactPartyID != null)
            {
                ServiceRequest[] sRs = ServiceRequest.LookupSRbyContactPartyID(columns, contactPartyID, 0, contactRecord.ID);

                if (sRs == null)
                    return reportRows;

                foreach (ServiceRequest req in sRs)
                {
                    ReportDataRow reportDataRow = new ReportDataRow(this.Columns.Count);
                    if (req != null) // live ebs row 316 of 319 of contact 4431 return null
                        addSiebelSrRow(ref columns, ref reportDataRow, ref reportRows, req);
                }
            }
            return reportRows;
        }
Пример #16
0
        /// <summary>
        /// Method called to update the social channel
        /// </summary>
        /// <param name="incident"></param>
        private void updateSocialChannelAccount(IIncident incident)
        {
            // get it again
            _socialChannelAccountId = ConfigurationSetting.getSrmStringCustomAttrInt(incident, "srm_social_channel_account_id");

            if (_socialChannelAccountId == 0)
            {
                ConfigurationSetting.logWrap.DebugLog(logMessage: String.Format(Properties.Resources.SocialChannelEmptyError, incident.ID));
                return;
            }

            /* Custom Object: SocialChannelAccount
             *
             */
            int incidentContactId = 0;

            foreach (IInc2Contact c in incident.Contact)
            {
                if (c.Prmry == true)
                {
                    incidentContactId = (int)c.Cid;
                }
            }

            Boolean toUpdate = false;

            // if incident's contact is changed
            if (_incidentContactIdWhenLoaded != incidentContactId)
            {
                // check if updated incidentContactId same as SocialChannelAccount.ContactId
                if (_socialChannelAccountId != 0 && incidentContactId != _socialChannelAccountId)
                {
                    DialogResult result = MessageBox.Show(String.Format(Properties.Resources.ChangeContactReassignMessage, _socialChannelUserName), Properties.Resources.Info, MessageBoxButtons.OK, MessageBoxIcon.Information);
                    if (result == DialogResult.OK)
                    {
                        toUpdate = true;
                    }
                }
                // update in Accelerator.SocialChannelAccount
                if (toUpdate)
                {
                    // create a row in SocialChannelAccount
                    ClientInfoHeader clientInfoHeader = new ClientInfoHeader();
                    clientInfoHeader.AppID = "Update a SocialChannelAccount";

                    GenericObject go = new GenericObject();

                    //Set the object type
                    RNObjectType objType = new RNObjectType();
                    objType.Namespace = "Accelerator";
                    objType.TypeName  = "SocialChannelAccount";
                    go.ObjectType     = objType;

                    List <GenericField> gfs = new List <GenericField>();

                    ID socialAccountId = new ID();
                    socialAccountId.id          = _socialChannelAccountId;
                    socialAccountId.idSpecified = true;

                    go.ID = socialAccountId;

                    NamedID contactIdNamedID =
                        new NamedID
                    {
                        ID = new ID
                        {
                            id          = incidentContactId,
                            idSpecified = true
                        }
                    };

                    gfs.Add(createGenericField("ContactId", ItemsChoiceType.NamedIDValue, contactIdNamedID));
                    go.GenericFields = gfs.ToArray();

                    RNObject[] objects = new RNObject[] { go };

                    UpdateProcessingOptions cpo = new UpdateProcessingOptions();
                    cpo.SuppressExternalEvents = false;
                    cpo.SuppressRules          = false;

                    ConfigurationSetting.logWrap.DebugLog(logMessage: String.Format(Properties.Resources.UpdateSocialChannelMessage, _socialChannelAccountId, incidentContactId));
                    ConfigurationSetting.client.Update(clientInfoHeader, objects, cpo);

                    DialogResult result = MessageBox.Show(String.Format(Properties.Resources.ReassignAllIncidentsMessage, _socialChannelUserName), Properties.Resources.Info, MessageBoxButtons.OKCancel, MessageBoxIcon.Information);
                    if (result == DialogResult.OK)
                    {
                        updateIncidents(incidentContactId);
                    }
                }
            }
        }