changeset 65:ebce59b45b50

Agregado de version inicial del publicador para el blog
author ROWIES@ardejorxp.inworx.corp
date Tue, 17 May 2011 18:04:56 -0300
parents c40b97bbed01
children a61f3204c9f7
files Agendas/trunk/src/Agendas.Blog/Agendas.Blog.csproj Agendas/trunk/src/Agendas.Blog/IPostWriter.cs Agendas/trunk/src/Agendas.Blog/IPostWriterFactory.cs Agendas/trunk/src/Agendas.Blog/Impl/BlogPublicador.cs Agendas/trunk/src/Agendas.Blog/Impl/NullObjectPostWriter.cs Agendas/trunk/src/Agendas.Blog/Impl/PostWriter.cs Agendas/trunk/src/Agendas.Blog/Impl/PostWriterFactory.cs Agendas/trunk/src/Agendas.Blog/Impl/PublicarReunionPostWriter.cs Agendas/trunk/src/Agendas.Blog/Impl/RealizarReunionPostWriter.cs Agendas/trunk/src/Agendas.Blog/Properties/AssemblyInfo.cs Agendas/trunk/src/Agendas.Blog/Properties/Resources.Designer.cs Agendas/trunk/src/Agendas.Blog/Properties/Resources.resx Agendas/trunk/src/Agendas.Tests/Agendas.Tests.csproj Agendas/trunk/src/Agendas.Tests/DateTimeFormattingTests.cs Agendas/trunk/src/Agendas.sln
diffstat 15 files changed, 623 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Blog/Agendas.Blog.csproj	Tue May 17 18:04:56 2011 -0300
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{DDD605FF-EF42-428A-AEB6-F3496A46A82B}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Agendas.Blog</RootNamespace>
+    <AssemblyName>Agendas.Blog</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Impl\BlogPublicador.cs" />
+    <Compile Include="IPostWriter.cs" />
+    <Compile Include="IPostWriterFactory.cs" />
+    <Compile Include="Impl\NullObjectPostWriter.cs" />
+    <Compile Include="Impl\PostWriter.cs" />
+    <Compile Include="Impl\PostWriterFactory.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Properties\Resources.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DesignTime>True</DesignTime>
+      <DependentUpon>Resources.resx</DependentUpon>
+    </Compile>
+    <Compile Include="Impl\PublicarReunionPostWriter.cs" />
+    <Compile Include="Impl\RealizarReunionPostWriter.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Agendas.Domain\Agendas.Domain.csproj">
+      <Project>{A14907DF-02E4-4FA7-BE27-4292AF50AA22}</Project>
+      <Name>Agendas.Domain</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="Properties\Resources.resx">
+      <Generator>ResXFileCodeGenerator</Generator>
+      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Blog/IPostWriter.cs	Tue May 17 18:04:56 2011 -0300
@@ -0,0 +1,9 @@
+using AltNetHispano.Agendas.Domain;
+
+namespace Agendas.Blog
+{
+  public interface IPostWriter
+  {
+    void WritePost(Evento evento);
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Blog/IPostWriterFactory.cs	Tue May 17 18:04:56 2011 -0300
@@ -0,0 +1,9 @@
+using AltNetHispano.Agendas.Domain;
+
+namespace Agendas.Blog
+{
+  public interface IPostWriterFactory
+  {
+    IPostWriter GetPostWriter(Accion accion);
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Blog/Impl/BlogPublicador.cs	Tue May 17 18:04:56 2011 -0300
@@ -0,0 +1,20 @@
+using AltNetHispano.Agendas.Domain;
+
+namespace Agendas.Blog.Impl
+{
+  public class BlogPublicador : IPublicador
+  {
+    private readonly IPostWriterFactory _postWriterFactory;
+
+    public BlogPublicador(IPostWriterFactory postWriterFactory)
+    {
+      _postWriterFactory = postWriterFactory;
+    }
+
+    public void Publicar(Evento evento)
+    {
+      foreach (var track in evento.Tracks)
+        _postWriterFactory.GetPostWriter(track.Accion).WritePost(evento);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Blog/Impl/NullObjectPostWriter.cs	Tue May 17 18:04:56 2011 -0300
@@ -0,0 +1,22 @@
+using AltNetHispano.Agendas.Domain;
+
+namespace Agendas.Blog.Impl
+{
+  public class NullObjectPostWriter : PostWriter
+  {
+    public override void WritePost(Evento evento)
+    {
+      //no-op
+    }
+
+    protected override string GetBody(Evento evento)
+    {
+      throw new System.NotImplementedException();
+    }
+
+    protected override string GetTitle(Evento evento)
+    {
+      throw new System.NotImplementedException();
+    }
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Blog/Impl/PostWriter.cs	Tue May 17 18:04:56 2011 -0300
@@ -0,0 +1,31 @@
+using System;
+using AltNetHispano.Agendas.Domain;
+
+namespace Agendas.Blog.Impl
+{
+  public abstract class PostWriter : IPostWriter
+  {
+    public virtual void WritePost(Evento evento)
+    {
+      var title = GetTitle(evento);
+      var body = GetBody(evento);
+      this.ExecuteService(title, body);
+    }
+
+    protected abstract string GetBody(Evento evento);
+
+    protected abstract string GetTitle(Evento evento);
+
+    protected string GetNombreUsuario(Evento evento)
+    {
+      return string.Empty;
+      //return evento.Tracks.Single(t => t.Accion == Accion.Realizar).Usuario; TODO (property Usuario debe ser publica)
+    }
+
+    protected void ExecuteService(string title, string body)
+    {
+      //TODO: invocar al web service
+      throw new NotImplementedException();
+    }
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Blog/Impl/PostWriterFactory.cs	Tue May 17 18:04:56 2011 -0300
@@ -0,0 +1,20 @@
+using AltNetHispano.Agendas.Domain;
+
+namespace Agendas.Blog.Impl
+{
+  public class PostWriterFactory : IPostWriterFactory
+  {
+    public IPostWriter GetPostWriter(Accion accion)
+    {
+      switch (accion)
+      {
+        case Accion.Realizar:
+          return new RealizarReunionPostWriter();
+        case Accion.Publicar:
+          return new PublicarReunionPostWriter();
+        default:
+          return new NullObjectPostWriter();
+      }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Blog/Impl/PublicarReunionPostWriter.cs	Tue May 17 18:04:56 2011 -0300
@@ -0,0 +1,33 @@
+using System;
+using System.Globalization;
+using Agendas.Blog.Properties;
+using AltNetHispano.Agendas.Domain;
+
+namespace Agendas.Blog.Impl
+{
+  public class PublicarReunionPostWriter : PostWriter
+  {
+    protected override string GetTitle(Evento evento)
+    {
+      return string.Format(CultureInfo.InvariantCulture, Resources.VAN_Publicacion_Title,
+                           string.Empty, //# de VAN en el historial TODO
+                           evento.Ponente.Nombre //Nombre y apellido del ponente
+
+        );
+    }
+
+    protected override string GetBody(Evento evento)
+    {
+      return string.Format(CultureInfo.InvariantCulture, Resources.VAN_Realizacion_Body,
+                           getUrlPublicacionEnWiki(evento), //Url al video publicado en la wiki
+                           GetNombreUsuario(evento) //Usuario que postea en el blog
+        );
+    }
+
+    private string getUrlPublicacionEnWiki(Evento evento)
+    {
+      //TODO
+      throw new NotImplementedException();
+    }
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Blog/Impl/RealizarReunionPostWriter.cs	Tue May 17 18:04:56 2011 -0300
@@ -0,0 +1,50 @@
+using System;
+using System.Globalization;
+using Agendas.Blog.Properties;
+using AltNetHispano.Agendas.Domain;
+using System.Linq;
+
+namespace Agendas.Blog.Impl
+{
+  public class RealizarReunionPostWriter : PostWriter
+  {
+    protected override string GetTitle(Evento evento)
+    {
+      return string.Format(CultureInfo.InvariantCulture, Resources.VAN_Realizacion_Title,
+                           evento.Ponente.Nombre, //Nombre y apellido del ponente
+                           evento.Titulo //Tema a tratar en la reunion
+        );
+    }
+
+    protected override string GetBody(Evento evento)
+    {
+      var fecha = getFechaFormateada(evento.Fecha);
+      return string.Format(CultureInfo.InvariantCulture, Resources.VAN_Realizacion_Body,
+                           fecha, //Fecha y hora en GMT+0
+                           evento.Ponente.Nombre, //Nombre y apellido del ponente
+                           evento.Titulo, //Tema a tratar en la reunion
+                           getUrlThreadListaCorreo(evento), //Url al thread en la lista de correo
+                           GetNombreUsuario(evento) //Usuario que postea en el blog
+        );
+    }
+
+    private string getFechaFormateada(DateTime? fecha)
+    {
+      if (fecha == null)
+        throw new ArgumentNullException("fecha");
+
+      var fechaCast = (DateTime)fecha;
+      var culture = CultureInfo.CreateSpecificCulture("es-ES");
+      var result = fechaCast.ToString("D", culture) + " a las " +
+                     fechaCast.ToString("t", culture) + " UTC/GMT";
+
+      return result;
+    }
+
+    private string getUrlThreadListaCorreo(Evento evento)
+    {
+      return string.Format(CultureInfo.InvariantCulture, Resources.VAN_Realizacion_Body_UrlListaCorreo,
+                           string.Empty /*evento.UrlListaCorreo*/);//TODO
+    }
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Blog/Properties/AssemblyInfo.cs	Tue May 17 18:04:56 2011 -0300
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Agendas.Blog")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Inworx IT Solutions")]
+[assembly: AssemblyProduct("Agendas.Blog")]
+[assembly: AssemblyCopyright("Copyright © Inworx IT Solutions 2011")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("07426378-5e93-4122-b92f-a0c300d5cd7a")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Blog/Properties/Resources.Designer.cs	Tue May 17 18:04:56 2011 -0300
@@ -0,0 +1,123 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.225
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace Agendas.Blog.Properties {
+    using System;
+    
+    
+    /// <summary>
+    ///   A strongly-typed resource class, for looking up localized strings, etc.
+    /// </summary>
+    // This class was auto-generated by the StronglyTypedResourceBuilder
+    // class via a tool like ResGen or Visual Studio.
+    // To add or remove a member, edit your .ResX file then rerun ResGen
+    // with the /str option, or rebuild your VS project.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    internal class Resources {
+        
+        private static global::System.Resources.ResourceManager resourceMan;
+        
+        private static global::System.Globalization.CultureInfo resourceCulture;
+        
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Resources() {
+        }
+        
+        /// <summary>
+        ///   Returns the cached ResourceManager instance used by this class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Resources.ResourceManager ResourceManager {
+            get {
+                if (object.ReferenceEquals(resourceMan, null)) {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Agendas.Blog.Properties.Resources", typeof(Resources).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+        
+        /// <summary>
+        ///   Overrides the current thread's CurrentUICulture property for all
+        ///   resource lookups using this strongly typed resource class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Globalization.CultureInfo Culture {
+            get {
+                return resourceCulture;
+            }
+            set {
+                resourceCulture = value;
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to &lt;p&gt;Ya está publicada la grabación de esta VAN en: &lt;/p&gt;
+        ///&lt;p&gt;&lt;a href=&quot;{0}&quot;&gt;{0}&lt;/a&gt;&lt;/p&gt;
+        ///&lt;br /&gt;
+        ///&lt;p&gt; &lt;/p&gt;
+        ///&lt;p&gt;En nombre de la comunidad ALT.NET Hispano,&lt;/p&gt;
+        ///&lt;p&gt;{1}&lt;/p&gt;
+        ///&lt;p&gt;&lt;/p&gt;.
+        /// </summary>
+        internal static string VAN_Publicacion_Body {
+            get {
+                return ResourceManager.GetString("VAN_Publicacion_Body", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Publicada la grabación de la VAN #{0} - {1}.
+        /// </summary>
+        internal static string VAN_Publicacion_Title {
+            get {
+                return ResourceManager.GetString("VAN_Publicacion_Title", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to &lt;p&gt;El día {0}, {1} presentará en una nueva VAN el tema &quot;{2}&quot;&lt;/p&gt;
+        ///{3}
+        ///&lt;p&gt;&amp;nbsp;&lt;/p&gt;
+        ///&lt;p&gt;Para acceder, pueden hacerlo por live meeting mediante alguno de los siguientes enlaces:&lt;/p&gt;
+        ///&lt;p&gt;&lt;a href=&quot;http://snipr.com/virtualaltnet&quot;&gt;http://snipr.com/virtualaltnet &lt;/a&gt;&lt;/p&gt;
+        ///&lt;p&gt;&lt;a href=&quot;https://www323.livemeeting.com/cc/usergroups/join?id=van&amp;amp;role=attend&quot;&gt;https://www323.livemeeting.com/cc/usergroups/join?id=van&amp;amp;role=attend&lt;/a&gt;&lt;/p&gt;
+        ///&lt;p&gt;&amp;nbsp;&lt;/p&gt;
+        ///&lt;p&gt;Más información sobre las reuniones virtuales de la comuni [rest of string was truncated]&quot;;.
+        /// </summary>
+        internal static string VAN_Realizacion_Body {
+            get {
+                return ResourceManager.GetString("VAN_Realizacion_Body", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to &lt;p&gt;En el siguiente enlace a la lista de correos, podrán encontrar el detalle de los temas a tratar:&lt;/p&gt;
+        ///&lt;p&gt;&lt;a href=&quot;{0}&quot;&gt;{0}&lt;/a&gt;&lt;/p&gt;
+        ///&lt;p&gt;&lt;/p&gt;.
+        /// </summary>
+        internal static string VAN_Realizacion_Body_UrlListaCorreo {
+            get {
+                return ResourceManager.GetString("VAN_Realizacion_Body_UrlListaCorreo", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Presentación de VAN con {0} - {1}.
+        /// </summary>
+        internal static string VAN_Realizacion_Title {
+            get {
+                return ResourceManager.GetString("VAN_Realizacion_Title", resourceCulture);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Blog/Properties/Resources.resx	Tue May 17 18:04:56 2011 -0300
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <data name="VAN_Publicacion_Body" xml:space="preserve">
+    <value>&lt;p&gt;Ya está publicada la grabación de esta VAN en: &lt;/p&gt;
+&lt;p&gt;&lt;a href="{0}"&gt;{0}&lt;/a&gt;&lt;/p&gt;
+&lt;br /&gt;
+&lt;p&gt; &lt;/p&gt;
+&lt;p&gt;En nombre de la comunidad ALT.NET Hispano,&lt;/p&gt;
+&lt;p&gt;{1}&lt;/p&gt;
+&lt;p&gt;&lt;/p&gt;</value>
+  </data>
+  <data name="VAN_Publicacion_Title" xml:space="preserve">
+    <value>Publicada la grabación de la VAN #{0} - {1}</value>
+  </data>
+  <data name="VAN_Realizacion_Body" xml:space="preserve">
+    <value>&lt;p&gt;El día {0}, {1} presentará en una nueva VAN el tema "{2}"&lt;/p&gt;
+{3}
+&lt;p&gt;&amp;nbsp;&lt;/p&gt;
+&lt;p&gt;Para acceder, pueden hacerlo por live meeting mediante alguno de los siguientes enlaces:&lt;/p&gt;
+&lt;p&gt;&lt;a href="http://snipr.com/virtualaltnet"&gt;http://snipr.com/virtualaltnet &lt;/a&gt;&lt;/p&gt;
+&lt;p&gt;&lt;a href="https://www323.livemeeting.com/cc/usergroups/join?id=van&amp;amp;role=attend"&gt;https://www323.livemeeting.com/cc/usergroups/join?id=van&amp;amp;role=attend&lt;/a&gt;&lt;/p&gt;
+&lt;p&gt;&amp;nbsp;&lt;/p&gt;
+&lt;p&gt;Más información sobre las reuniones virtuales de la comunidad:&lt;/p&gt;
+&lt;p&gt;&lt;a href="../../reuniones/descripcion.aspx"&gt;http://altnethispano.org/reuniones/descripcion.aspx&lt;/a&gt;&lt;/p&gt;
+&lt;p&gt; &lt;/p&gt;
+&lt;p&gt;&lt;/p&gt;
+&lt;p&gt;En nombre de la comunidad ALT.NET Hispano,&lt;/p&gt;
+&lt;p&gt;{4}&lt;/p&gt;</value>
+  </data>
+  <data name="VAN_Realizacion_Body_UrlListaCorreo" xml:space="preserve">
+    <value>&lt;p&gt;En el siguiente enlace a la lista de correos, podrán encontrar el detalle de los temas a tratar:&lt;/p&gt;
+&lt;p&gt;&lt;a href="{0}"&gt;{0}&lt;/a&gt;&lt;/p&gt;
+&lt;p&gt;&lt;/p&gt;</value>
+  </data>
+  <data name="VAN_Realizacion_Title" xml:space="preserve">
+    <value>Presentación de VAN con {0} - {1}</value>
+  </data>
+</root>
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.Tests/Agendas.Tests.csproj	Tue May 17 01:55:19 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Tests/Agendas.Tests.csproj	Tue May 17 18:04:56 2011 -0300
@@ -53,6 +53,7 @@
   </ItemGroup>
   <ItemGroup>
     <Compile Include="Cruds\EventoCrud.cs" />
+    <Compile Include="DateTimeFormattingTests.cs" />
     <Compile Include="PonentesTests.cs" />
     <Compile Include="PropuestasTests.cs" />
     <Compile Include="Cruds\EventoTests.cs" />
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Tests/DateTimeFormattingTests.cs	Tue May 17 18:04:56 2011 -0300
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using NUnit.Framework;
+
+namespace AltNetHispano.Agendas.Tests
+{
+  [TestFixture]
+  public class DateTimeFormattingTests
+  {
+    [Test]
+    public void la_fecha_debe_formatearse_en_castellano()
+    {
+      var fecha = new DateTime(2010, 11, 20, 18, 0, 0);
+      Assert.AreEqual("sábado, 20 de noviembre de 2010", fecha.ToString("D", CultureInfo.CreateSpecificCulture("es-ES")));
+    }
+
+    [Test]
+    public void la_hora_debe_expresarse_en_24hs()
+    {
+      var fecha = new DateTime(2010, 11, 20, 18, 0, 0);
+      Assert.AreEqual("18:00", fecha.ToString("t", CultureInfo.CreateSpecificCulture("es-ES")));
+    }
+  }
+
+}
--- a/Agendas/trunk/src/Agendas.sln	Tue May 17 01:55:19 2011 -0300
+++ b/Agendas/trunk/src/Agendas.sln	Tue May 17 18:04:56 2011 -0300
@@ -22,6 +22,8 @@
 		Features.txt = Features.txt
 	EndProjectSection
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Agendas.Blog", "Agendas.Blog\Agendas.Blog.csproj", "{DDD605FF-EF42-428A-AEB6-F3496A46A82B}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -56,6 +58,10 @@
 		{306DDA8A-49A5-42E5-A639-A9D3D521865F}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{306DDA8A-49A5-42E5-A639-A9D3D521865F}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{306DDA8A-49A5-42E5-A639-A9D3D521865F}.Release|Any CPU.Build.0 = Release|Any CPU
+		{DDD605FF-EF42-428A-AEB6-F3496A46A82B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{DDD605FF-EF42-428A-AEB6-F3496A46A82B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{DDD605FF-EF42-428A-AEB6-F3496A46A82B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{DDD605FF-EF42-428A-AEB6-F3496A46A82B}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE