Month: July 2007

.NET en vrac…

Posted by – July 27, 2007

  • un (très bon) billet sur le principe de simplicité. J’essaie d’appliquer ce principe depuis plusieurs années déjà, pas toujours évident, mais devrait faire partie de la liste des meilleures pratiques de tout développeur. L’auteur est le coordinateur1 de BlogEngine.Net, et à la vue de son CV, je ne peux dire que respect
  • Visual Studio 2008 Bêta 2 : Silverlight 1.0 RC1 inclus, .NET 3.5
  • les Rubystes vont être contents (mmmMMMM) : IronRuby : en pre-Alpha12, bientôt dans les bacs sur RubyForge, et sous licence3 Ms-PL , sinon il y a toujours Ruby.NET
  • vous connaissez delicious, voici son avatar Devlicios.us, une communauté .NET
  • Codeur ? alors Koders propose des outils de recherche pour Visual Studio, Eclipse, ou Firefox sous forme d’extension.
  • un article sur les meilleures pratiques NHibernate où on nous parle de design (patterns), inversion de dépendance, ws, asp.net, tests, le tout autour de NHibernate 1.2
  • un tutoriel, 1er d’une série, sur les design patterns, dans la série meilleures pratiques, toujours bien de s’en rappeler quelques uns.

1 bientôt la 1.2, avec notamment la possibilité de faire des hooks sur divers événements de BlogEngine, souplesse pour l’extensibilité au rendez-vous !

2 Déjà un fix pour un bug concernant les opérations mathématiques, et un tutoriel pour une 1ère utilisation

3 Oui, oui, MS se met (enfin) à l’Opensource, très bonne initiative

Faites un don pour les réfugiés du Darfour au Tchad

Posted by – July 25, 2007

Vous avez un surplus de monnaie, vous voulez payer moins d’impôts, ou tout simplement parce que cela vous touche, alors faites un don pour les réfugiés du Darfour dans l’est du Tchad, un peu de sous pour un grand soutien.

Source : Planète Eléa

Inscriptions aux Techdays 2008 ouvertes

Posted by – July 23, 2007

Inscriptions aux Techdays 2008

…c’est tôt, vu qu’ils auront lieu les 11, 12 et 13 Février 2008 ;)

Source : Christophe

Comment ça marche dokuWiki ?

Posted by – July 19, 2007

dokuWiki est un moteur de Wiki opensource, qui a la particularité de fonctionner sans base de données. Un wiki est très utile pour documenter, d’autant plus lorsqu’on travaille en équipe, cela permet une synergie et un travail en mode collaboratif, bien mieux que de la documentation Word ou OpenOffice.

Un résumé de ses fonctionnalités : historique des versions, interface ergonomique et utilisation d’Ajax (mode brouillon, correcteur orthographique, recherche), ne nécessite pas de base de données, table des matières automatisée, RSS/Atom, Opensearch, URLs courtes, nombreux plugins.

Parmi les plugins à avoir :

  • notes : permet d’écrire des notes bien visibles
  • box : offre la possibilité de faire des boites personnalisables

Ceux-là seront à installer dans ~/lib/plugins , et activer par le biais de l’interface d’administration (/doku.php/start?do=admin).

Le correcteur orthographique est bien pratique, et reste bien géré sous dokuWiki (en Ajax), il requiert aspell et son dictionnaire aspell-fr (ou toute langue qui vous plaira) :

  • apt-get install aspell
  • apt-get install aspell-fr

et l’activer dans les paramètres de configuration de dokuWiki (doku.php/start?do=admin&page=config).

Dans les paramètres, j’aime aussi les URL esthétiques, voir la section Paramètres avancées.

Le wiki est installé sur votre serveur Web préféré, il reste à écrire une nouvelle page.

Le principe est simple : tout accès à une page inexistante permet de la créer : par exemple, http://monsite/doku.php/manouvellepage ouvrira une page avec un bouton Créer cette page, rien de plus simple.

Il vous reste à apprendre la syntaxe du wiki pour formater le texte, accéder à d’autres parties du wiki, ou faire des sections (les =).

Blogengine.net : un moteur de blog .NET multi-blogs, multi-utilisateurs, …

Posted by – July 18, 2007

Blogengine.net vient de mettre à jour son moteur en version 1.1.

