示例#1
0
        private void parseBoolean(string[] formatTokens,
                                  ref PlaceholderInfo outInfo)
        {
            var m0 = new Mapping {
                minValue = 0, maxValue = 0
            };
            var m1 = new Mapping {
                minValue = 1, maxValue = 1
            };

            switch (formatTokens.Length)
            {
            case 1:
                switch (formatTokens[0].Length)
                {
                case 1:
                    // nothing to do
                    break;

                case 3:
                    m0.representation = formatTokens[0][1].ToString();
                    m1.representation = formatTokens[0][2].ToString();
                    break;

                default:
                    outInfo.result.HasError = true;
                    outInfo.result.Message  = "PlaceholderBinLengthInvalid";
                    return;
                }
                break;

            case 3:
                m0.representation = formatTokens[1];
                m1.representation = formatTokens[2];
                break;

            default:
                outInfo.result.HasError = true;
                outInfo.result.Message  = "PlaceholderBinLengthInvalid";
                return;
            }
            if ((null != m0.representation) && (null != m1.representation))
            {
                outInfo.mappings = new List <Mapping>();
                outInfo.mappings.Add(m0);
                outInfo.mappings.Add(m1);

                if (!isBinTextValid(m0.representation) || !isBinTextValid(m1.representation))
                {
                    outInfo.result.HasError = true;
                    outInfo.result.Message  = "PlaceholderBinInvalidAssign";
                }

                if (m0.representation == m1.representation)
                {
                    outInfo.result.HasError = true;
                    outInfo.result.Message  = "PlaceholderBinSameText";
                }
            }
        }
示例#2
0
        private void parseStringMappings(string[] formatTokens,
                                         ref PlaceholderInfo outInfo)
        {
            // Ignore entry at index 0 (type processed by caller)
            outInfo.textMappings = null;
            if (formatTokens.Length > 1)
            {
                outInfo.textMappings = new List <TextMapping>(formatTokens.Length - 1);
                for (int i = 1; i < formatTokens.Length; i++)
                {
                    string[] valueRepresentation = formatTokens[i].Split('=');
                    switch (valueRepresentation.Length)
                    {
                    case 1:
                        outInfo.result.HasError = true;
                        outInfo.result.Message  = "MappingNoImplicitTextValues";
                        return;

                    case 2:
                        parseExplicitTextMapping(valueRepresentation, ref outInfo);
                        if (outInfo.result.HasError)
                        {
                            return;
                        }
                        break;

                    default:
                        outInfo.result.HasError = true;
                        outInfo.result.Message  = "MappingWrongTextAssignment";
                        return;
                    }
                }
            }
        }
        private static string ReplaceGlobalPlaceholders(string value)
        {
            foreach (Match match in GlobalPlaceholderRegex.Matches(value))
            {
                PlaceholderInfo placeholder = new PlaceholderInfo(match);
                value = ReplacePlaceholder(value, placeholder, Globals[placeholder.Name]);
            }

            return(value);
        }
示例#4
0
 public static PRJ_PLACEHOLDER_INFO Create(PlaceholderInfo placeholderInfo)
 {
     return(new PRJ_PLACEHOLDER_INFO()
     {
         FileBasicInfo = PRJ_FILE_BASIC_INFO.Create(placeholderInfo.BasicInfo),
         VersionInfo = placeholderInfo.VersionInfo == null ?
                       PRJ_PLACEHOLDER_VERSION_INFO.Empty :
                       PRJ_PLACEHOLDER_VERSION_INFO.Create(placeholderInfo.VersionInfo)
     });
 }
示例#5
0
 private void parseString(string[] formatTokens,
                          ref PlaceholderInfo outInfo)
 {
     if ((formatTokens.Length > 0) &&
         ((formatTokens[0].Length < 0) || (formatTokens[0].Length > 1)))
     {
         outInfo.result.HasError = true;
         outInfo.result.Message  = "PlaceholderStrLengthInvalid";
         return;
     }
     // no additional info to store
 }
示例#6
0
 private void parseStringPlaceholder(string[] formatTokens,
                                     ref PlaceholderInfo outInfo)
 {
     if ((formatTokens.Length > 0) &&
         ((formatTokens[0].Length < 0) || (formatTokens[0].Length > 1)))
     {
         outInfo.result.HasError = true;
         outInfo.result.Message  = "PlaceholderStrLengthInvalid";
         return;
     }
     parseStringMappings(formatTokens, ref outInfo);
 }
