public FpgaTimebaseTask(DeviceSettings deviceSettings, okCFrontPanel opalKellyDevice, SequenceData sequence, double masterClockPeriod, out int nSegments, bool useRfModulation, bool assymetric)
            : base()
        {
            com.opalkelly.frontpanel.okCFrontPanel.ErrorCode errorCode;

            this.opalKellyDevice = opalKellyDevice;

            this.masterClockPeriod = masterClockPeriod;

            TimestepTimebaseSegmentCollection segments = sequence.generateVariableTimebaseSegments(SequenceData.VariableTimebaseTypes.AnalogGroupControlledVariableFrequencyClock,
                                                                                                   masterClockPeriod);

            this.max_elapsedtime_ms = (UInt32)((sequence.SequenceDuration * 1000.0) + 100);

            byte[] data = FpgaTimebaseTask.createByteArray(segments, sequence, out nSegments, masterClockPeriod, assymetric);

            // Send the device an abort trigger.
            errorCode = opalKellyDevice.ActivateTriggerIn(0x40, 1);
            if (errorCode != okCFrontPanel.ErrorCode.NoError)
            {
                throw new Exception("Unable to set abort trigger to FPGA device. Error code " + errorCode.ToString());
            }

            UInt16 wireInValue = 0;

            if (deviceSettings.StartTriggerType != DeviceSettings.TriggerType.SoftwareTrigger)
            {
                wireInValue += 1;
            }

            if (useRfModulation)
            {
                wireInValue += 2;
            }

            setWireInValue(0x00, wireInValue);

            setWireInValue(0x01, deviceSettings.RetriggerDebounceSamples);

            opalKellyDevice.UpdateWireIns();

            // pipe the byte stream to the device
            int xfered = opalKellyDevice.WriteToPipeIn(0x80, data.Length, data);

            if (xfered != data.Length)
            {
                throw new Exception("Error when piping clock data to FPGA device. Sent " + xfered + " bytes instead of " + data.Length + "bytes.");
            }
        }
        /// <summary>
        /// This method should be run after setSettings and setSequence to ensure sane data.
        /// </summary>
        /// <param name="listIterationNumber"></param>
        /// <returns></returns>
        public override BufferGenerationStatus generateBuffers(int listIterationNumber)
        {
            lock (remoteLockObj)
            {
                clientFinishedRun = false;

                lock (taskFinishTimeClicks)
                {
                    taskFinishTimeClicks.Clear();
                }

                expectedNumberOfSamplesGenerated = new Dictionary<string, long>();

                try
                {

                    messageLog(this, new MessageEvent("Stopping and cleaning up old tasks."));
                    if (!stopAndCleanupTasks())
                        return BufferGenerationStatus.Failed_Buffer_Underrun;

                    messageLog(this, new MessageEvent("Generating buffers."));
                    if (settings == null)
                    {
                        messageLog(this, new MessageEvent("Unable to generate buffers. Null settings."));
                        displayError();
                        return BufferGenerationStatus.Failed_Settings_Null;
                    }
                    if (sequence == null)
                    {
                        messageLog(this, new MessageEvent("Unable to generate buffers. Null sequence."));
                        displayError();
                        return BufferGenerationStatus.Failed_Sequence_Null;
                    }

                    // This is redundant.
                    sequence.ListIterationNumber = listIterationNumber;

                    #region Generate variable timebase FPGA task

                    if (serverSettings.UseOpalKellyFPGA)
                    {
                        fpgaTasks = new Dictionary<string, FpgaTimebaseTask>();
                        foreach (DeviceSettings fsettings in myServerSettings.myDevicesSettings.Values)
                        {
                            if (fsettings.IsFPGADevice)
                            {
                                if (fsettings.DeviceEnabled)
                                {
                                    if (fsettings.UsingVariableTimebase)
                                    {
                                        if (opalKellyDeviceNames.Contains(fsettings.DeviceName))
                                        {
                                            messageLog(this, new MessageEvent("Creating Variable Timebase Task on fpga device " + fsettings.DeviceName + "."));
                                            int nSegs = 0;
                                            FpgaTimebaseTask ftask = new FpgaTimebaseTask(fsettings,
                                                opalKellyDevices[opalKellyDeviceNames.IndexOf(fsettings.DeviceName)],
                                                sequence,
                                                Common.getPeriodFromFrequency(fsettings.SampleClockRate),
                                                out nSegs,
                                                myServerSettings.UseFpgaRfModulatedClockOutput,
                                                myServerSettings.UseFpgaAssymetricDutyCycleClocking);
                                            fpgaTasks.Add(fsettings.DeviceName, ftask);
                                            messageLog(this, new MessageEvent("...Done (" + nSegs + " segments total)"));
                                        }
                                        else
                                        {
                                            messageLog(this, new MessageEvent("FPGA device " + fsettings.DeviceName + " is not programmed. Please press the refresh hardware button to program it. Or, if variable timebase on this device is not desired, set DeviceEnabled to false in this device's settings."));
                                            messageLog(this, new MessageEvent("Unable to create variable timebase output on FPGA device. Aborting buffer generation."));
                                            displayError();
                                            return BufferGenerationStatus.Failed_Invalid_Data;
                                        }
                                    }
                                }
                            }
                        }
                    }

                    #endregion

                    #region Generate variable timebase clock output task

                    // If a variable timebase is to be generated by a NI digital output,
                    // then generate the variable timebase output task.
                    if (serverSettings.VariableTimebaseOutputChannel != null && serverSettings.VariableTimebaseOutputChannel != "")
                    {
                        messageLog(this, new MessageEvent("Generating Variable Timebase output clock buffer."));

                        bool otherChannelsOnVariableTimebaseDeviceAlsoUsed = false;
                        foreach (HardwareChannel hc in usedDigitalChannels.Values)
                        {
                            // if the digital channel for the variable timebase is also bound to a logical channel,
                            // complain
                            if (hc.physicalChannelName().ToUpper() == serverSettings.VariableTimebaseOutputChannel)
                            {
                                messageLog(this, new MessageEvent("The variable timebase clock output channel also has a sequence-specified channel bound to it. This is not allowed."));
                                displayError();
                                return BufferGenerationStatus.Failed_Invalid_Data;
                            }

                            // detect if the variable timebase output channel is on a device which also has other
                            // used digital channels.
                            if (hc.DeviceName.ToUpper() == HardwareChannel.parseDeviceNameStringFromPhysicalChannelString(serverSettings.VariableTimebaseOutputChannel).ToUpper())
                            {
                                otherChannelsOnVariableTimebaseDeviceAlsoUsed = true;
                            }
                        }

                        // if the variable timebase output is on the same
                        // device as other digital output channels,
                        // then create the variable timebase task
                        // with the fancy function that can create a shared buffer
                        // for the variable timebase and for the digital output.
                        // Otherwise, use the simpler function which cannot.
                        // NOTE: The above comment is currently incorrect. The variable timebase output
                        // cannot currently exist on the same task as other used channels. Atticus will
                        // complain in a descriptive way if this is attempted.
                        if (otherChannelsOnVariableTimebaseDeviceAlsoUsed)
                        {

                            string variableTimebaseOutputDevice = HardwareChannel.parseDeviceNameStringFromPhysicalChannelString(serverSettings.VariableTimebaseOutputChannel);

                            if (!variableTimebaseOutputDevice.Contains("Dev"))
                            {
                                messageLog(this, new MessageEvent("******* You are using a NI device named " + variableTimebaseOutputDevice + ". This does not follow the convention of naming your devices Dev1, Dev2, Dev3, etc. Unpredictable results are possible! Not recommended! *******"));
                                displayError();
                            }

                            // NOTE! This call will modify useDigitalChannels. Those digital channels which
                            // get their buffers generated within this task will be removed. This is useful,
                            // because we may later in generateBuffers() do another
                            // call to generate another task on this device, but
                            // we want that call to only generate buffers for the remaining digital channels.

                            int nDigitals = usedDigitalChannels.Count;

                            if (myServerSettings.myDevicesSettings.ContainsKey(variableTimebaseOutputDevice))
                            {
                                messageLog(this, new MessageEvent("Variable timebase output device [" + variableTimebaseOutputDevice + "]"));

                                variableTimebaseClockTask = DaqMxTaskGenerator.createDaqMxDigitalOutputAndVariableTimebaseSource(
                                    serverSettings.VariableTimebaseOutputChannel,
                                    null,
                                    serverSettings.VariableTimebaseMasterFrequency,
                                    sequence,
                                    serverSettings.VariableTimebaseType,
                                    variableTimebaseOutputDevice,
                                    serverSettings.myDevicesSettings[variableTimebaseOutputDevice],
                                    settings,
                                    usedDigitalChannels,
                                    serverSettings);
                            }
                            else
                            {
                                messageLog(this, new MessageEvent("***** Server does not contain device named " + variableTimebaseOutputDevice));
                                displayError();
                                return BufferGenerationStatus.Failed_Invalid_Data;
                            }

                            variableTimebaseClockTask.Done += new TaskDoneEventHandler(aTaskFinished);

                            int consumedChannels = nDigitals - usedDigitalChannels.Count;
                            messageLog(this, new MessageEvent(consumedChannels.ToString() + " output buffers also generated. Note, buffer generation on device " + variableTimebaseOutputDevice + " may skip due to no additional channels."));
                        }
                        else
                        {

                            string variableTimebaseOutputDevice = HardwareChannel.parseDeviceNameStringFromPhysicalChannelString(serverSettings.VariableTimebaseOutputChannel);

                            if (myServerSettings.myDevicesSettings.ContainsKey(variableTimebaseOutputDevice))
                            {
                                messageLog(this, new MessageEvent("Variable timebase output device [" + variableTimebaseOutputDevice + "]"));

                                variableTimebaseClockTask = DaqMxTaskGenerator.createDaqMxVariableTimebaseSource(
                                    serverSettings.VariableTimebaseOutputChannel,
                                    serverSettings.VariableTimebaseMasterFrequency,
                                    sequence,
                                    serverSettings.VariableTimebaseType,
                                    serverSettings,
                                    serverSettings.myDevicesSettings[variableTimebaseOutputDevice]);
                            }
                            else
                            {
                                messageLog(this, new MessageEvent("***** Server does not contain device named " + variableTimebaseOutputDevice));
                                displayError();
                                return BufferGenerationStatus.Failed_Invalid_Data;
                            }

                            variableTimebaseClockTask.Done += new TaskDoneEventHandler(aTaskFinished);
                        }

                        try
                        {

                            messageLog(this, new MessageEvent("Variable timebase output clock buffer generated successfully. " + variableTimebaseClockTask.Stream.Buffer.OutputBufferSize + " samples per channel. On board buffer size: " + variableTimebaseClockTask.Stream.Buffer.OutputOnBoardBufferSize + " samples per channel."));
                        }
                        catch (Exception)
                        {
                            messageLog(this, new MessageEvent("Unable to poll task for buffer information. This is probably not a problem."));
                        }
                    }
                    else
                    {
                        variableTimebaseClockTask = null;
                    }

                    #endregion

                    #region Analog and Digital NI device generation (daqMx)

                    /// Is multi-threaded buffer generation enabled?
                    if (!serverSettings.UseMultiThreadedDaqmxBufferGeneration)
                    {
                        // if not, generate each buffer sequentially, in this thread.
                        foreach (string dev in usedDaqMxDevices)
                        {
                            if (!dev.Contains("Dev"))
                            {
                                messageLog(this, new MessageEvent("******* You are using a NI device named " + dev + ". This does not follow the convention of naming your devices Dev1, Dev2, Dev3, etc. Unpredictable results are possible! Not recommended! *******"));
                                displayError();
                            }

                            generateDaqMxTaskOnDevice(dev);
                        }
                    }
                    else
                    {
                        // if yes, generate each buffer in a parallel thread.

                        List<Thread> generateThreads = new List<Thread>();
                        try
                        {

                            messageLog(this, new MessageEvent("Generating buffers in parallel..."));
                            foreach (string dev in usedDaqMxDevices)
                            {
                                if (!dev.Contains("Dev"))
                                {
                                    messageLog(this, new MessageEvent("******* You are using a NI device named " + dev + ". This does not follow the convention of naming your devices Dev1, Dev2, Dev3, etc. Unpredictable results are possible! Not recommended! *******"));
                                    displayError();
                                }
                                Thread thread = new Thread(generateDaqMxTaskOnDevice);
                                generateThreads.Add(thread);

                                thread.Start(dev);
                            }
                            // wait for threads to all complete.

                            foreach (Thread thread in generateThreads)
                            {
                                thread.Join();
                            }
                            messageLog(this, new MessageEvent("...done."));
                        }
                        finally
                        {
                            foreach (Thread thread in generateThreads)
                            {
                                thread.Abort();
                            }
                        }

                    }

                    #endregion

                    // This is where the analog input task is defined
                    #region Analog In Task

                    //First we determine if an analog in task should be created
                    foreach (DeviceSettings ds in AtticusServer.server.serverSettings.myDevicesSettings.Values)
                    {
                        analogInCardDetected |= (ds.DeviceDescription.Contains("6259") || ds.DeviceDescription.Contains("6363")) && ds.AnalogInEnabled; // program will also support PXIe-6363 cards
                    }

                    if (analogInCardDetected)
                    {
                        // Creates the analog in task
                        analogS7ReadTask = new Task();
                        analogS7ReadTask.SynchronizeCallbacks = false;
                        analog_in_names = new List<string>();
                        // bool isUsed; // adareau : now obsolete

                        #region Old Code
                       // // Obtains a list of the analog in channels to be included in the task, and their name
                       // AnalogInChannels the_channels = AtticusServer.server.serverSettings.AIChannels[0];
                       // AnalogInNames the_names = AtticusServer.server.serverSettings.AINames[0];

                       //// We use part of the channels as single ended, and part as differential. He channels are added here. The task is created on Slot 7. This shouldn't be hard coded and will be changed.
                       // #region Single ended
                       // for (int analog_index = 0; analog_index < 10; analog_index++)
                       // {
                       //     PropertyInfo the_channel = the_channels.GetType().GetProperty("AS" + analog_index.ToString());
                       //     isUsed = (bool)the_channel.GetValue(the_channels, null);
                       //     if (isUsed)
                       //     {
                       //         if (analog_index < 5)
                       //         {
                       //             analogS7ReadTask.AIChannels.CreateVoltageChannel("PXI1Slot7/ai" + analog_index.ToString(), "",
                       //                 AITerminalConfiguration.Nrse, -10, 10, AIVoltageUnits.Volts);
                       //         }
                       //         else
                       //         {
                       //             analogS7ReadTask.AIChannels.CreateVoltageChannel("PXI1Slot7/ai" + (analog_index + 3).ToString(), "",
                       //                 AITerminalConfiguration.Nrse, -10, 10, AIVoltageUnits.Volts);
                       //         }
                       //         string theName = (string)(the_names.GetType().GetProperty("AS" + analog_index.ToString()).GetValue(the_names, null));
                       //         if (theName == "")
                       //             analog_in_names.Add("AIS" + analog_index.ToString());
                       //         else
                       //             analog_in_names.Add(theName);
                       //     }
                       // }
                       // #endregion

                       // #region Differential
                       // for (int analog_index = 0; analog_index < 11; analog_index++)
                       // {
                       //     PropertyInfo the_channel = the_channels.GetType().GetProperty("AD" + NamingFunctions.number_to_string(analog_index, 2));
                       //     isUsed = (bool)the_channel.GetValue(the_channels, null);

                       //     if (isUsed)
                       //     {
                       //         if (analog_index < 3)
                       //         {
                       //             analogS7ReadTask.AIChannels.CreateVoltageChannel("PXI1Slot7/ai" + (analog_index + 5).ToString(), "",
                       //                 AITerminalConfiguration.Differential, -10, 10, AIVoltageUnits.Volts);
                       //         }
                       //         else
                       //         {
                       //             analogS7ReadTask.AIChannels.CreateVoltageChannel("PXI1Slot7/ai" + (analog_index + 13).ToString(), "",
                       //                 AITerminalConfiguration.Differential, -10, 10, AIVoltageUnits.Volts);
                       //         }
                       //         string theName = (string)(the_names.GetType().GetProperty("AD" + NamingFunctions.number_to_string(analog_index, 2)).GetValue(the_names, null));
                       //         if (theName == "")
                       //             analog_in_names.Add("AID" + analog_index.ToString());
                       //         else
                       //             analog_in_names.Add(theName);
                       //     }
                       // }
                       // #endregion

                        #endregion

                        #region New Code

                        List<AnalogInChannels> channels_list = AtticusServer.server.serverSettings.AIChannels;

                        foreach (AnalogInChannels aiChannel in channels_list)
                        {
                            if (aiChannel.UseChannel)
                            {
                                if (aiChannel.AnalogInChannelType == AnalogInChannels.AnalogInChannelTypeList.SingleEnded)
                                {
                                    analogS7ReadTask.AIChannels.CreateVoltageChannel(AtticusServer.server.serverSettings.AIDev + "/" + aiChannel.ChannelName, "",
                                      AITerminalConfiguration.Nrse, -10, 10, AIVoltageUnits.Volts);
                                }

                                else if (aiChannel.AnalogInChannelType == AnalogInChannels.AnalogInChannelTypeList.Differential)
                                {
                                    analogS7ReadTask.AIChannels.CreateVoltageChannel(AtticusServer.server.serverSettings.AIDev + "/" + aiChannel.ChannelName, "",
                                     AITerminalConfiguration.Differential, -10, 10, AIVoltageUnits.Volts);
                                }

                                string theName = aiChannel.SaveName;
                                analog_in_names.Add(theName);

                            }

                        }

                        #endregion

                        // Configure timing specs of the analog In task. Again these things shouldn't be hard coded and will be changed
                        analogS7ReadTask.Timing.ConfigureSampleClock("", (double)(AtticusServer.server.serverSettings.AIFrequency), SampleClockActiveEdge.Rising,
                            SampleQuantityMode.FiniteSamples, sequence.nSamples(1 / ((double)(AtticusServer.server.serverSettings.AIFrequency))));

                        //analogS7ReadTask.Timing.ReferenceClockSource = "/PXI1Slot7/PXI_Trig7"; // adareau : with my configuration, declaring a ReferenceClockSource was generating errors. I remove this for now...

                        if (AtticusServer.server.serverSettings.UseAITaskTriggering) //AD
                        {

                            DigitalEdgeStartTriggerEdge triggerEdge = DigitalEdgeStartTriggerEdge.Rising;  // AD : see below
                            analogS7ReadTask.Triggers.StartTrigger.ConfigureDigitalEdgeTrigger(AtticusServer.server.serverSettings.AITriggerSource, triggerEdge); // AD : to fix synchronization problem between analog in and output tasks, I trigger
                                                                                                                                                                 //  the analog in task, using the variable timebase source signal (available on PXI_Trig0)
                                                                                                                                                                 // the task starts with the first signal sent by the VT source...
                        }
                        analogS7ReadTask.Timing.ReferenceClockRate = 20000000;
                        analogS7ReadTask.Stream.Timeout = Convert.ToInt32(sequence.SequenceDuration * 1000) + 10000;

                        reader_analog_S7 = new AnalogMultiChannelReader(analogS7ReadTask.Stream);

                    }
                    #endregion

                    #region Watchdog Timer stuff -- NOT FINISHED YET, THUS COMMENTED OUT

                    if (serverSettings.UseWatchdogTimerMonitoringTask)
                    {
                        messageLog(this, new MessageEvent("Watchdog Timer tasks no longer supported. Ignoring serverSettings.UseWatchdogTimerMonitoringTask"));
                        /*
                        if (daqMxTasks.ContainsKey(serverSettings.DeviceToSyncSoftwareTimedTasksTo))
                        {
                            messageLog(this, new MessageEvent("Creating watchdog timer monitoring task"));
                            WatchdogTimerTask wtask = new WatchdogTimerTask(sequence, myServerSettings.myDevicesSettings[serverSettings.DeviceToSyncSoftwareTimedTasksTo].SampleClockRate, daqMxTasks[serverSettings.DeviceToSyncSoftwareTimedTasksTo], .2);
                        }
                        else
                        {
                            messageLog(this, new MessageEvent("Unable to create watchdog timer monitoring task, since the hardware-timed device it was to be synched to is not being used. Continuing without watchdog."));
                        }*/
                    }

                    #endregion

                    #region GPIB device and masquerading gpib channels (like rfsg channels)

                    foreach (int gpibID in usedGpibChannels.Keys)
                    {
                        HardwareChannel gpibChannel = usedGpibChannels[gpibID];
                        if (!gpibChannel.gpibMasquerade)
                        {
                            messageLog(this, new MessageEvent("Generating gpib buffer for gpib ID " + gpibID));

                            NationalInstruments.NI4882.Device gpibDevice = new NationalInstruments.NI4882.Device(
                                gpibChannel.gpibBoardNumber(),
                                new NationalInstruments.NI4882.Address(gpibChannel.GpibAddress.PrimaryAddress, gpibChannel.GpibAddress.SecondaryAddress));
                            GpibTask gpibTask = new GpibTask(gpibDevice);
                            gpibTask.generateBuffer(sequence, myServerSettings.myDevicesSettings[gpibChannel.DeviceName],
                                gpibChannel, gpibID, myServerSettings.GpibRampConverters);
                            gpibTask.Done += new TaskDoneEventHandler(aTaskFinished);
                            gpibTasks.Add(gpibChannel, gpibTask);
                            messageLog(this, new MessageEvent("Done."));

                        }
                        else
                        {
                            switch (gpibChannel.myGpibMasqueradeType)
                            {
                                case HardwareChannel.GpibMasqueradeType.NONE:
                                    messageLog(this, new MessageEvent("********** Error. GPIB channel with ID " + gpibID + " has its masquerading bit set to true, but has its masquerading type set to NONE. **********"));
                                    displayError();
                                    break;
                                case HardwareChannel.GpibMasqueradeType.RFSG:
                                    messageLog(this, new MessageEvent("Generating RFSG buffer for gpib ID " + gpibID));
                                    RfsgTask rftask = new RfsgTask(sequence, settings, gpibID, gpibChannel.DeviceName, serverSettings.myDevicesSettings[gpibChannel.DeviceName]);
                                    rftask.Done += new TaskDoneEventHandler(aTaskFinished);
                                    rfsgTasks.Add(gpibChannel, rftask);
                                    messageLog(this, new MessageEvent("Done."));
                                    break;
                            }
                        }
                    }

                    #endregion

                    #region RS 232 Devices
                    foreach (int rs232ID in usedRS232Channels.Keys)
                    {
                        if (sequence.rs232ChannelUsed(rs232ID))
                        {
                            messageLog(this, new MessageEvent("Generating rs232 buffer for rs232 ID " + rs232ID));
                            HardwareChannel hc = usedRS232Channels[rs232ID];
                            //NationalInstruments.VisaNS.SerialSession device = new NationalInstruments.VisaNS.SerialSession(hc.ChannelName);

                            NationalInstruments.VisaNS.SerialSession device;

                            try
                            {
                                device = getSerialSession(hc);
                            }
                            catch (Exception e)
                            {
                                messageLog(this, new MessageEvent("Caught exception when attempting to open serial device for rs232 channel #" + rs232ID + ". Exception: " + e.Message + e.StackTrace));
                                return BufferGenerationStatus.Failed_Out_Of_Memory;
                            }

                            //                NationalInstruments.VisaNS.RegisterBasedSession device = (NationalInstruments.VisaNS.RegisterBasedSession) NationalInstruments.VisaNS.ResourceManager.GetLocalManager().Open(hc.ChannelName);

                            RS232Task rs232task = new RS232Task(device);
                            rs232task.generateBuffer(sequence, myServerSettings.myDevicesSettings["Serial"], hc, rs232ID);
                            rs232task.Done += new TaskDoneEventHandler(aTaskFinished);
                            rs232Tasks.Add(hc, rs232task);
                            messageLog(this, new MessageEvent("Done."));
                        }
                        else
                        {
                            messageLog(this, new MessageEvent("Skipping rs232 channel ID " + rs232ID + ", that channel is not used in this sequence."));
                        }
                    }

                    #endregion

                    makeTerminalConnections();

                    // Try to clean up as much memory as possible so that there wont be any garbage collection
                    // during the run. Suspect that GCs during the run may be the cause of sporadic buffer underruns.
                    // Note: This is likely wrong. Most of these buffer underruns were eventually fixed with the
                    // data transfer mechanism tweaks described in the user manual. However, no harm in doing some
                    // GC here.
                    System.GC.Collect();
                    System.GC.Collect();
                    System.GC.Collect();
                    System.GC.WaitForPendingFinalizers();

                    messageLog(this, new MessageEvent("Buffers generated succesfully."));

                    return BufferGenerationStatus.Success;

                }
                catch (Exception e)
                {
                    messageLog(this, new MessageEvent("Failed buffer generation due to exception: " + e.Message + "\n" + e.StackTrace));
                    displayError();
                    return BufferGenerationStatus.Failed_Invalid_Data;
                }
            }
        }