- Handler for content fields.

- Relies on the Activated event to weld fields to parts.
- New event Initializing added to the content management lifecycle, old Activated event is now Initializing.
- Unifying part and field template result classes.
- Refactoring.

--HG--
branch : dev
This commit is contained in:
Suha Can
2010-06-14 13:12:41 -07:00
parent e8766af95a
commit a5833533f9
22 changed files with 163 additions and 122 deletions

View File

@@ -1,11 +1,9 @@
using JetBrains.Annotations;
using Orchard.Core.Common.Models;
using Orchard.Core.Common.ViewModels;
using Orchard.Data;
using Orchard.Localization;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers;
using Orchard.ContentManagement.ViewModels;
using Orchard.Security;
using Orchard.Services;
@@ -37,10 +35,10 @@ namespace Orchard.Core.Common.Handlers {
Filters.Add(StorageFilter.For(commonRepository));
Filters.Add(StorageFilter.For(commonVersionRepository));
OnActivated<CommonAspect>(PropertySetHandlers);
OnActivated<CommonAspect>(AssignCreatingOwner);
OnActivated<ContentPart<CommonRecord>>(AssignCreatingDates);
OnActivated<ContentPart<CommonVersionRecord>>(AssignCreatingDates);
OnInitializing<CommonAspect>(PropertySetHandlers);
OnInitializing<CommonAspect>(AssignCreatingOwner);
OnInitializing<ContentPart<CommonRecord>>(AssignCreatingDates);
OnInitializing<ContentPart<CommonVersionRecord>>(AssignCreatingDates);
OnLoaded<CommonAspect>(LazyLoadHandlers);
@@ -67,20 +65,20 @@ namespace Orchard.Core.Common.Handlers {
public Localizer T { get; set; }
void AssignCreatingOwner(ActivatedContentContext context, CommonAspect part) {
void AssignCreatingOwner(InitializingContentContext context, CommonAspect part) {
// and use the current user as Owner
if (part.Record.OwnerId == 0) {
part.Owner = _authenticationService.GetAuthenticatedUser();
}
}
void AssignCreatingDates(ActivatedContentContext context, ContentPart<CommonRecord> part) {
void AssignCreatingDates(InitializingContentContext context, ContentPart<CommonRecord> part) {
// assign default create/modified dates
part.Record.CreatedUtc = _clock.UtcNow;
part.Record.ModifiedUtc = _clock.UtcNow;
}
void AssignCreatingDates(ActivatedContentContext context, ContentPart<CommonVersionRecord> part) {
void AssignCreatingDates(InitializingContentContext context, ContentPart<CommonVersionRecord> part) {
// assign default create/modified dates
part.Record.CreatedUtc = _clock.UtcNow;
part.Record.ModifiedUtc = _clock.UtcNow;
@@ -124,7 +122,7 @@ namespace Orchard.Core.Common.Handlers {
aspect.ContainerField.Loader(() => aspect.Record.Container == null ? null : _contentManager.Get(aspect.Record.Container.Id));
}
static void PropertySetHandlers(ActivatedContentContext context, CommonAspect aspect) {
static void PropertySetHandlers(InitializingContentContext context, CommonAspect aspect) {
// add handlers that will update records when aspect properties are set
aspect.OwnerField.Setter(user => {

View File

@@ -5,7 +5,6 @@ using Orchard.Localization;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers;
using Orchard.Localization.Services;
using Orchard.Settings;
namespace Orchard.Core.Localization.Handlers {
[UsedImplicitly]
@@ -20,7 +19,7 @@ namespace Orchard.Core.Localization.Handlers {
Filters.Add(StorageFilter.For(localizedRepository));
OnActivated<Localized>(InitializePart);
OnInitializing<Localized>(InitializePart);
OnLoaded<Localized>(LazyLoadHandlers);
@@ -34,7 +33,7 @@ namespace Orchard.Core.Localization.Handlers {
localized.MasterContentItemField.Loader(ctx => _contentManager.Get(localized.Record.MasterContentItemId));
}
void InitializePart(ActivatedContentContext context, Localized localized) {
void InitializePart(InitializingContentContext context, Localized localized) {
localized.CultureField.Setter(cultureRecord => {
localized.Record.CultureId = cultureRecord.Id;
return cultureRecord;

View File

@@ -13,7 +13,7 @@ namespace Orchard.Core.Navigation.Handlers {
Filters.Add(new ActivatingFilter<MenuPart>("menuitem"));
Filters.Add(StorageFilter.For(menuPartRepository));
OnActivated<MenuPart>((ctx, x) => {
OnInitializing<MenuPart>((ctx, x) => {
x.OnMainMenu = false;
x.MenuText = String.Empty;
});

View File

@@ -8,9 +8,7 @@ using Orchard.Blogs.Services;
using Orchard.ContentManagement;
using Orchard.Core.Common.Models;
using Orchard.ContentManagement.Handlers;
using Orchard.Core.Common.Services;
using Orchard.Localization;
using Orchard.UI.Notify;
namespace Orchard.Blogs.Handlers {
[UsedImplicitly]
@@ -40,7 +38,7 @@ namespace Orchard.Blogs.Handlers {
blog.PostCount = posts.Count;
});
OnActivated<BlogPost>((context, bp) => {
OnInitializing<BlogPost>((context, bp) => {
var blogSlug = requestContext.RouteData.Values.ContainsKey("blogSlug") ? requestContext.RouteData.Values["blogSlug"] as string : null;
if (!string.IsNullOrEmpty(blogSlug)) {
bp.Blog = blogService.Get(blogSlug);

View File

@@ -16,7 +16,7 @@ namespace Orchard.Comments.Handlers {
Filters.Add(StorageFilter.For(hasCommentsRepository));
OnActivated<HasComments>((ctx, x) => {
OnInitializing<HasComments>((ctx, x) => {
x.CommentsActive = true;
x.CommentsShown = true;
});

View File

@@ -9,10 +9,10 @@ namespace Orchard.Media.Handlers {
public MediaSettingsHandler(IRepository<MediaSettingsRecord> repository) {
Filters.Add(new ActivatingFilter<MediaSettings>("site"));
Filters.Add(StorageFilter.For(repository) );
OnActivated<MediaSettings>(DefaultSettings);
OnInitializing<MediaSettings>(DefaultSettings);
}
private static void DefaultSettings(ActivatedContentContext context, MediaSettings settings) {
private static void DefaultSettings(InitializingContentContext context, MediaSettings settings) {
settings.Record.RootMediaFolder = "~/Media";
}
}

View File

@@ -1,9 +1,9 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using Orchard.ContentManagement.MetaData.Models;
using Orchard.ContentManagement.Utilities;
namespace Orchard.ContentManagement {
public class ContentField : ContentPart {
public class ContentField {
public virtual ContentPart ContentPart { get; set; }
public string Name { get { return PartFieldDefinition.Name; } }
public IDictionary<string, string> Settings { get; private set; }
@@ -11,10 +11,15 @@ namespace Orchard.ContentManagement {
public new ContentPartDefinition PartDefinition { get { return ContentPart.PartDefinition; } }
public ContentPartDefinition.Field PartFieldDefinition { get; set; }
public ContentFieldDefinition FieldDefinition { get { return PartFieldDefinition.FieldDefinition; } }
public Func<string, string> Getter { get; set; }
public Action<string, string> Setter { get; set; }
}
public class ContentField<TRecord> : ContentField {
public readonly LazyField<TRecord> _record = new LazyField<TRecord>();
public TRecord Record { get { return _record.Value; } set { _record.Value = value; } }
}
//public class AddressField : ContentField {
// public string Zip {
// get {return Getter("zip");}
// set { Setter("zip", value); }
// }
//}
}

View File

@@ -21,12 +21,10 @@ namespace Orchard.ContentManagement {
public bool Has(Type fieldType, string fieldName) {
return fieldType == typeof(ContentItem) || _fields.Any(field => fieldType.IsAssignableFrom(field.GetType()) && field.Name == fieldName);
return _fields.Any(field => fieldType.IsAssignableFrom(field.GetType()) && field.Name == fieldName);
}
public IContent Get(Type fieldType, string fieldName) {
if (fieldType == typeof(ContentItem))
return this;
public ContentField Get(Type fieldType, string fieldName) {
return _fields.FirstOrDefault(field => fieldType.IsAssignableFrom(field.GetType()) && field.Name == fieldName);
}

View File

@@ -5,7 +5,6 @@ using Autofac;
using Orchard.ContentManagement.Handlers;
using Orchard.ContentManagement.MetaData;
using Orchard.ContentManagement.MetaData.Builders;
using Orchard.ContentManagement.MetaData.Models;
using Orchard.ContentManagement.Records;
using Orchard.Data;
using Orchard.Mvc.ViewModels;
@@ -78,8 +77,18 @@ namespace Orchard.ContentManagement {
handler.Activated(context2);
}
var context3 = new InitializingContentContext {
ContentType = contentType,
ContentItem = context.Builder.Build()
};
context3.ContentItem.ContentManager = this;
foreach (var handler in Handlers) {
handler.Initializing(context3);
}
// composite result is returned
return context2.ContentItem;
return context3.ContentItem;
}
public virtual ContentItem Get(int id) {

View File

@@ -1,4 +1,7 @@
using Orchard.ContentManagement.Handlers;
using System.Collections.Generic;
using System.Linq;
using Orchard.ContentManagement.Handlers;
using Orchard.ContentManagement.MetaData;
namespace Orchard.ContentManagement.Drivers {
@@ -6,42 +9,61 @@ namespace Orchard.ContentManagement.Drivers {
DriverResult BuildDisplayModel(BuildDisplayModelContext context);
DriverResult BuildEditorModel(BuildEditorModelContext context);
DriverResult UpdateEditorModel(UpdateEditorModelContext context);
IEnumerable<ContentFieldInfo> GetFieldInfo();
}
public abstract class ContentFieldDriver<TContent> : IContentFieldDriver where TContent : ContentField, new() {
public abstract class ContentFieldDriver<TField> : IContentFieldDriver where TField : ContentField, new() {
protected virtual string Prefix { get { return ""; } }
protected virtual string Zone { get { return "body"; } }
DriverResult IContentFieldDriver.BuildDisplayModel(BuildDisplayModelContext context) {
var field = context.ContentItem.As<TContent>();
return field == null ? null : Display(field, context.DisplayType);
var results = context.ContentItem.Parts.SelectMany(part => part.Fields).
OfType<TField>().
Select(field => Display(field, context.DisplayType));
return Combined(results.ToArray());
}
DriverResult IContentFieldDriver.BuildEditorModel(BuildEditorModelContext context) {
var field = context.ContentItem.As<TContent>();
return field == null ? null : Editor(field);
var results = context.ContentItem.Parts.SelectMany(part => part.Fields).
OfType<TField>().
Select(field => Editor(field));
return Combined(results.ToArray());
}
DriverResult IContentFieldDriver.UpdateEditorModel(UpdateEditorModelContext context) {
var field = context.ContentItem.As<TContent>();
return field == null ? null : Editor(field, context.Updater);
var results = context.ContentItem.Parts.SelectMany(part => part.Fields).
OfType<TField>().
Select(field => Editor(field, context.Updater));
return Combined(results.ToArray());
}
protected virtual DriverResult Display(TContent field, string displayType) { return null; }
protected virtual DriverResult Editor(TContent field) { return null; }
protected virtual DriverResult Editor(TContent field, IUpdateModel updater) { return null; }
public IEnumerable<ContentFieldInfo> GetFieldInfo() {
var contentFieldInfo = new[] {
new ContentFieldInfo {
FieldTypeName = typeof (TField).Name,
Factory = partFieldDefinition => new TField {PartFieldDefinition = partFieldDefinition}
}
};
public ContentFieldTemplateResult ContentPartTemplate(object model) {
return new ContentFieldTemplateResult(model, null, Prefix).Location(Zone);
return contentFieldInfo;
}
public ContentFieldTemplateResult ContentPartTemplate(object model, string template) {
return new ContentFieldTemplateResult(model, template, Prefix).Location(Zone);
protected virtual DriverResult Display(TField field, string displayType) { return null; }
protected virtual DriverResult Editor(TField field) { return null; }
protected virtual DriverResult Editor(TField field, IUpdateModel updater) { return null; }
public ContentTemplateResult ContentPartTemplate(object model) {
return new ContentTemplateResult(model, null, Prefix).Location(Zone);
}
public ContentFieldTemplateResult ContentPartTemplate(object model, string template, string prefix) {
return new ContentFieldTemplateResult(model, template, prefix).Location(Zone);
public ContentTemplateResult ContentPartTemplate(object model, string template) {
return new ContentTemplateResult(model, template, Prefix).Location(Zone);
}
public ContentTemplateResult ContentPartTemplate(object model, string template, string prefix) {
return new ContentTemplateResult(model, template, prefix).Location(Zone);
}
public CombinedResult Combined(params DriverResult[] results) {

View File

@@ -36,16 +36,16 @@ namespace Orchard.ContentManagement.Drivers {
protected virtual DriverResult Editor(TContent part, IUpdateModel updater) { return null; }
public ContentPartTemplateResult ContentPartTemplate(object model) {
return new ContentPartTemplateResult(model, null, Prefix).Location(Zone);
public ContentTemplateResult ContentPartTemplate(object model) {
return new ContentTemplateResult(model, null, Prefix).Location(Zone);
}
public ContentPartTemplateResult ContentPartTemplate(object model, string template) {
return new ContentPartTemplateResult(model, template, Prefix).Location(Zone);
public ContentTemplateResult ContentPartTemplate(object model, string template) {
return new ContentTemplateResult(model, template, Prefix).Location(Zone);
}
public ContentPartTemplateResult ContentPartTemplate(object model, string template, string prefix) {
return new ContentPartTemplateResult(model, template, prefix).Location(Zone);
public ContentTemplateResult ContentPartTemplate(object model, string template, string prefix) {
return new ContentTemplateResult(model, template, prefix).Location(Zone);
}
public CombinedResult Combined(params DriverResult[] results) {

View File

@@ -1,56 +0,0 @@
using System.Linq;
using Orchard.ContentManagement.Handlers;
namespace Orchard.ContentManagement.Drivers {
public class ContentPartTemplateResult : DriverResult {
public object Model { get; set; }
public string TemplateName { get; set; }
public string Prefix { get; set; }
public string Zone { get; set; }
public string Position { get; set; }
public ContentPartTemplateResult(object model, string templateName, string prefix) {
Model = model;
TemplateName = templateName;
Prefix = prefix;
}
public override void Apply(BuildDisplayModelContext context) {
context.ViewModel.Zones.AddDisplayPart(
Zone + ":" + Position, Model, TemplateName, Prefix);
}
public override void Apply(BuildEditorModelContext context) {
context.ViewModel.Zones.AddEditorPart(
Zone + ":" + Position, Model, TemplateName, Prefix);
}
public ContentPartTemplateResult Location(string zone) {
Zone = zone;
return this;
}
public ContentPartTemplateResult Location(string zone, string position) {
Zone = zone;
Position = position;
return this;
}
public ContentPartTemplateResult LongestMatch(string displayType, params string[] knownDisplayTypes) {
if (string.IsNullOrEmpty(displayType))
return this;
var longest = knownDisplayTypes.Aggregate("", (best, x) => {
if (displayType.StartsWith(x) && x.Length > best.Length) return x;
return best;
});
if (string.IsNullOrEmpty(longest))
return this;
TemplateName += "." + longest;
return this;
}
}
}

View File

@@ -2,14 +2,14 @@
using Orchard.ContentManagement.Handlers;
namespace Orchard.ContentManagement.Drivers {
public class ContentFieldTemplateResult : DriverResult {
public class ContentTemplateResult : DriverResult {
public object Model { get; set; }
public string TemplateName { get; set; }
public string Prefix { get; set; }
public string Zone { get; set; }
public string Position { get; set; }
public ContentFieldTemplateResult(object model, string templateName, string prefix) {
public ContentTemplateResult(object model, string templateName, string prefix) {
Model = model;
TemplateName = templateName;
Prefix = prefix;
@@ -25,18 +25,18 @@ namespace Orchard.ContentManagement.Drivers {
Zone + ":" + Position, Model, TemplateName, Prefix);
}
public ContentFieldTemplateResult Location(string zone) {
public ContentTemplateResult Location(string zone) {
Zone = zone;
return this;
}
public ContentFieldTemplateResult Location(string zone, string position) {
public ContentTemplateResult Location(string zone, string position) {
Zone = zone;
Position = position;
return this;
}
public ContentFieldTemplateResult LongestMatch(string displayType, params string[] knownDisplayTypes) {
public ContentTemplateResult LongestMatch(string displayType, params string[] knownDisplayTypes) {
if (string.IsNullOrEmpty(displayType))
return this;

View File

@@ -0,0 +1,26 @@
using System.Collections.Generic;
using System.Linq;
using Orchard.ContentManagement.Drivers;
namespace Orchard.ContentManagement.Handlers {
public class ContentFieldHandler: ContentHandlerBase {
private readonly IEnumerable<IContentFieldDriver> _contentFieldDrivers;
public ContentFieldHandler(IEnumerable<IContentFieldDriver> contentFieldDrivers) {
_contentFieldDrivers = contentFieldDrivers;
}
public override void Activated(ActivatedContentContext context) {
var fieldInfos = _contentFieldDrivers.SelectMany(x => x.GetFieldInfo());
var parts = context.ContentItem.Parts;
foreach (var contentPart in parts) {
foreach (var field in contentPart.Fields) {
var fieldTypeName = field.FieldDefinition.Name;
var fieldInfo = fieldInfos.FirstOrDefault(x => x.FieldTypeName == fieldTypeName);
if (fieldInfo != null)
contentPart.Weld(fieldInfo.Factory(field.PartFieldDefinition));
}
}
}
}
}

View File

@@ -17,6 +17,10 @@ namespace Orchard.ContentManagement.Handlers {
Filters.Add(new InlineStorageFilter<TPart> { OnActivated = handler });
}
protected void OnInitializing<TPart>(Action<InitializingContentContext, TPart> handler) where TPart : class, IContent {
Filters.Add(new InlineStorageFilter<TPart> { OnInitializing = handler });
}
protected void OnCreating<TPart>(Action<CreateContentContext, TPart> handler) where TPart : class, IContent {
Filters.Add(new InlineStorageFilter<TPart> { OnCreating = handler });
}
@@ -90,6 +94,7 @@ namespace Orchard.ContentManagement.Handlers {
class InlineStorageFilter<TPart> : StorageFilterBase<TPart> where TPart : class, IContent {
public Action<ActivatedContentContext, TPart> OnActivated { get; set; }
public Action<InitializingContentContext, TPart> OnInitializing { get; set; }
public Action<CreateContentContext, TPart> OnCreating { get; set; }
public Action<CreateContentContext, TPart> OnCreated { get; set; }
public Action<SaveContentContext, TPart> OnSaving { get; set; }
@@ -107,6 +112,9 @@ namespace Orchard.ContentManagement.Handlers {
protected override void Activated(ActivatedContentContext context, TPart instance) {
if (OnActivated != null) OnActivated(context, instance);
}
protected override void Initializing(InitializingContentContext context, TPart instance) {
if (OnInitializing != null) OnInitializing(context, instance);
}
protected override void Creating(CreateContentContext context, TPart instance) {
if (OnCreating != null) OnCreating(context, instance);
}
@@ -189,6 +197,12 @@ namespace Orchard.ContentManagement.Handlers {
Activated(context);
}
void IContentHandler.Initializing(InitializingContentContext context) {
foreach (var filter in Filters.OfType<IContentStorageFilter>())
filter.Initializing(context);
Initializing(context);
}
void IContentHandler.Creating(CreateContentContext context) {
foreach (var filter in Filters.OfType<IContentStorageFilter>())
filter.Creating(context);
@@ -297,6 +311,8 @@ namespace Orchard.ContentManagement.Handlers {
protected virtual void Activating(ActivatingContentContext context) { }
protected virtual void Activated(ActivatedContentContext context) { }
protected virtual void Initializing(InitializingContentContext context) { }
protected virtual void Creating(CreateContentContext context) { }
protected virtual void Created(CreateContentContext context) { }

View File

@@ -13,6 +13,9 @@ namespace Orchard.ContentManagement.Handlers {
public virtual void Activated(ActivatedContentContext context) {
}
public virtual void Initializing(InitializingContentContext context) {
}
public virtual void Creating(CreateContentContext context) {
}

View File

@@ -6,6 +6,7 @@ namespace Orchard.ContentManagement.Handlers {
void Activating(ActivatingContentContext context);
void Activated(ActivatedContentContext context);
void Initializing(InitializingContentContext context);
void Creating(CreateContentContext context);
void Created(CreateContentContext context);
void Saving(SaveContentContext context);

View File

@@ -1,6 +1,7 @@
namespace Orchard.ContentManagement.Handlers {
public interface IContentStorageFilter : IContentFilter {
void Activated(ActivatedContentContext context);
void Initializing(InitializingContentContext context);
void Creating(CreateContentContext context);
void Created(CreateContentContext context);
void Saving(SaveContentContext context);

View File

@@ -0,0 +1,6 @@
namespace Orchard.ContentManagement.Handlers {
public class InitializingContentContext {
public string ContentType { get; set; }
public ContentItem ContentItem { get; set; }
}
}

View File

@@ -2,6 +2,7 @@ namespace Orchard.ContentManagement.Handlers {
public abstract class StorageFilterBase<TPart> : IContentStorageFilter where TPart : class, IContent {
protected virtual void Activated(ActivatedContentContext context, TPart instance) { }
protected virtual void Initializing(InitializingContentContext context, TPart instance) { }
protected virtual void Creating(CreateContentContext context, TPart instance) { }
protected virtual void Created(CreateContentContext context, TPart instance) { }
protected virtual void Saving(SaveContentContext context, TPart instance) { }
@@ -23,6 +24,11 @@ namespace Orchard.ContentManagement.Handlers {
Activated(context, context.ContentItem.As<TPart>());
}
void IContentStorageFilter.Initializing(InitializingContentContext context) {
if (context.ContentItem.Is<TPart>())
Initializing(context, context.ContentItem.As<TPart>());
}
void IContentStorageFilter.Creating(CreateContentContext context) {
if (context.ContentItem.Is<TPart>())
Creating(context, context.ContentItem.As<TPart>());

View File

@@ -0,0 +1,9 @@
using System;
using Orchard.ContentManagement.MetaData.Models;
namespace Orchard.ContentManagement.MetaData {
public class ContentFieldInfo {
public string FieldTypeName { get; set; }
public Func<ContentPartDefinition.Field, ContentField> Factory { get; set; }
}
}

View File

@@ -173,7 +173,6 @@
</Compile>
<Compile Include="ContentManagement\Drivers\ContentFieldDriver.cs" />
<Compile Include="ContentManagement\Drivers\ContentFieldDriverHandler.cs" />
<Compile Include="ContentManagement\Drivers\ContentFieldTemplateResult.cs" />
<Compile Include="ContentManagement\Drivers\ContentItemDriver.cs">
<SubType>Code</SubType>
</Compile>
@@ -189,9 +188,7 @@
<Compile Include="ContentManagement\Drivers\ContentPartDriverHandler.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="ContentManagement\Drivers\ContentPartTemplateResult.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="ContentManagement\Drivers\ContentTemplateResult.cs" />
<Compile Include="ContentManagement\Drivers\DriverResult.cs">
<SubType>Code</SubType>
</Compile>
@@ -219,6 +216,7 @@
<Compile Include="ContentManagement\Handlers\ContentContextBase.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="ContentManagement\Handlers\ContentFieldHandler.cs" />
<Compile Include="ContentManagement\Handlers\ContentHandler.cs">
<SubType>Code</SubType>
</Compile>
@@ -250,6 +248,7 @@
<Compile Include="ContentManagement\Handlers\IContentTemplateFilter.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="ContentManagement\Handlers\InitializingContentContext.cs" />
<Compile Include="ContentManagement\Handlers\LoadContentContext.cs">
<SubType>Code</SubType>
</Compile>
@@ -298,6 +297,7 @@
</Compile>
<Compile Include="ContentManagement\MetaData\Builders\ContentPartDefinitionBuilder.cs" />
<Compile Include="ContentManagement\MetaData\Builders\ContentTypeDefinitionBuilder.cs" />
<Compile Include="ContentManagement\MetaData\ContentFieldInfo.cs" />
<Compile Include="ContentManagement\MetaData\ContentPartHandler.cs">
<SubType>Code</SubType>
</Compile>