示例#7
0
 private void parseIntegerPlaceholder(string[] formatTokens,
                                      ref PlaceholderInfo outInfo)
 {
     System.Diagnostics.Trace.Assert(formatTokens.Length > 0);
     if (formatTokens[0].Length != 1)
     {
         outInfo.result.HasError = true;
         outInfo.result.Message  = "PlaceholderIntLengthInvalid";
         return;
     }
     outInfo.format = "G"; // shortest possible number format for integers
     parseNumericMappings(/* allowImplicitValues = */ true, formatTokens, ref outInfo);
 }
示例#8
0
        public TokenBase createPlaceholderToken(string placeholderText,
                                                string groupSeparator, string decimalSeparator)
        {
            PlaceholderInfo info = parsePlaceholder(placeholderText);

            if (info.result.HasError)
            {
                return(new ErrorToken(placeholderText, info.result.Message));
            }
            else
            {
                VarTokenBase ret;

                switch (info.type)
                {
                case TokenType.VarBoolean:
                    ret = new VarBooleanToken(placeholderText, info.name, info.isDefaultName, info.numericMappings);
                    break;

                case TokenType.VarInteger:
                    ret = new VarNumericToken <int>(placeholderText, info.type, info.name, info.isDefaultName,
                                                    info.format, groupSeparator, decimalSeparator, info.numericMappings);
                    break;

                case TokenType.VarNumber:
                    ret = new VarNumericToken <double>(placeholderText, info.type, info.name, info.isDefaultName,
                                                       info.format, groupSeparator, decimalSeparator, info.numericMappings);
                    break;

                case TokenType.VarString:
                    ret = new VarStringToken(placeholderText, info.name, info.isDefaultName, info.textMappings);
                    break;

                case TokenType.VarReference:
                    if (info.hasType)
                    {
                        return(new VarReferenceToken(placeholderText, info.reference, info.format, info.numericMappings));
                    }
                    else
                    {
                        return(new VarReferenceToken(placeholderText, info.reference));
                    }

                default:
                    return(new ErrorToken(placeholderText, "UnsupportedPlaceholderType"));
                }
                mPlaceholders.Add(info.name, ret);
                return(ret);
            }
        }
示例#9
0
 private void parseNumberPlaceholder(string[] formatTokens,
                                     ref PlaceholderInfo outInfo)
 {
     System.Diagnostics.Trace.Assert(formatTokens.Length > 0);
     if ((formatTokens[0].Length == 1) ||
         ((formatTokens[0].Length == 2) && (char.IsDigit(formatTokens[0][1]))))
     { // No or one digit parameter, use as number format as-is
         outInfo.format = formatTokens[0];
     }
     else
     {
         outInfo.result.HasError = true;
         outInfo.result.Message  = "PlaceholderNumFormatInvalid";
         return;
     }
     parseNumericMappings(/* allowImplicitValues = */ false, formatTokens, ref outInfo);
 }
示例#10
0
        private void parseFormatAndMappings(string formatText,
                                            ref PlaceholderInfo outInfo)
        {
            string[] formatTokens = formatText.Split('|');
            formatTokens[0] = formatTokens[0].ToUpper().Trim();
            TokenType type = getType(formatTokens[0]);

            switch (type)
            {
            case TokenType.VarBoolean:
                parseBoolean(formatTokens, ref outInfo);
                break;

            case TokenType.VarInteger:
                parseInteger(formatTokens, ref outInfo);
                break;

            case TokenType.VarNumber:
                parseNumber(formatTokens, ref outInfo);
                break;

            case TokenType.VarString:
                parseString(formatTokens, ref outInfo);
                break;

            default:
                outInfo.result.HasError = true;
                outInfo.result.Message  = "PlaceholderTypeInvalid";
                break;
            }

            if (outInfo.type == TokenType.VarReference)
            {
                if (outInfo.reference.getType() != type)
                {
                    outInfo.result.HasError = true;
                    outInfo.result.Message  = "PlaceholderReuseWrongType";
                }
            }
            else
            {
                outInfo.type = type;
            }
        }
        private static string ReplaceParentPlaceholders(string value, ConfigurationElement element, string name)
        {
            foreach (Match match in ParentPlaceholderRegex.Matches(value))
            {
                PlaceholderInfo      placeholder = new PlaceholderInfo(match);
                string               placeholderName = placeholder.Name, currentValue = null;
                ConfigurationElement currentElement = placeholderName == name?element.GetParent() : element;

                do
                {
                    currentValue   = currentElement.GetResolvedValue(placeholderName);
                    currentElement = currentElement.GetParent();
                }while (string.IsNullOrEmpty(currentValue) && currentElement != null);

                value = ReplacePlaceholder(value, placeholder, currentValue);
            }

            return(value);
        }
示例#12
0
        private void parseExplicitTextMapping(string[] valueRepresentation,
                                              ref PlaceholderInfo outInfo)
        {
            System.Diagnostics.Trace.Assert(valueRepresentation.Length == 2);

            if (valueRepresentation[0].Length > 0)
            {
                TextMapping mapping = new TextMapping
                {
                    original       = valueRepresentation[0],
                    representation = valueRepresentation[1]
                };
                outInfo.textMappings.Add(mapping);
            }
            else
            {
                outInfo.result.HasError = true;
                outInfo.result.Message  = "MappingNoOriginalTextValue";
            }
        }
        private static string ReplacePlaceholder(string value, PlaceholderInfo placeholder, string placeholderValue)
        {
            switch (placeholder.FormatType)
            {
            case FormatType.Number:
                if (double.TryParse(placeholderValue, out double numberValue))
                {
                    placeholderValue = numberValue.ToString(placeholder.Format);
                }
                break;

            case FormatType.Date:
                if (DateTime.TryParse(placeholderValue, out DateTime dateValue))
                {
                    placeholderValue = dateValue.ToString(placeholder.Format);
                }
                break;
            }

            return(value.Replace(placeholder.Content, placeholderValue));
        }
示例#14
0
 private void parseExplicitMapping(string[] valueRepresentation,
                                   ref PlaceholderInfo outInfo)
 {
     if (valueRepresentation.Length == 2)
     {
         string[] rangeStrings = valueRepresentation[0].Split('.');
         if (rangeStrings.Length == 1)
         {
             DoubleVal value = parseValue(rangeStrings[0]);
             if (value.isValid)
             {
                 Mapping mapping = new Mapping  {
                     minValue       = value.value,
                     maxValue       = value.value,
                     representation = valueRepresentation[1]
                 };
                 outInfo.mappings.Add(mapping);
             }
             else
             {
                 outInfo.result.HasError = true;
                 outInfo.result.Message  = "ExplicitMappingInvalidValue";
                 return;
             }
         }
         else if ((rangeStrings.Length == 3) && (rangeStrings[1].Length == 0))
         {
             DoubleVal minValue = parseRangeValue(rangeStrings[0], /* isMin = */ true);
             DoubleVal maxValue = parseRangeValue(rangeStrings[2], /* isMin = */ false);
             if (minValue.isValid && maxValue.isValid)
             {
                 if (minValue.value < maxValue.value)
                 {
                     Mapping mapping = new Mapping {
                         minValue           = minValue.value,
                         isMinValueExcluded = minValue.isExcluded,
                         maxValue           = maxValue.value,
                         isMaxValueExcluded = maxValue.isExcluded,
                         representation     = valueRepresentation[1]
                     };
                     outInfo.mappings.Add(mapping);
                 }
                 else
                 {
                     outInfo.result.HasError = true;
                     outInfo.result.Message  = "ExplicitMappingInvertedRange";
                     return;
                 }
             }
             else
             {
                 outInfo.result.HasError = true;
                 outInfo.result.Message  = "ExplicitMappingInvRngVal";
                 return;
             }
         }
         else
         {
             outInfo.result.HasError = true;
             outInfo.result.Message  = "ExplicitMappingInvalidRange";
             return;
         }
     }
     else
     { // Paranoia; should be checked by caller
         outInfo.result.HasError = true;
         outInfo.result.Message  = "MappingWrongAssignment";
         return;
     }
 }
示例#15
0
        private void parseMappings(bool allowImplicitValues,
                                   string[] formatTokens,
                                   ref PlaceholderInfo outInfo)
        {
            bool allowExplicitValues = true; // until an implicit value has been found
            int  implicitValue       = 0;

            // Ignore entry at index 0 (type/precision processed by caller)
            outInfo.mappings = new List <Mapping>(formatTokens.Length - 1);
            for (int i = 1; i < formatTokens.Length; i++)
            {
                string[] valueRepresentation = formatTokens[i].Split('=');
                switch (valueRepresentation.Length)
                {
                case 1:
                    if (allowImplicitValues)
                    {
                        Mapping mapping = new Mapping {
                            minValue       = implicitValue,
                            maxValue       = implicitValue,
                            representation = valueRepresentation[0]
                        };
                        if (0 == mapping.representation.Length)
                        {
                            outInfo.result.HasError = true;
                            outInfo.result.Message  = "MappingEmptyImplicitValue";
                            return;
                        }

                        outInfo.mappings.Add(mapping);
                        allowExplicitValues = false;
                        implicitValue++;
                    }
                    else
                    {
                        outInfo.result.HasError = true;
                        outInfo.result.Message  = "MappingNoImplicitValues";
                        return;
                    }
                    break;

                case 2:
                    if (allowExplicitValues)
                    {
                        parseExplicitMapping(valueRepresentation, ref outInfo);
                        if (outInfo.result.HasError)
                        {
                            return;
                        }
                        allowImplicitValues = false;
                    }
                    else
                    {
                        outInfo.result.HasError = true;
                        outInfo.result.Message  = "MappingNoExplicitValues";
                        return;
                    }
                    break;

                default:
                    outInfo.result.HasError = true;
                    outInfo.result.Message  = "MappingWrongAssignment";
                    return;
                }
            }
        }
        public Certificate GenerateCertificate(string username, int courseId, AssessmentSubmission assessmentSubmission)
        {
            User   user   = _users.GetByUsername(username);
            Course course = _courses.GetById(courseId);

            Certificate certificate = new Certificate
            {
                UserId = user.Id,
                AssesmentSubmissionId = assessmentSubmission.Id,
                CourseId = course.Id,
                Code     = _random.GenerateRandomCode(10)
            };

            CertificateGenerationInfo certificateGenerationInfo = _generationInfoProvider.GetByCourseId(courseId);

            string certificateRelativePath = string.Format(CertificateFilePathFormat, certificate.Code);
            string filePath = Path.Combine(certificateGenerationInfo.BaseFilePath, certificateRelativePath);

            certificate.FilePath = certificateRelativePath;
            _certificates.Add(certificate);
            _certificates.SaveChanges();


            Bitmap        bitmap  = (Bitmap)Image.FromFile(Path.GetFullPath(certificateGenerationInfo.TemplateFilePath));//load the image file
            QRCodeEncoder encoder = new QRCodeEncoder();
            Bitmap        certificateUrlQrCode = encoder.Encode(string.Format(CertificateUrlFormat, certificate.Code));

            using (Graphics certificateTemplate = Graphics.FromImage(bitmap))
            {
                using (Font arialFont = new Font("Arial", 16, FontStyle.Bold))
                {
                    using (Font arialFontLarge = new Font("Arial", 20, FontStyle.Bold))
                    {
                        PlaceholderInfo studentData     = certificateGenerationInfo.StudentName;
                        PlaceholderInfo courseData      = certificateGenerationInfo.CourseName;
                        PlaceholderInfo datePlaceholder = certificateGenerationInfo.IssueDate;
                        PlaceholderInfo qrPlaceholder   = certificateGenerationInfo.QrCode;
                        PlaceholderInfo certificateNumberPlaceholder = certificateGenerationInfo.CertificateNumber;
                        PlaceholderInfo moduleNamesPlaceholder       = certificateGenerationInfo.ModuleNames;
                        PlaceholderInfo numberOfHoursPlaceholder     = certificateGenerationInfo.NumberOfHours;
                        certificateTemplate.DrawString($"{user.FirstName} {user.MiddleName} {user.LastName}", arialFontLarge, new SolidBrush(ColorTranslator.FromHtml(studentData.Color)), new Rectangle(studentData.TopLeftX, studentData.TopLeftY, studentData.Width, studentData.Height));
                        certificateTemplate.DrawString(course.Title, arialFontLarge, new SolidBrush(ColorTranslator.FromHtml(courseData.Color)), new Rectangle(courseData.TopLeftX, courseData.TopLeftY, courseData.Width, courseData.Height));
                        certificateTemplate.DrawString(DateTime.Today.ToString("dd.MM.yyy") + "г.", arialFont, new SolidBrush(ColorTranslator.FromHtml(datePlaceholder.Color)), new Rectangle(datePlaceholder.TopLeftX, datePlaceholder.TopLeftY, datePlaceholder.Width, datePlaceholder.Height));
                        certificateTemplate.DrawImage(certificateUrlQrCode, new Rectangle(qrPlaceholder.TopLeftX, qrPlaceholder.TopLeftY, qrPlaceholder.Width, qrPlaceholder.Height));
                        certificateTemplate.DrawString($"Рег. № {certificate.Id}", arialFontLarge, new SolidBrush(ColorTranslator.FromHtml(certificateNumberPlaceholder.Color)), new Rectangle(certificateNumberPlaceholder.TopLeftX, certificateNumberPlaceholder.TopLeftY, certificateNumberPlaceholder.Width, certificateNumberPlaceholder.Height));
                        certificateTemplate.DrawString(course.ModuleNames, arialFont, new SolidBrush(ColorTranslator.FromHtml(moduleNamesPlaceholder.Color)), new Rectangle(moduleNamesPlaceholder.TopLeftX, moduleNamesPlaceholder.TopLeftY, moduleNamesPlaceholder.Width, moduleNamesPlaceholder.Height));
                        certificateTemplate.DrawString($"{course.NumberOfHours} учебни часа", arialFont, new SolidBrush(ColorTranslator.FromHtml(numberOfHoursPlaceholder.Color)), new Rectangle(numberOfHoursPlaceholder.TopLeftX, numberOfHoursPlaceholder.TopLeftY, numberOfHoursPlaceholder.Width, numberOfHoursPlaceholder.Height));


                        string directoryPath = Path.GetDirectoryName(filePath);
                        Debug.Assert(!string.IsNullOrEmpty(directoryPath));
                        if (!Directory.Exists(directoryPath))
                        {
                            Directory.CreateDirectory(directoryPath);
                        }

                        bitmap.Save(filePath);
                    }
                }
            }
            return(certificate);
        }