J’avais déjà installé et essayé la 1.0 qui souffrait un peu de sa jeunesse mais était déjà prometteuse :

  • multi-blogs
  • multi-utilisateurs
  • pas de base de données nécessaire
  • web 2.0 : ajax, microformats, rss, respect des standards
  • thèmes

Cette version 1.1 ajoute notamment le support de SQL Server, la protection contre les spams, internationalisation en 17 langues, de nouveaux thèmes, des modules (vote, derniers posts, …), …

La traduction française est assurée par l’auteur de ce blog.

Au niveau de l’architecture, projet intéressant du point de vue de l’abstraction des couches et des techniques utilisées, du code propre : providers pour le stockage (Xml, SQL Server), ensemble d’handlers pour servir différents services (Syndication, Rating, Sitemap, …) et donc extensibles, API (MetaWeblogAPI), modules (redirections d’URLs / courtes, compression).

Comment ça marche memcached ?

Posted by – July 17, 2007

Comme le dit le site Danga qui maintient le projet

memcached is a high-performance, distributed memory object caching system, generic in nature, but intended for use in speeding up dynamic web applications by alleviating database load.

On peut faire l’analogie avec les IPC sous Un*x : mémoire partagée et gestion des sémaphores, mais memcached permet le partage de données entre plusieurs machines ou processus à partir d’un cache serveur(s).

Memcached est utilisé par de gros sites tels que Live Journal, Facebook, Digg ou Slashdot. Le plus de memcached est qu’il est fournit avec de nombreuses API : Perl, .NET, Php, Ruby, …, ce qui facilite l’interopérabilité entre les systèmes.

  • Installation sous Debian : apt-get install memcached
  • Fichier de configuration : /etc/memcached.conf

Quelques ressources sur memcached

Dans le cadre d’un projet, j’en ai eu besoin afin de partager des URLs1 entre un serveur Linux et un serveur Windows 2003, ces 2 derniers effectuant des traitements sur des mails. Le service memcached2 étant installé sur le serveur Debian. L’affichage du résultat des 2 traitements Linux/Windows s’effectue sur une simple page ASP.NET d’un 3ème serveur.

memcached pourrait remplacer tout système de cache pour le Web (l’objet Cache d’ASP.NET compris). Le cache est primordial pour tout site un tant soit peu sérieux. 2 implémentations de la librairie C# pour le client memcached : Memcacheddotnet, EnyimMemcached (non testé).

Ci-après le code des 2 scripts à titre d’exemples, ils ne sont pas opérationnels tels que.

Script Perl

Dans le script Perl, les méthodes à connaître :

  • le constructeur, le cache peut être géré par plusieurs serveur de façon transparent : my $memd = new Cache::Memcached { ‘servers’ => [ “localhost:11211” ], };
  • stocker une valeur, $expire (expiration de la donnée en sec.) est optionnel : $memd->set($cle,$valeur,$expire);
  • obtenir une valeur : $val = $memd->get(“macle”);

Code complet du script Perl de traitement. Il a pour but de traiter des mails (bounces) provenant d’une douane anti-spams afin d’en extraire les URLs d’accès à l’interface Web de la quarantaine pour le mail concerné.


#!/usr/bin/perl
use lib '/home/sympa/bin';
use List;
use Conf;
use Log;
use Message;
use DBI;
use MIME::Parser;
use Cache::Memcached;
# email de notifications de la douane anti-spam
my $fromdouane="no-reply\\@xxxx.net";
my $regexp = "^(http://.+)";
my $expire = 8*60*60;
&Conf::load('/etc/sympa.conf') || die 'config_error';
my $spool = $Conf{'queue'};
my $memd = new Cache::Memcached { 'servers' => [ "localhost:11211" ], };
# traitement d'un message
# sortir l'URL d'accès à la quarantaine de la douane
# pour le mail concerné
sub TraiteMessage {
($message) = @_;
my $msg = $message->{'msg'};
my $hdr = $msg->head;
my $rcpt = $message->{'rcpt'};
my $sender = $message->{'sender'};
($listname, $robot) = split(/\\@/,$rcpt);
$listname = lc($listname);
if ($msg->is_multipart()) {
my $status = &tools::as_singlepart($msg, 'text/plain');
unless (defined $status) {
&do_log('err', 'Could not change multipart to singlepart');
return undef;
}
}
if (defined $msg->bodyhandle) {
my $mime = $hdr->get('Mime-Version') ;
my $content_type = $hdr->get('Content-type');
my $transfert_encoding = $hdr->get('Content-transfer-encoding');
unless (($content_type =~ /text/i and !$mime)
or !($content_type)
or ($content_type =~ /text\\/plain/i)) {
return $success;
}
my @body = $msg->bodyhandle->as_lines();
foreach $i (@body) {
#if ($transfert_encoding =~ /quoted-printable/i) {
# $i = MIME::QuotedPrint::decode($i);
#}
$i =~ s/^\\s*>?\\s*(.*)\\s*$/$1/g;
next if ($i =~ /^$/); ## skip empty lines
next if ($i =~ /^\\s*\\#/) ;
if( $i =~ /^$regexp/m ) {
$memd->set($listname,$i,$expire);
}
}
}
}
sub TraiteSpams {
my ($spool_dir) = @_;
unless (opendir(DIR, $spool_dir)) {
return undef;
}
my @qfile = sort grep (!/^\\.+$/,readdir(DIR));
closedir DIR;
foreach my $f (sort @qfile) {
my $message = new Message("$spool_dir/$f");
my $sender = $message->{'sender'};
if(defined $sender && "$sender" eq "$fromdouane") {
TraiteMessage($message);
}
}
}
&TraiteSpams("$spool/bad");

code de la classe C#

Code complet de la classe C# pour le traitement :


using Memcached.ClientLibrary;
using LumiSoft.Net.Mime;
public class DetectSpams : ITask
{
SockIOPool pool = null;
MemcachedClient mc = null;
Regex regex = new Regex("(http://.+[^\ ])",
RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.IgnoreCase);
DataTable dt;
DBContext CurrentContext;
string fromdouane = CcinetConfig.Application["emailDouane"];
bool debug = CcinetConfig.Application["debug"] == "true";
string sqldouane = "";
/// <summary>
/// Init DB Lyris
/// </summary>
private void initDb()
{
CurrentContext = new DBContext();
CurrentContext.InitConfig(CcinetConfig.Global, "DbConfigLyris");
// extraction de la requête à exécuter : retrouve les messages de notifications de quarantaine
XmlDocument xsql = new XmlDocument();
xsql.Load(CcinetConfig.Application["SQLdouane"]);
XmlNode sqln = xsql.SelectSingleNode("//SQLdouane");
sqldouane = string.Format(sqln.InnerText, DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, fromdouane);
}
/// <summary>
/// Init memcached
/// </summary>
private void initMemcached()
{
String[] serverlist = CcinetConfig.Application["memcachedServers"].Split(new char[] {';',',',' '});
pool = SockIOPool.GetInstance();
pool.SetServers(serverlist);
pool.InitConnections = 3;
pool.MinConnections = 3;
pool.MaxConnections = 5;
pool.SocketConnectTimeout = 1000;
pool.SocketTimeout = 3000;
// évite la maintenance des threads du pool : pb. pour la tâche lancée dans son propre thread
pool.MaintenanceSleep = 0;
pool.Failover = true;
pool.Nagle = false;
pool.Initialize();
mc = new MemcachedClient();
mc.EnableCompression = false;
mc.PrimitiveAsString = true;
}
private void shutdownMemcached()
{
SockIOPool.GetInstance().Shutdown();
}
private void getUrl(Stream msg)
{
Mime message = Mime.Parse(msg);
// traitement du message pour extraire l'URL puis sotckage dans le cache
if (message.MainEntity.From.Mailboxes.Length > 0 &&
message.MainEntity.From.Mailboxes[0].EmailAddress == fromdouane &&
message.MainEntity.To.Mailboxes.Length > 0)
{
string lstname = message.MainEntity.To.Mailboxes[0].EmailAddress.Split('@')[0];
foreach (MimeEntity mime in message.MimeEntities)
{
/// on prend uniquement le texte contenu dans la partie text/plain
if (mime.ContentType == MediaType_enum.Text_plain)
{
Match m = regex.Match(mime.DataText);
if (m.Success)
mc.Set(lstname, m.Value, DateTime.Now.AddHours(double.Parse(CcinetConfig.Application["expireHours"])));
}
}
}
}
/// <summary>
/// Transforme les \ en \ \ pour respect RFC 2822
/// </summary>
/// <param name="field"></param>
/// <returns></returns>
private string FoldField(string field)
{
string stmp = field.Replace("\ \ ", "\ ");
return stmp.Replace("\ ", "\ ").Replace("\ ", "\ \ ");
}
/// <summary>
/// Stream pour LumiSoft.Mime
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
private Stream getStream(string s)
{
byte[] b = Encoding.Default.GetBytes(s);
MemoryStream ms = new MemoryStream(b);
return (Stream)ms;
}

public void detectSpams()
{
initDb();
initMemcached();

try
{
CurrentContext.AddQueryResult(sqldouane, "NOTIFSSPAMS", true,false,true);
dt = CurrentContext.dataSet.Tables["NOTIFSSPAMS"];

// construction du message entêtes + corps
for (int i = 0; i < dt.Rows.Count; i++)
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("{0}\ \ \ \ ", FoldField((string)dt.Rows[i]["hdrall_"]));
sb.Append(FoldField((string)dt.Rows[i]["body_"]));

getUrl(getStream(sb.ToString()));
}
}
catch (Exception e)
{
LogManager.WriteLog("WebArcSvc", string.Format("DetectSpams : {0}\ {1}", e.Message, e.StackTrace), LogType.ERROR);
}

shutdownMemcached();
}

#region ITask Members

public void Execute(TaskCallback taskCallback, object[] args)
{
detectSpams();
}

#endregion
}

