public override IOperation Extract(Process process, Entity entity, bool firstRun) { var p = new PartialProcessOperation(process); if (entity.InputOperation == null) { if (process.DataSets.ContainsKey(entity.Name)) { // TODO: Make EntityFieldTypeConverterOperation var converter = Common.GetObjectConversionMap(); var rows = process.DataSets[entity.Name]; foreach (var field in entity.Fields.WithInput()) { if (field.SimpleType == "string") { continue; } foreach (var row in rows) { row[field.Name] = converter[field.SimpleType](row[field.Name]); } } entity.InputOperation = new RowsOperation(process.DataSets[entity.Name]); } else { entity.InputOperation = new EmptyOperation(); } } p.Register(entity.InputOperation); p.Register(new AliasOperation(entity)); return(p); }
public override IOperation Extract(Process process, Entity entity, bool firstRun) { if (Schemas && entity.Schema.Equals(string.Empty)) { entity.Schema = DefaultSchema; } var p = new PartialProcessOperation(process); if (entity.HasSqlOverride()) { p.Register(new SqlOverrideOperation(entity, this)); } else { if (entity.PrimaryKey.WithInput().Any()) { p.Register(new EntityKeysSaveOperation(entity)); p.Register(new EntityKeysToOperations(ref entity, this, firstRun)); p.Register(new SerialUnionAllOperation(entity)); } else { entity.SqlOverride = SqlTemplates.Select(entity, this); p.Register(new SqlOverrideOperation(entity, this)); } } return(p); }
public override IOperation Insert(Process process, Entity entity) { var pp = new PartialProcessOperation(process); pp.Register(new HtmlRowOperation(entity, "HtmlRow")); pp.Register(new HtmlLoadOperation(this, entity, "HtmlRow")); return(pp); }
public override IOperation Extract(Process process, Entity entity, bool firstRun) { var outKey = entity.Fields.First().Alias; var url = new Parameter("url", _element.Url == string.Empty ? _element.NormalizeUrl(80) : _element.Url); var data = new Parameter("data", _element.Data == Common.DefaultValue ? string.Empty : _element.Data); var partial = new PartialProcessOperation(process); var rows = new Row[1]; rows[0] = new Row(); partial.Register(new RowsOperation(rows)); partial.Register(new WebOperation(url, outKey, 0, _element.WebMethod, data, _element.ContentType)); return partial; }
public override IOperation Extract(Process process, Entity entity, bool firstRun) { var outKey = entity.Fields.First().Alias; var url = new Parameter("url", _element.Url == string.Empty ? _element.NormalizeUrl(80) : _element.Url); var data = new Parameter("data", _element.Data == Common.DefaultValue ? string.Empty : _element.Data); var partial = new PartialProcessOperation(process); var rows = new Row[1]; rows[0] = new Row(); partial.Register(new RowsOperation(rows)); partial.Register(new WebOperation(url, outKey, 0, _element.WebMethod, data, _element.ContentType)); return(partial); }
public void TestExtractAndFilterDatabases() { var d1 = new PartialProcessOperation(); d1.Register(new DatabaseExtract("Server=localhost;Database=master;Trusted_Connection=True;")); d1.Register(new DatabaseFilter()); d1.Register(new LogOperation()); var d2 = new PartialProcessOperation(); d2.Register(new DatabaseExtract("Server=localhost;Database=master;Trusted_Connection=True;")); d2.Register(new DatabaseFilter()); d2.Register(new LogOperation()); var union = new SerialUnionAllOperation(d1,d2); var results = TestOperation( union ); Assert.Less(0, results.Count); }
public void TestExtractAndFilterDatabases() { var d1 = new PartialProcessOperation(); d1.Register(new DatabaseExtract("Server=localhost;Database=master;Trusted_Connection=True;")); d1.Register(new DatabaseFilter()); d1.Register(new LogOperation()); var d2 = new PartialProcessOperation(); d2.Register(new DatabaseExtract("Server=localhost;Database=master;Trusted_Connection=True;")); d2.Register(new DatabaseFilter()); d2.Register(new LogOperation()); var union = new SerialUnionAllOperation(d1, d2); var results = TestOperation( union ); Assert.Less(0, results.Count); }
public override IOperation Extract(Process process, Entity entity, bool firstRun) { var p = new PartialProcessOperation(process); if (entity.InputOperation == null) { if (process.DataSets.ContainsKey(entity.Name)) { // TODO: Make EntityFieldTypeConverterOperation var converter = Common.GetObjectConversionMap(); var rows = process.DataSets[entity.Name]; foreach (var field in entity.Fields.WithInput()) { if (field.SimpleType == "string") continue; foreach (var row in rows) { row[field.Name] = converter[field.SimpleType](row[field.Name]); } } entity.InputOperation = new RowsOperation(process.DataSets[entity.Name]); } else { entity.InputOperation = new EmptyOperation(); } } p.Register(entity.InputOperation); p.Register(new AliasOperation(entity)); return p; }
private PartialProcessOperation PrepareOutputOperation(Process process, NamedConnection output) { var partial = new PartialProcessOperation(process); partial.Register(new FilterOutputOperation(output.ShouldRun) { EntityName = _entity.Name }); if (output.Connection.Type == ProviderType.Internal) { partial.Register(_collectors[output.Name]); } else { if (Process.IsFirstRun || !_entity.DetectChanges) { partial.Register(new EntityAddTflFields(process, _entity)); partial.Register(output.Connection.Insert(process, _entity)); } else { partial.Register(new EntityJoinAction(process, _entity).Right(output.Connection.ExtractCorrespondingKeysFromOutput(_entity))); var branch = new BranchingOperation() .Add(new PartialProcessOperation(process) .Register(new EntityActionFilter(process, _entity, EntityAction.Insert)) .Register(output.Connection.Insert(process, _entity))) .Add(new PartialProcessOperation(process) .Register(new EntityActionFilter(process, _entity, EntityAction.Update)) .Register(output.Connection.Update(_entity))); partial.Register(branch); } } return(partial); }
public IOperation Create(Field field, TflTransform element, IParameters parameters) { if (_isInitMode) { return(new EmptyOperation()); } Func <Row, bool> shouldRun = row => true; var toTimeZone = string.IsNullOrEmpty(element.ToTimeZone) ? _process.TimeZone : element.ToTimeZone; var hasParameters = parameters.Count > 0; var inKey = hasParameters ? parameters[0].Name : field.Alias; var inType = hasParameters ? parameters[0].SimpleType : field.SimpleType; var outKey = field.Alias; var outType = field.SimpleType; var scripts = new Dictionary <string, Script>(); if (!hasParameters) { parameters.Add(field.Alias, field.Alias, null, field.SimpleType); } if (!element.RunField.Equals(string.Empty)) { var op = (ComparisonOperator)Enum.Parse(typeof(ComparisonOperator), element.RunOperator, true); var simpleType = Common.ToSimpleType(element.RunType.Equals(Common.DefaultValue) ? "boolean" : element.RunType); var runValue = simpleType.StartsWith("bool") && element.RunValue.Equals(Common.DefaultValue) ? "true" : element.RunValue; var value = Common.ConversionMap[simpleType](runValue); shouldRun = row => Common.CompareMap[op](row[element.RunField], value); } var templates = ComposeTemplates(field, element); switch (element.Method.ToLower()) { case "convert": return(new ConvertOperation( inKey, inType, outKey, element.To.Equals(Common.DefaultValue) ? outType : element.To, element.Encoding, element.Format ) { ShouldRun = shouldRun, EntityName = _entityName }); case "copy": if (parameters.Count > 1) { return new CopyMultipleOperation(outKey, parameters) { ShouldRun = shouldRun, EntityName = _entityName } } ; return(new CopyOperation(inKey, outKey) { ShouldRun = shouldRun, EntityName = _entityName }); case "collapse": var partial = new PartialProcessOperation(_process); partial.Register(new RegexReplaceOperation(inKey, outKey, "[\r\n]{2,}", "\r\n", 0) { ShouldRun = shouldRun, EntityName = _entityName }); partial.Register(new RegexReplaceOperation(inKey, outKey, " {2,}", " ", 0) { ShouldRun = shouldRun, EntityName = _entityName }); partial.Register(new TrimOperation(inKey, outKey, " ") { ShouldRun = shouldRun, EntityName = _entityName }); return(partial); case "compress": return(new CompressOperation(inKey, outKey) { ShouldRun = shouldRun, EntityName = _entityName }); case "toyesno": return(new ToYesNoOperation(inKey, outKey) { ShouldRun = shouldRun, EntityName = _entityName }); case "decompress": return(new DecompressOperation(inKey, outKey) { ShouldRun = shouldRun, EntityName = _entityName }); case "elipse": return(new ElipseOperation(inKey, outKey, element.Length, element.Elipse) { ShouldRun = shouldRun, EntityName = _entityName }); case "replace": return(new ReplaceOperation( inKey, outKey, element.OldValue, element.NewValue ) { ShouldRun = shouldRun, EntityName = _entityName }); case "regexreplace": return(new RegexReplaceOperation( inKey, outKey, element.Pattern, element.Replacement, element.Count ) { ShouldRun = shouldRun, EntityName = _entityName }); case "striphtml": return(new RegexReplaceOperation( inKey, outKey, @"<[^>]+>| ", string.Empty, 0 ) { ShouldRun = shouldRun, EntityName = _entityName }); case "insert": return(new InsertOperation( inKey, outKey, element.StartIndex, element.Value, parameters[0].Name.Equals(outKey) ? null : GetParameter(_entityName, parameters[0].Name) ) { ShouldRun = shouldRun, EntityName = _entityName }); case "insertinterval": return(new InsertIntervalOperation( inKey, outKey, element.Interval, element.Value ) { ShouldRun = shouldRun, EntityName = _entityName }); case "append": return(new AppendOperation( inKey, outKey, element.Value, parameters[0].Name.Equals(outKey) ? null : GetParameter(_entityName, parameters[0].Name) ) { ShouldRun = shouldRun, EntityName = _entityName }); case "if": var leftParameter = GetParameter(_entityName, element.Left, parameters); return(new IfOperation( leftParameter, (ComparisonOperator)Enum.Parse(typeof(ComparisonOperator), element.Operator, true), GetParameter(_entityName, element.Right, parameters, leftParameter.SimpleType), GetParameter(_entityName, element.Then, parameters), GetParameter(_entityName, element.Else, parameters), outKey, outType ) { ShouldRun = shouldRun, EntityName = _entityName }); case "distinctwords": if (element.Separator.Equals(Common.DefaultValue)) { element.Separator = SPACE; } return(new DistinctWordsOperation( inKey, outKey, element.Separator ) { ShouldRun = shouldRun, EntityName = _entityName }); case "guid": return(new GuidOperation(inKey, outKey) { ShouldRun = shouldRun, EntityName = _entityName }); case "utcnow": return(new UtcNowOperation( inKey, outKey ) { ShouldRun = shouldRun, EntityName = _entityName }); case "now": return(new NowOperation( inKey, outKey ) { ShouldRun = shouldRun, EntityName = _entityName }); case "remove": return(new RemoveOperation( inKey, outKey, element.StartIndex, element.Length ) { ShouldRun = shouldRun, EntityName = _entityName }); case "trimstart": return(new TrimStartOperation( inKey, outKey, element.TrimChars ) { ShouldRun = shouldRun, EntityName = _entityName }); case "trimstartappend": return(new TrimStartAppendOperation( inKey, outKey, element.TrimChars, element.Separator ) { ShouldRun = shouldRun, EntityName = _entityName }); case "trimend": return(new TrimEndOperation( inKey, outKey, element.TrimChars ) { ShouldRun = shouldRun, EntityName = _entityName }); case "trim": return(new TrimOperation( inKey, outKey, element.TrimChars ) { ShouldRun = shouldRun, EntityName = _entityName }); case "substring": return(new SubstringOperation( inKey, outKey, element.StartIndex, element.Length ) { ShouldRun = shouldRun, EntityName = _entityName }); case "left": return(new LeftOperation( inKey, outKey, element.Length ) { ShouldRun = shouldRun, EntityName = _entityName }); case "right": return(new RightOperation( inKey, outKey, element.Length ) { ShouldRun = shouldRun, EntityName = _entityName }); case "hashcode": case "gethashcode": return(new GetHashCodeOperation( inKey, outKey ) { ShouldRun = shouldRun, EntityName = _entityName }); case "mail": var connection = _process.Connections.GetConnectionByName(element.Connection).Connection; if (!parameters.ContainsName("body")) { parameters.Add(field.Alias, "body", null, "string"); } return(new MailOperation( (MailConnection)connection, parameters ) { ShouldRun = shouldRun, EntityName = _entityName }); case "map": var equals = _process.MapEquals.ContainsKey(element.Map) ? _process.MapEquals[element.Map] : new Map(); var startsWith = _process.MapStartsWith.ContainsKey(element.Map) ? _process.MapStartsWith[element.Map] : new Map(); var endsWith = _process.MapEndsWith.ContainsKey(element.Map) ? _process.MapEndsWith[element.Map] : new Map(); //TODO: Move to Modify and Validate if (equals.Count == 0 && startsWith.Count == 0 && endsWith.Count == 0) { if (element.Map.Contains("=")) { foreach (var item in element.Map.Split(new[] { ',' })) { var split = item.Split(new[] { '=' }); if (split.Length == 2) { var left = split[0]; var right = split[1]; Field tryField; if (_process.TryGetField(_entityName, right, out tryField, false)) { equals.Add(left, new Item(tryField.Alias, right)); } else { equals.Add(left, new Item(right)); } } } if (equals.Count == 0) { _logger.EntityWarn(_entityName, "Map '{0}' is empty.", element.Map); } } else { _logger.EntityWarn(_entityName, "Map '{0}' is empty.", element.Map); } } return(new MapOperation( inKey, outKey, outType, new[] { @equals, startsWith, endsWith } ) { ShouldRun = shouldRun, EntityName = _entityName }); case "markdown": return(new MarkDownOperation(inKey, outKey) { ShouldRun = shouldRun, EntityName = _entityName }); case "padleft": return(new PadLeftOperation( inKey, outKey, element.TotalWidth, element.PaddingChar ) { ShouldRun = shouldRun, EntityName = _entityName }); case "padright": return(new PadRightOperation( inKey, outKey, element.TotalWidth, element.PaddingChar ) { ShouldRun = shouldRun, EntityName = _entityName }); case "tostring": return(new ToStringOperation( inKey, inType, outKey, element.Format ) { ShouldRun = shouldRun, EntityName = _entityName }); case "toupper": return(new ToUpperOperation( inKey, outKey ) { ShouldRun = shouldRun, EntityName = _entityName }); case "tolower": return(new ToLowerOperation( inKey, outKey ) { ShouldRun = shouldRun, EntityName = _entityName }); case "javascript": foreach (var script in element.Scripts) { //TODO: Move to Validate if (!_process.Scripts.ContainsKey(script.Name)) { throw new TransformalizeException(_logger, _entityName, "Invalid script reference: {0}.", script.Name); } scripts[script.Name] = _process.Scripts[script.Name]; } return(new JavascriptOperation( outKey, element.Script, scripts, parameters, _logger ) { ShouldRun = shouldRun, EntityName = _entityName }); case "csharp": foreach (var script in element.Scripts) { // TODO: Move to Validate if (!_process.Scripts.ContainsKey(script.Name)) { throw new TransformalizeException(_logger, _entityName, "Invalid script reference: {0}.", script.Name); } scripts[script.Name] = _process.Scripts[script.Name]; } return(new CSharpOperation( outKey, outType, //TODO: Move to Modify (element.ReplaceSingleQuotes ? Regex.Replace(element.Script, @"(?<=[^'])'{1}(?=[^'])", "\"") : element.Script), scripts, parameters ) { ShouldRun = shouldRun, EntityName = _entityName }); case "razor": case "template": return(new RazorOperation( outKey, outType, element.Template, element.Model, templates, parameters, _logger ) { ShouldRun = shouldRun, EntityName = _entityName }); case "velocity": return(new VelocityOperation( outKey, outType, element.Template, templates, parameters ) { ShouldRun = shouldRun, EntityName = _entityName }); case "tag": return(new TagOperation( outKey, element.Tag, parameters, element.Decode, element.Encode ) { ShouldRun = shouldRun, EntityName = _entityName }); case "format": return(new FormatOperation( outKey, element.Format, parameters ) { ShouldRun = shouldRun, EntityName = _entityName }); case "timespan": return(new TimeSpanOperation( parameters, outKey ) { ShouldRun = shouldRun, EntityName = _entityName }); case "concat": return(new ConcatOperation( outKey, parameters ) { ShouldRun = shouldRun, EntityName = _entityName }); case "totitlecase": return(new ToTitleCaseOperation( inKey, outKey ) { ShouldRun = shouldRun, EntityName = _entityName }); case "formatphone": return(new FormatPhoneOperation(inKey, outKey) { ShouldRun = shouldRun, EntityName = _entityName }); case "join": //TODO: Move to Modify if (element.Separator.Equals(Common.DefaultValue)) { element.Separator = SPACE; } return(new JoinTransformOperation( outKey, element.Separator, parameters ) { ShouldRun = shouldRun, EntityName = _entityName }); case "tolocaltime": return(new ToLocalTimeOperation( inKey, outKey, element.FromTimeZone, element.ToTimeZone ) { ShouldRun = shouldRun, EntityName = _entityName }); case "timeago": return(new RelativeTimeOperation( inKey, outKey, element.FromTimeZone, true ) { ShouldRun = shouldRun, EntityName = _entityName }); case "timeahead": return(new RelativeTimeOperation( inKey, outKey, element.FromTimeZone, false ) { ShouldRun = shouldRun, EntityName = _entityName }); case "timezone": //TODO: Move to Modify element.FromTimeZone = TimeZoneOperation.GuardTimeZone(field.Process, _entityName, element.FromTimeZone, "UTC", _process.Logger); toTimeZone = TimeZoneOperation.GuardTimeZone(field.Process, _entityName, toTimeZone, TimeZoneInfo.Local.Id, _process.Logger); return(new TimeZoneOperation( inKey, outKey, element.FromTimeZone, toTimeZone ) { ShouldRun = shouldRun, EntityName = _entityName }); case "tojson": return(new ToJsonOperation( outKey, parameters ) { ShouldRun = shouldRun, EntityName = _entityName }); case "fromxml": switch ((XmlMode)Enum.Parse(typeof(XmlMode), element.XmlMode)) { case XmlMode.First: return(new FromFirstXmlOperation( outKey, new Fields(_process, parameters, _entityName) ) { ShouldRun = shouldRun, EntityName = _entityName }); case XmlMode.All: return(new FromXmlOperation( outKey, element.Root, new Fields(_process, parameters, _entityName) ) { ShouldRun = shouldRun, EntityName = _entityName }); default: return(new FromNanoXmlOperation( outKey, new Fields(_process, parameters, _entityName) ) { ShouldRun = shouldRun, EntityName = _entityName }); } case "fromregex": return(new FromRegexOperation( outKey, element.Pattern, parameters ) { ShouldRun = shouldRun, EntityName = _entityName }); case "fromjson": return(new FromJsonOperation( TryRemoveInputParameters(element, parameters) ? inKey : outKey, parameters ) { ShouldRun = shouldRun, EntityName = _entityName }); case "fromsplit": return(new FromSplitOperation(outKey, element.Separator, parameters) { ShouldRun = shouldRun, EntityName = _entityName }); case "distance": return(new DistanceOperation( outKey, element.Units, GetParameter(_entityName, element.FromLat), GetParameter(_entityName, element.FromLong), GetParameter(_entityName, element.ToLat), GetParameter(_entityName, element.ToLong) ) { ShouldRun = shouldRun, EntityName = _entityName }); case "length": return(new LengthOperation(inKey, outKey) { ShouldRun = shouldRun, EntityName = _entityName }); case "timeofday": return(new TimeOfDayOperation(inKey, inType, outKey, outType, element.TimeComponent) { ShouldRun = shouldRun, EntityName = _entityName }); case "value": return(new ValueOperation(outKey, outType, element.Value, parameters) { ShouldRun = shouldRun, EntityName = _entityName }); case "xpath": return(new XPathOperation(inKey, outKey, outType, element.Xpath) { ShouldRun = shouldRun, EntityName = _entityName }); case "xmlencode": return(new XmlEncodeOperation(inKey, outKey) { ShouldRun = shouldRun, EntityName = _entityName }); case "urlencode": return(new UrlEncodeOperation(inKey, outKey) { ShouldRun = shouldRun, EntityName = _entityName }); case "htmlencode": return(new HtmlEncodeOperation(inKey, outKey) { ShouldRun = shouldRun, EntityName = _entityName }); case "htmldecode": case "xmldecode": return(new HtmlDecodeOperation(inKey, outKey) { ShouldRun = shouldRun, EntityName = _entityName }); case "filter": return(new FilterOperation( inKey, outKey, outType, element.Value, (ComparisonOperator)Enum.Parse(typeof(ComparisonOperator), element.Operator, true) ) { ShouldRun = shouldRun, EntityName = _entityName }); case "splitindex": return(new SplitIndexOperation( inKey, outKey, outType, element.Separator, element.Count, element.Index ) { ShouldRun = shouldRun, EntityName = _entityName }); case "datepart": return(new DatePartOperation( inKey, outKey, outType, element.TimeComponent ) { ShouldRun = shouldRun, EntityName = _entityName }); case "average": return(new AverageOperation( outKey, outType, parameters ) { ShouldRun = shouldRun, EntityName = _entityName }); case "add": return(new AddOperation( outKey, outType, parameters ) { ShouldRun = shouldRun, EntityName = _entityName }); case "geocode": return(new GeoCodeOperation( inKey, outKey, element.Sleep, element.UseHttps, parameters ) { ShouldRun = shouldRun, EntityName = _entityName }); case "transliterate": return(new TransliterateOperation(inKey, outKey) { ShouldRun = shouldRun, EntityName = _entityName }); case "slug": return(new SlugOperation(inKey, outKey, element.Length) { ShouldRun = shouldRun, EntityName = _entityName }); case "cyrtolat": return(new CyrToLatOperation(inKey, outKey) { ShouldRun = shouldRun, EntityName = _entityName }); case "web": return(new WebOperation( element.Url.Equals(string.Empty) ? parameters[0] : GetParameter(_entityName, element.Url, parameters), outKey, element.Sleep, element.WebMethod, GetParameter(_entityName, element.Data, parameters), element.ContentType ) { ShouldRun = shouldRun, EntityName = _entityName }); case "run": return(new RunOperation( inKey, _process.Connections.GetConnectionByName(element.Connection).Connection, element.TimeOut ) { ShouldRun = shouldRun, EntityName = _entityName }); case "weekofyear": return(new WeekOfYearOperation( inKey, outKey, (CalendarWeekRule)Enum.Parse(typeof(CalendarWeekRule), element.CalendarWeekRule, true), (DayOfWeek)Enum.Parse(typeof(DayOfWeek), element.DayOfWeek, true) ) { ShouldRun = shouldRun, EntityName = _entityName }); // validators case "equals": return(new EqualsOperation(outKey, parameters) { ShouldRun = shouldRun, EntityName = _entityName }); case "isempty": return(new IsEmptyOperation( inKey, outKey ) { ShouldRun = shouldRun, EntityName = _entityName }); case "isdaylightsavings": return(new IsDaylightSavingsOperation( inKey, outKey ) { ShouldRun = shouldRun, EntityName = _entityName }); case "any": return(new AnyOperation( string.IsNullOrEmpty(element.Value) ? GetParameter(_entityName, element.Left, parameters) : new Parameter(element.Value, element.Value), outKey, (ComparisonOperator)Enum.Parse(typeof(ComparisonOperator), element.Operator, true), parameters, element.Negated ) { ShouldRun = shouldRun, EntityName = _entityName }); case "containscharacters": return(new ContainsCharactersValidatorOperation( inKey, outKey, element.Characters, (ContainsCharacters)Enum.Parse(typeof(ContainsCharacters), element.ContainsCharacters, true), element.Negated )); case "datetimerange": return(new DateTimeRangeValidatorOperation( inKey, outKey, (DateTime)_conversionMap[inType](element.LowerBound), (RangeBoundaryType)Enum.Parse(typeof(RangeBoundaryType), element.LowerBoundType, true), (DateTime)_conversionMap[inType](element.UpperBound), (RangeBoundaryType)Enum.Parse(typeof(RangeBoundaryType), element.UpperBoundType, true), element.Negated )); case "domain": if (element.Separator.Equals(Common.DefaultValue)) { element.Separator = COMMA; } var domain = element.Domain.Split(element.Separator.ToCharArray()).Select(s => _conversionMap[inType](s)); return(new DomainValidatorOperation( inKey, outKey, domain, element.Negated )); case "isjson": return(new JsonValidatorOperation(inKey, outKey, element.Negated)); case "notnull": return(new NotNullValidatorOperation(inKey, outKey, element.Negated)); case "fieldcomparison": return(new PropertyComparisonValidatorOperation(inKey, element.TargetField, outKey, element.Operator, element.Negated)); case "range": return(new RangeValidatorOperation( inKey, outKey, (IComparable)_conversionMap[field.SimpleType](element.LowerBound), (RangeBoundaryType)Enum.Parse(typeof(RangeBoundaryType), element.LowerBoundType, true), (IComparable)_conversionMap[field.SimpleType](element.UpperBound), (RangeBoundaryType)Enum.Parse(typeof(RangeBoundaryType), element.UpperBoundType, true), element.Negated )); case "regex": return(new RegexValidatorOperation( inKey, outKey, element.Pattern, element.Negated )); case "relativedatetime": return(new RelativeDateTimeValidatorOperation( inKey, outKey, Convert.ToInt32(element.LowerBound), (DateTimeUnit)Enum.Parse(typeof(DateTimeUnit), element.LowerUnit, true), (RangeBoundaryType)Enum.Parse(typeof(RangeBoundaryType), element.LowerBoundType, true), Convert.ToInt32(element.UpperBound), (DateTimeUnit)Enum.Parse(typeof(DateTimeUnit), element.UpperUnit, true), (RangeBoundaryType)Enum.Parse(typeof(RangeBoundaryType), element.UpperBoundType, true), element.Negated )); case "startswith": return(new StartsWithValidatorOperation( inKey, element.Value, outKey, element.Negated )); case "stringlength": return(new StringLengthValidatorOperation( inKey, outKey, Convert.ToInt32(element.LowerBound), (RangeBoundaryType)Enum.Parse(typeof(RangeBoundaryType), element.LowerBoundType, true), Convert.ToInt32(element.UpperBound), (RangeBoundaryType)Enum.Parse(typeof(RangeBoundaryType), element.UpperBoundType, true), element.Negated )); case "typeconversion": return(new TypeConversionValidatorOperation( inKey, outKey, Common.ToSystemType(element.Type), element.Negated, element.IgnoreEmpty )); } _logger.EntityWarn(_entityName, "{0} method is undefined. It will not be used.", element.Method); return(new EmptyOperation()); }
public override IOperation Extract(Process process, Entity entity, bool firstRun) { if (Schemas && entity.Schema.Equals(string.Empty)) { entity.Schema = DefaultSchema; } var p = new PartialProcessOperation(process); if (entity.HasSqlOverride()) { p.Register(new SqlOverrideOperation(entity, this)); } else { if (entity.PrimaryKey.WithInput().Any()) { p.Register(new EntityKeysSaveOperation(entity)); p.Register(new EntityKeysToOperations(ref entity, this, firstRun)); p.Register(new SerialUnionAllOperation(entity)); } else { entity.SqlOverride = SqlTemplates.Select(entity, this); p.Register(new SqlOverrideOperation(entity, this)); } } return p; }
public override IOperation Insert(Process process, Entity entity) { var pp = new PartialProcessOperation(process); pp.Register(new HtmlRowOperation(entity, "HtmlRow")); pp.Register(new HtmlLoadOperation(this, entity, "HtmlRow")); return pp; }
public IOperation Create(Field field, TflTransform element, IParameters parameters) { if (_isInitMode) return new EmptyOperation(); Func<Row, bool> shouldRun = row => true; var toTimeZone = string.IsNullOrEmpty(element.ToTimeZone) ? _process.TimeZone : element.ToTimeZone; var hasParameters = parameters.Count > 0; var inKey = hasParameters ? parameters[0].Name : field.Alias; var inType = hasParameters ? parameters[0].SimpleType : field.SimpleType; var outKey = field.Alias; var outType = field.SimpleType; var scripts = new Dictionary<string, Script>(); if (!hasParameters) { parameters.Add(field.Alias, field.Alias, null, field.SimpleType); } if (!element.RunField.Equals(string.Empty)) { var op = (ComparisonOperator)Enum.Parse(typeof(ComparisonOperator), element.RunOperator, true); var simpleType = Common.ToSimpleType(element.RunType.Equals(Common.DefaultValue) ? "boolean" : element.RunType); var runValue = simpleType.StartsWith("bool") && element.RunValue.Equals(Common.DefaultValue) ? "true" : element.RunValue; var value = Common.ConversionMap[simpleType](runValue); shouldRun = row => Common.CompareMap[op](row[element.RunField], value); } var templates = ComposeTemplates(field, element); switch (element.Method.ToLower()) { case "convert": return new ConvertOperation( inKey, inType, outKey, element.To.Equals(Common.DefaultValue) ? outType : element.To, element.Encoding, element.Format ) { ShouldRun = shouldRun, EntityName = _entityName }; case "copy": if (parameters.Count > 1) return new CopyMultipleOperation(outKey, parameters) { ShouldRun = shouldRun, EntityName = _entityName }; return new CopyOperation(inKey, outKey) { ShouldRun = shouldRun, EntityName = _entityName }; case "collapse": var partial = new PartialProcessOperation(_process); partial.Register(new RegexReplaceOperation(inKey, outKey, "[\r\n]{2,}", "\r\n", 0) { ShouldRun = shouldRun, EntityName = _entityName }); partial.Register(new RegexReplaceOperation(inKey, outKey, " {2,}", " ", 0) { ShouldRun = shouldRun, EntityName = _entityName }); partial.Register(new TrimOperation(inKey, outKey, " ") { ShouldRun = shouldRun, EntityName = _entityName }); return partial; case "compress": return new CompressOperation(inKey, outKey) { ShouldRun = shouldRun, EntityName = _entityName }; case "toyesno": return new ToYesNoOperation(inKey, outKey) { ShouldRun = shouldRun, EntityName = _entityName}; case "decompress": return new DecompressOperation(inKey, outKey) { ShouldRun = shouldRun, EntityName = _entityName }; case "elipse": return new ElipseOperation(inKey, outKey, element.Length, element.Elipse) { ShouldRun = shouldRun, EntityName = _entityName }; case "replace": return new ReplaceOperation( inKey, outKey, element.OldValue, element.NewValue ) { ShouldRun = shouldRun, EntityName = _entityName }; case "regexreplace": return new RegexReplaceOperation( inKey, outKey, element.Pattern, element.Replacement, element.Count ) { ShouldRun = shouldRun, EntityName = _entityName }; case "striphtml": return new RegexReplaceOperation( inKey, outKey, @"<[^>]+>| ", string.Empty, 0 ) { ShouldRun = shouldRun, EntityName = _entityName }; case "insert": return new InsertOperation( inKey, outKey, element.StartIndex, element.Value, parameters[0].Name.Equals(outKey) ? null : GetParameter(_entityName, parameters[0].Name) ) { ShouldRun = shouldRun, EntityName = _entityName }; case "insertinterval": return new InsertIntervalOperation( inKey, outKey, element.Interval, element.Value ) { ShouldRun = shouldRun, EntityName = _entityName }; case "append": return new AppendOperation( inKey, outKey, element.Value, parameters[0].Name.Equals(outKey) ? null : GetParameter(_entityName, parameters[0].Name) ) { ShouldRun = shouldRun, EntityName = _entityName }; case "if": var leftParameter = GetParameter(_entityName, element.Left, parameters); return new IfOperation( leftParameter, (ComparisonOperator)Enum.Parse(typeof(ComparisonOperator), element.Operator, true), GetParameter(_entityName, element.Right, parameters, leftParameter.SimpleType), GetParameter(_entityName, element.Then, parameters), GetParameter(_entityName, element.Else, parameters), outKey, outType ) { ShouldRun = shouldRun, EntityName = _entityName }; case "distinctwords": if (element.Separator.Equals(Common.DefaultValue)) { element.Separator = SPACE; } return new DistinctWordsOperation( inKey, outKey, element.Separator ) { ShouldRun = shouldRun, EntityName = _entityName }; case "guid": return new GuidOperation(inKey, outKey) { ShouldRun = shouldRun, EntityName = _entityName }; case "utcnow": return new UtcNowOperation( inKey, outKey ) {ShouldRun = shouldRun, EntityName = _entityName}; case "now": return new NowOperation( inKey, outKey ) { ShouldRun = shouldRun, EntityName = _entityName }; case "remove": return new RemoveOperation( inKey, outKey, element.StartIndex, element.Length ) { ShouldRun = shouldRun, EntityName = _entityName }; case "trimstart": return new TrimStartOperation( inKey, outKey, element.TrimChars ) { ShouldRun = shouldRun, EntityName = _entityName }; case "trimstartappend": return new TrimStartAppendOperation( inKey, outKey, element.TrimChars, element.Separator ) { ShouldRun = shouldRun, EntityName = _entityName }; case "trimend": return new TrimEndOperation( inKey, outKey, element.TrimChars ) { ShouldRun = shouldRun, EntityName = _entityName }; case "trim": return new TrimOperation( inKey, outKey, element.TrimChars ) { ShouldRun = shouldRun, EntityName = _entityName }; case "substring": return new SubstringOperation( inKey, outKey, element.StartIndex, element.Length ) { ShouldRun = shouldRun, EntityName = _entityName }; case "left": return new LeftOperation( inKey, outKey, element.Length ) { ShouldRun = shouldRun, EntityName = _entityName }; case "right": return new RightOperation( inKey, outKey, element.Length ) { ShouldRun = shouldRun, EntityName = _entityName }; case "hashcode": case "gethashcode": return new GetHashCodeOperation( inKey, outKey ) { ShouldRun = shouldRun, EntityName = _entityName }; case "mail": var connection = _process.Connections.GetConnectionByName(element.Connection).Connection; if (!parameters.ContainsName("body")) { parameters.Add(field.Alias, "body", null, "string"); } return new MailOperation( (MailConnection)connection, parameters ) { ShouldRun = shouldRun, EntityName = _entityName }; case "map": var equals = _process.MapEquals.ContainsKey(element.Map) ? _process.MapEquals[element.Map] : new Map(); var startsWith = _process.MapStartsWith.ContainsKey(element.Map) ? _process.MapStartsWith[element.Map] : new Map(); var endsWith = _process.MapEndsWith.ContainsKey(element.Map) ? _process.MapEndsWith[element.Map] : new Map(); //TODO: Move to Modify and Validate if (equals.Count == 0 && startsWith.Count == 0 && endsWith.Count == 0) { if (element.Map.Contains("=")) { foreach (var item in element.Map.Split(new[] { ',' })) { var split = item.Split(new[] { '=' }); if (split.Length == 2) { var left = split[0]; var right = split[1]; Field tryField; if (_process.TryGetField(_entityName, right, out tryField, false)) { equals.Add(left, new Item(tryField.Alias, right)); } else { equals.Add(left, new Item(right)); } } } if (equals.Count == 0) { _logger.EntityWarn(_entityName, "Map '{0}' is empty.", element.Map); } } else { _logger.EntityWarn(_entityName, "Map '{0}' is empty.", element.Map); } } return new MapOperation( inKey, outKey, outType, new[] { @equals, startsWith, endsWith } ) { ShouldRun = shouldRun, EntityName = _entityName }; case "markdown": return new MarkDownOperation(inKey, outKey) { ShouldRun = shouldRun, EntityName = _entityName }; case "padleft": return new PadLeftOperation( inKey, outKey, element.TotalWidth, element.PaddingChar ) { ShouldRun = shouldRun, EntityName = _entityName }; case "padright": return new PadRightOperation( inKey, outKey, element.TotalWidth, element.PaddingChar ) { ShouldRun = shouldRun, EntityName = _entityName }; case "tostring": return new ToStringOperation( inKey, inType, outKey, element.Format ) { ShouldRun = shouldRun, EntityName = _entityName }; case "toupper": return new ToUpperOperation( inKey, outKey ) { ShouldRun = shouldRun, EntityName = _entityName }; case "tolower": return new ToLowerOperation( inKey, outKey ) { ShouldRun = shouldRun, EntityName = _entityName }; case "javascript": foreach (var script in element.Scripts) { //TODO: Move to Validate if (!_process.Scripts.ContainsKey(script.Name)) { throw new TransformalizeException(_logger, _entityName, "Invalid script reference: {0}.", script.Name); } scripts[script.Name] = _process.Scripts[script.Name]; } return new JavascriptOperation( outKey, element.Script, scripts, parameters, _logger ) { ShouldRun = shouldRun, EntityName = _entityName }; case "csharp": foreach (var script in element.Scripts) { // TODO: Move to Validate if (!_process.Scripts.ContainsKey(script.Name)) { throw new TransformalizeException(_logger, _entityName, "Invalid script reference: {0}.", script.Name); } scripts[script.Name] = _process.Scripts[script.Name]; } return new CSharpOperation( outKey, outType, //TODO: Move to Modify (element.ReplaceSingleQuotes ? Regex.Replace(element.Script, @"(?<=[^'])'{1}(?=[^'])", "\"") : element.Script), scripts, parameters ) { ShouldRun = shouldRun, EntityName = _entityName }; case "razor": case "template": return new RazorOperation( outKey, outType, element.Template, element.Model, templates, parameters, _logger ) { ShouldRun = shouldRun, EntityName = _entityName }; case "velocity": return new VelocityOperation( outKey, outType, element.Template, templates, parameters ) { ShouldRun = shouldRun, EntityName = _entityName }; case "tag": return new TagOperation( outKey, element.Tag, parameters, element.Decode, element.Encode ) { ShouldRun = shouldRun, EntityName = _entityName }; case "format": return new FormatOperation( outKey, element.Format, parameters ) { ShouldRun = shouldRun, EntityName = _entityName }; case "timespan": return new TimeSpanOperation( parameters, outKey ) { ShouldRun = shouldRun, EntityName = _entityName }; case "concat": return new ConcatOperation( outKey, parameters ) { ShouldRun = shouldRun, EntityName = _entityName }; case "totitlecase": return new ToTitleCaseOperation( inKey, outKey ) { ShouldRun = shouldRun, EntityName = _entityName }; case "formatphone": return new FormatPhoneOperation(inKey, outKey) { ShouldRun = shouldRun, EntityName = _entityName }; case "join": //TODO: Move to Modify if (element.Separator.Equals(Common.DefaultValue)) { element.Separator = SPACE; } return new JoinTransformOperation( outKey, element.Separator, parameters ) { ShouldRun = shouldRun, EntityName = _entityName }; case "tolocaltime": return new ToLocalTimeOperation( inKey, outKey, element.FromTimeZone, element.ToTimeZone ) { ShouldRun = shouldRun, EntityName = _entityName }; case "timeago": return new RelativeTimeOperation( inKey, outKey, element.FromTimeZone, true ) { ShouldRun = shouldRun, EntityName = _entityName }; case "timeahead": return new RelativeTimeOperation( inKey, outKey, element.FromTimeZone, false ) { ShouldRun = shouldRun, EntityName = _entityName }; case "timezone": //TODO: Move to Modify element.FromTimeZone = TimeZoneOperation.GuardTimeZone(field.Process, _entityName, element.FromTimeZone, "UTC", _process.Logger); toTimeZone = TimeZoneOperation.GuardTimeZone(field.Process, _entityName, toTimeZone, TimeZoneInfo.Local.Id, _process.Logger); return new TimeZoneOperation( inKey, outKey, element.FromTimeZone, toTimeZone ) { ShouldRun = shouldRun, EntityName = _entityName }; case "tojson": return new ToJsonOperation( outKey, parameters ) { ShouldRun = shouldRun, EntityName = _entityName }; case "fromxml": switch ((XmlMode)Enum.Parse(typeof(XmlMode), element.XmlMode)) { case XmlMode.First: return new FromFirstXmlOperation( outKey, new Fields(_process, parameters, _entityName) ) { ShouldRun = shouldRun, EntityName = _entityName }; case XmlMode.All: return new FromXmlOperation( outKey, element.Root, new Fields(_process, parameters, _entityName) ) { ShouldRun = shouldRun, EntityName = _entityName }; default: return new FromNanoXmlOperation( outKey, new Fields(_process, parameters, _entityName) ) { ShouldRun = shouldRun, EntityName = _entityName }; } case "fromregex": return new FromRegexOperation( outKey, element.Pattern, parameters ) { ShouldRun = shouldRun, EntityName = _entityName }; case "fromjson": return new FromJsonOperation( TryRemoveInputParameters(element, parameters) ? inKey : outKey, parameters ) { ShouldRun = shouldRun, EntityName = _entityName }; case "fromsplit": return new FromSplitOperation(outKey, element.Separator, parameters) { ShouldRun = shouldRun, EntityName = _entityName }; case "distance": return new DistanceOperation( outKey, element.Units, GetParameter(_entityName, element.FromLat), GetParameter(_entityName, element.FromLong), GetParameter(_entityName, element.ToLat), GetParameter(_entityName, element.ToLong) ) { ShouldRun = shouldRun, EntityName = _entityName }; case "length": return new LengthOperation(inKey, outKey) { ShouldRun = shouldRun, EntityName = _entityName }; case "timeofday": return new TimeOfDayOperation(inKey, inType, outKey, outType, element.TimeComponent) { ShouldRun = shouldRun, EntityName = _entityName }; case "value": return new ValueOperation(outKey, outType, element.Value, parameters) { ShouldRun = shouldRun, EntityName = _entityName }; case "xpath": return new XPathOperation(inKey, outKey, outType, element.Xpath) { ShouldRun = shouldRun, EntityName = _entityName }; case "xmlencode": return new XmlEncodeOperation(inKey, outKey) { ShouldRun = shouldRun, EntityName = _entityName }; case "urlencode": return new UrlEncodeOperation(inKey, outKey) { ShouldRun = shouldRun, EntityName = _entityName }; case "htmlencode": return new HtmlEncodeOperation(inKey, outKey) { ShouldRun = shouldRun, EntityName = _entityName }; case "htmldecode": case "xmldecode": return new HtmlDecodeOperation(inKey, outKey) { ShouldRun = shouldRun, EntityName = _entityName }; case "filter": return new FilterOperation( inKey, outKey, outType, element.Value, (ComparisonOperator)Enum.Parse(typeof(ComparisonOperator), element.Operator, true) ) { ShouldRun = shouldRun, EntityName = _entityName }; case "splitindex": return new SplitIndexOperation( inKey, outKey, outType, element.Separator, element.Count, element.Index ) { ShouldRun = shouldRun, EntityName = _entityName }; case "datepart": return new DatePartOperation( inKey, outKey, outType, element.TimeComponent ) { ShouldRun = shouldRun, EntityName = _entityName }; case "average": return new AverageOperation( outKey, outType, parameters ) { ShouldRun = shouldRun, EntityName = _entityName }; case "add": return new AddOperation( outKey, outType, parameters ) { ShouldRun = shouldRun, EntityName = _entityName }; case "geocode": return new GeoCodeOperation( inKey, outKey, element.Sleep, element.UseHttps, parameters ) { ShouldRun = shouldRun, EntityName = _entityName }; case "transliterate": return new TransliterateOperation(inKey, outKey) { ShouldRun = shouldRun, EntityName = _entityName }; case "slug": return new SlugOperation(inKey, outKey, element.Length) { ShouldRun = shouldRun, EntityName = _entityName }; case "cyrtolat": return new CyrToLatOperation(inKey, outKey) { ShouldRun = shouldRun, EntityName = _entityName }; case "web": return new WebOperation( element.Url.Equals(string.Empty) ? parameters[0] : GetParameter(_entityName, element.Url, parameters), outKey, element.Sleep, element.WebMethod, GetParameter(_entityName, element.Data, parameters), element.ContentType ) { ShouldRun = shouldRun, EntityName = _entityName }; case "run": return new RunOperation( inKey, _process.Connections.GetConnectionByName(element.Connection).Connection, element.TimeOut ) { ShouldRun = shouldRun, EntityName = _entityName }; case "weekofyear": return new WeekOfYearOperation( inKey, outKey, (CalendarWeekRule)Enum.Parse(typeof(CalendarWeekRule),element.CalendarWeekRule, true), (DayOfWeek)Enum.Parse(typeof(DayOfWeek),element.DayOfWeek, true) ) { ShouldRun = shouldRun, EntityName = _entityName }; // validators case "equals": return new EqualsOperation(outKey, parameters) { ShouldRun = shouldRun, EntityName = _entityName }; case "isempty": return new IsEmptyOperation( inKey, outKey ) { ShouldRun = shouldRun, EntityName = _entityName }; case "isdaylightsavings": return new IsDaylightSavingsOperation( inKey, outKey ) { ShouldRun = shouldRun, EntityName = _entityName }; case "any": return new AnyOperation( string.IsNullOrEmpty(element.Value) ? GetParameter(_entityName, element.Left, parameters) : new Parameter(element.Value, element.Value), outKey, (ComparisonOperator)Enum.Parse(typeof(ComparisonOperator), element.Operator, true), parameters, element.Negated ) { ShouldRun = shouldRun, EntityName = _entityName }; case "containscharacters": return new ContainsCharactersValidatorOperation( inKey, outKey, element.Characters, (ContainsCharacters)Enum.Parse(typeof(ContainsCharacters), element.ContainsCharacters, true), element.Negated ); case "datetimerange": return new DateTimeRangeValidatorOperation( inKey, outKey, (DateTime)_conversionMap[inType](element.LowerBound), (RangeBoundaryType)Enum.Parse(typeof(RangeBoundaryType), element.LowerBoundType, true), (DateTime)_conversionMap[inType](element.UpperBound), (RangeBoundaryType)Enum.Parse(typeof(RangeBoundaryType), element.UpperBoundType, true), element.Negated ); case "domain": if (element.Separator.Equals(Common.DefaultValue)) { element.Separator = COMMA; } var domain = element.Domain.Split(element.Separator.ToCharArray()).Select(s => _conversionMap[inType](s)); return new DomainValidatorOperation( inKey, outKey, domain, element.Negated ); case "isjson": return new JsonValidatorOperation(inKey, outKey, element.Negated); case "notnull": return new NotNullValidatorOperation(inKey, outKey, element.Negated); case "fieldcomparison": return new PropertyComparisonValidatorOperation(inKey, element.TargetField, outKey, element.Operator, element.Negated); case "range": return new RangeValidatorOperation( inKey, outKey, (IComparable)_conversionMap[field.SimpleType](element.LowerBound), (RangeBoundaryType)Enum.Parse(typeof(RangeBoundaryType), element.LowerBoundType, true), (IComparable)_conversionMap[field.SimpleType](element.UpperBound), (RangeBoundaryType)Enum.Parse(typeof(RangeBoundaryType), element.UpperBoundType, true), element.Negated ); case "regex": return new RegexValidatorOperation( inKey, outKey, element.Pattern, element.Negated ); case "relativedatetime": return new RelativeDateTimeValidatorOperation( inKey, outKey, Convert.ToInt32(element.LowerBound), (DateTimeUnit)Enum.Parse(typeof(DateTimeUnit), element.LowerUnit, true), (RangeBoundaryType)Enum.Parse(typeof(RangeBoundaryType), element.LowerBoundType, true), Convert.ToInt32(element.UpperBound), (DateTimeUnit)Enum.Parse(typeof(DateTimeUnit), element.UpperUnit, true), (RangeBoundaryType)Enum.Parse(typeof(RangeBoundaryType), element.UpperBoundType, true), element.Negated ); case "startswith": return new StartsWithValidatorOperation( inKey, element.Value, outKey, element.Negated ); case "stringlength": return new StringLengthValidatorOperation( inKey, outKey, Convert.ToInt32(element.LowerBound), (RangeBoundaryType)Enum.Parse(typeof(RangeBoundaryType), element.LowerBoundType, true), Convert.ToInt32(element.UpperBound), (RangeBoundaryType)Enum.Parse(typeof(RangeBoundaryType), element.UpperBoundType, true), element.Negated ); case "typeconversion": return new TypeConversionValidatorOperation( inKey, outKey, Common.ToSystemType(element.Type), element.Negated, element.IgnoreEmpty ); } _logger.EntityWarn(_entityName, "{0} method is undefined. It will not be used.", element.Method); return new EmptyOperation(); }
private PartialProcessOperation PrepareOutputOperation(Process process, NamedConnection output) { var partial = new PartialProcessOperation(process); partial.Register(new FilterOutputOperation(output.ShouldRun) { EntityName = _entity.Name }); if (output.Connection.Type == ProviderType.Internal) { partial.Register(_collectors[output.Name]); } else { if (Process.IsFirstRun || !_entity.DetectChanges) { partial.Register(new EntityAddTflFields(process, _entity)); partial.Register(output.Connection.Insert(process, _entity)); } else { partial.Register(new EntityJoinAction(process, _entity).Right(output.Connection.ExtractCorrespondingKeysFromOutput(_entity))); var branch = new BranchingOperation() .Add(new PartialProcessOperation(process) .Register(new EntityActionFilter(process, _entity, EntityAction.Insert)) .Register(output.Connection.Insert(process, _entity))) .Add(new PartialProcessOperation(process) .Register(new EntityActionFilter(process, _entity, EntityAction.Update)) .Register(output.Connection.Update(_entity))); partial.Register(branch); } } return partial; }