示例#17
0
 public HeaderStrategy(int executionOrder, PlaceholderInfoType type)
     : base(DefaultExecutionOrder, type)
 {
     this.Placeholder = new PlaceholderInfo(type);
 }
示例#18
0
 /// <summary>
 /// Writes a string to the output and sets the Handled flag.
 /// </summary>
 internal void WriteError(string message, PlaceholderInfo placeholder)
 {
     // By default, this doesn't do anything special.
     // However, it can be overridden, in order to monitor the output and customize it.
     this.WriteEscaped(message);
 }
示例#19
0
        private PlaceholderInfo parsePlaceholder(string placeholderText)
        {
            PlaceholderInfo retInfo = new PlaceholderInfo {
                type = TokenType.Error
            };

            retInfo.name = ""; // start empty

            if (0 < placeholderText.Length)
            {
                // Extract & process the name if one is given
                string[] s1 = placeholderText.Split(':');
                retInfo.name = s1[0].Trim();
                if (0 < retInfo.name.Length)
                {
                    if (!VALID_NAME_PATTERN.IsMatch(retInfo.name))
                    {
                        retInfo.result.HasError = true;
                        retInfo.result.Message  = "PlaceholderNameInvalid";
                        return(retInfo);
                    }
                    TokenBase preToken;
                    bool      preFound = mPlaceholders.TryGetValue(retInfo.name, out preToken);
                    if (preFound && (preToken is VarTokenBase preVarToken))
                    { // The name already exists
                        retInfo.type      = TokenType.VarReference;
                        retInfo.reference = preVarToken;
                    }
                }

                // Extract & process the format and mappings if given after ':'
                switch (s1.Length)
                {
                case 1: // Name only; no format given
                    if (retInfo.type != TokenType.VarReference)
                    {   // name alone is refernce and should have been found above
                        retInfo.result.HasError = true;
                        retInfo.result.Message  = "PlaceholderNameNotFound";
                    }
                    return(retInfo);

                case 2:                      // Name (potentially empty) and format given
                    placeholderText = s1[1]; // Format to parse follows after ':'
                    if (0 < placeholderText.Length)
                    {                        // Parse the format text to determine type, number format, and mappings
                        parseFormatAndMappings(placeholderText, ref retInfo);
                        if (retInfo.result.HasError)
                        {
                            return(retInfo);
                        }
                        retInfo.hasType = true;
                    }
                    break;

                default: // More than one colon is an error
                    retInfo.result.HasError = true;
                    retInfo.result.Message  = "PlaceholderMultipleColon";
                    return(retInfo);
                }

                if (0 == retInfo.name.Length)
                { // No name given, make one up
                    retInfo.name          = getNextDefaultName(retInfo.type);
                    retInfo.isDefaultName = true;
                }
            }
            else
            {
                retInfo.result.HasError = true;
                retInfo.result.Message  = "EmptyPlaceholder";
            }

            return(retInfo);
        }