consommation des données dans le cache

Il reste à afficher ce que je souhaite sur le serveur Web, sur une page de gestion, le code pour afficher les données contenues dans le cache sur un “repeater” :


void AfficheNotifsSpams_PreRender(object sender, EventArgs e)
{
Hashtable ht = new Hashtable();
ListeDiffusionCollection lddcoll = ListeDiffusion.GetAllLists();
for (int i = 0; i < lddcoll.Count; i++)
{
string ldd = ((ListeDiffusion)lddcoll[i]).Libelle.ToLower();
string url = (string) mc.Get(ldd);
if (url != null &&
!ht.ContainsKey(ldd))
ht[ldd] = url;
}
rpNotifs.DataSource = ht;
rpNotifs.DataBind();
}

1 trouvés après des traitements dans des mails par un script Perl sous Debian et un service Windows C#

2 disponible aussi pour windows

Aidez l’Afrique en achetant un MP3 à 1 €

Posted by – July 15, 2007

Via Paypal, Sidamoursi vous propose d’écouter un MP3 au prix d’1 €. Ce don est pour aider la lutte contre le sida en Afrique alors faites comme moi, un petit geste pour une grande cause.

Source : Kick & Blog

Quelques mises à jour : DokuWiki, ASP.Net RssToolkit

Posted by – July 15, 2007

Une nouvelle release DokuWiki du 26 juin.

Parmi les nouveautés de cette version, le support d’OpenSearch (utilisé par blogasty par exemple). FireFox, Flock ou IE 7 détecteront le lien de recherche Opensearch automatiquement.

Le changelog et la liste des fonctionnalités de DokuWiki. Nous l’utilisons pour l’équipe d’ingénierie, c’est un outil très pratique pour écrire de la documentation en mode collaboratif. Parmi les fonctionnalités, celle qui me plait le plus : pas de base de données nécessaire.

La librairie RSSToolKit vient d’arriver à sa version 2.0. Pour les développeurs ASP.Net / C# qui ont à gérer la syndication RSS ou Atom dans le monde .Net.

Comment ça marche mon réseau ?

Posted by – July 11, 2007

Cela fait suite à l’article VServer : une mise en place sous Debian. Il est toujours intéressant de schématiser les écrits, cela résume bien l’architecture générale mise en place.

Architecture od’s home

Avec une seule IP (fixe), c’est toujours amusant de voir ce que l’on arrive à faire :

Les avantages de son hébergement :

  • liberté de mettre en place ce que l’on souhaite
  • et de sa gestion
  • économie d’un hébergement

Les défauts de s’héberger :

  • upload faible : 75 ko/s 100 ko/s, il peut donc y avoir des ralentissements pour les visites
  • pas à l’abri d’une panne du fournisseur d’accès
  • ni d’un changement de l’IP [EDIT] sous free dégroupé, l’IP est fixe
  • l’infrastructure n’est pas optimum : onduleurs, sauvegardes, etc, etc.

JAlbum 7.2

Posted by – July 9, 2007

Une nouvelle version de JAlbum vient de sortir. JAlbum est un logiciel qui permet de créer des albums Web photos d’une grande qualité avec une interface intuitive et ergonomique.

Du fun : suivre en direct sur Google maps les téléchargements de JAlbum.