示例#20
0
        private void parseExplicitNumericMapping(string[] valueRepresentation,
                                                 ref PlaceholderInfo outInfo)
        {
            System.Diagnostics.Trace.Assert(valueRepresentation.Length == 2);

            string[] rangeStrings = valueRepresentation[0].Split('.');
            if (rangeStrings.Length == 1)
            {
                DoubleVal value = parseValue(rangeStrings[0]);
                if (value.isValid)
                {
                    NumericMapping mapping = new NumericMapping  {
                        minValue       = value.value,
                        maxValue       = value.value,
                        representation = valueRepresentation[1]
                    };
                    outInfo.numericMappings.Add(mapping);
                }
                else
                {
                    outInfo.result.HasError = true;
                    outInfo.result.Message  = "ExplicitMappingInvalidValue";
                    return;
                }
            }
            else if ((rangeStrings.Length == 3) && (rangeStrings[1].Length == 0))
            {
                DoubleVal minValue = parseRangeValue(rangeStrings[0], /* isMin = */ true);
                DoubleVal maxValue = parseRangeValue(rangeStrings[2], /* isMin = */ false);
                if (minValue.isValid && maxValue.isValid)
                {
                    if (minValue.value < maxValue.value)
                    {
                        NumericMapping mapping = new NumericMapping {
                            minValue           = minValue.value,
                            isMinValueExcluded = minValue.isExcluded,
                            maxValue           = maxValue.value,
                            isMaxValueExcluded = maxValue.isExcluded,
                            representation     = valueRepresentation[1]
                        };
                        outInfo.numericMappings.Add(mapping);
                    }
                    else
                    {
                        outInfo.result.HasError = true;
                        outInfo.result.Message  = "ExplicitMappingInvertedRange";
                        return;
                    }
                }
                else
                {
                    outInfo.result.HasError = true;
                    outInfo.result.Message  = "ExplicitMappingInvRngVal";
                    return;
                }
            }
            else
            {
                outInfo.result.HasError = true;
                outInfo.result.Message  = "ExplicitMappingInvalidRange";
                return;
            }
        }
        internal static NativeBuffer <PRJ_PLACEHOLDER_INFO> PRJ_PLACEHOLDER_INFOFromPlaceholderInfo(PlaceholderInfo original)
        {
            var ph = new PRJ_PLACEHOLDER_INFO
            {
                FileBasicInfo = PRJ_FILE_BASIC_INFOFromBasicInfo(original.BasicInfo),
                VersionInfo   = PRJ_PLACEHOLDER_VERSION_INFOFromPlaceholderVersion(original.Version)
            };

            if (original.Security == null)
            {
                return(new NativeBuffer <PRJ_PLACEHOLDER_INFO>(ph));
            }
            var securityBuffer = original.Security.GetSecurityDescriptorBinaryForm();

            ph.SecurityInformation.OffsetToSecurityDescriptor = Marshal.SizeOf <PRJ_PLACEHOLDER_INFO>();
            ph.SecurityInformation.SecurityBufferSize         = securityBuffer.Length;
            return(new NativeBuffer <PRJ_PLACEHOLDER_INFO>(ph, securityBuffer));
        }
示例#22
0
 /// <summary>
 /// Writes a string to the output and sets the Handled flag.
 /// </summary>
 internal void WriteError(string message, PlaceholderInfo placeholder)
 {
     // By default, this doesn't do anything special.
     // However, it can be overridden, in order to monitor the output and customize it.
     this.WriteEscaped(message);
 }