L’insieme cellulare di Conway è servito: un programma educativo alla scoperta del gioco della vita

Dopo aver spiegato le regole su cui si basa il gioco della vita di Conway e più in generale degli insiemi cellulari a due dimensioni, vi presento una sua implementazione software, open-source e gratuita, sviluppato in C# (WPF .NET Framework 4). Di seguito un video con le principali funzionalità e caratteristiche:

E’ possibile impostare la regola S/B (Survivor / Born), la dimensione dell’insieme, il numero di stati e i relativi colori. E’ possibile variare il modello di rendering dei singoli automi (punti, palle, quadrati) e variarne la dimensione. Impostare una condizione iniziale in qualsiasi momento, disegnando direttamente all’interno dell’insieme. Esportare in vari formati: gif animata, PNGs, video Avi. Possibilità di importare modelli codificati nel formato RLE, e salvarli in locale utilizzando un formato proprietario.

Qui un paio di gif animate di esempio su cosa si può ottenere con il programma:
Gioco della Vita Regola S012345689/B3
Regola S012345689/B3

Gioco della Vita Regola S1234/B3
Regola S1234/B3

cudumar-xmpp festeggia il primo commit su google code

Abbiamo già parlato del client cudumar-xmpp usato per accedere a reti che adottano lo standard XMPP.

Stamattina apro la mia web-mail e PUM dritto in un occhio leggo il messaggio da parte del team del super cetriolo: “oggi festeggiamo il nostro primo commit su google code, un traguardo da festeggiare con capriole e succo di cetriolo!”.

cudumar-xmpp src google code

In pratica si tratta del codice sorgente della pre-release 0.0.4, un’anteprima sfiziosa per tutti i ghiottoni di nuove tecnologie. WPF, .Net Framework 4 e XMPP = leggerezza e semplicità. Qui la pagina dove è possibile scaricare i sorgenti, utilizzando il vostro VCS preferito. Il team di cudumar-xmpp utilizza TortoiseHg, una GUI basata su Mercurial.

L’insieme cellulare di Wolfram è servito: un programma educativo alla scoperta degli automi cellulari unidimensionali

Dopo i recenti articoli pubblicati Rendering grafico in GDI e WPF e Calcolo parallelo applicato agli automi cellulari ecco un video dimostrativo sul mondo cellulare di Wolfram.

Scritto in C# WPF (.NET Framework 4) e compilato con Visual Studio 2010, il codice sorgente e l’eseguibile sono scaricabili dalla pagina cellular-automata-world ospitata su google code.

Danimarca in solitario

Partenza
Stazione dei treni di Pordenone, 7 agosto 2010, tardo pomeriggio.

Verona
Che bello aspettare il treno fino all’una di notte! Pieno di tedeschi e austriaci ricolmi di gioiosi ricordi veneziani e scottature farcite di sudore.

Monaco
Che bello l’arrivo a monaco, la notte passata insonne rigorosamente su sedili intercity italiani. Non erano i sedili, era l’adrenalina dai, per il viaggio, no? Zainetto in spalla, minimale, senza grandi pretese, due braghe, qualche maglietta, un paio di felpette, una giacca militare del signor cocco immanicato nell’esercito che gentilmente mi ha offerto come piccolo conforto di viaggio. Aspettando scalpitante l’alba, finalmente arriva soffusa e vivace, illuminando le vallate. Colori: nebbia e rosa.

Amburgo
Amburgo-Monaco in mattinata, che bello ho tutto il pomeriggio per visitare Amburgo, che bella, dall’alto, il porto. Che bello, una festa tipo gaypride, che bello, musica tecno wow, la mia preferita (ironico).

Copenaghen
Qui non mi fermo, non voglio perdere altro tempo, la notte passa lenta e inesorabile su questo treno. Un po’ in corridoio, in mezzo a vera gente danese, divertente notare che qui non dorme mai nessuno in treno, a parte qualche cinese o turista sperduto. Non esistono treni notturni in Danimarca, e la gente sembra essersene fatta una ragione di viaggio.

Hoje Taastrup
Cambio treno alle tre di notte, sosta di un’ora scarsa per sondare il vicinato. Carino, buio, quasi accogliente. Nonostante l’ora, numerose sono le persone che attendono il treno diretto verso nord.

Lindholm
Come dimenticare questa graziosa cittadina. Piccola e armoniosa sosta alle sei di mattina, in attesa di cambio treno. Dopo una tirata da Copenaghen, dopo un po’, magari si ha desiderio di sgranchirsi le gambe. Il corridoio del treno non era molto simpatico, devo ammettere. Colgo l’occasione per cambiare un po’ di corone danesi, dato che ne ero sprovvisto. Occhio però a non farsi mangiare la carta di credito dallo sportello, mi raccomando attenzione. Ok? (fesso)
La cittadina si presenta asettica, senza un vero e proprio centro città. Usciti dalla semplice stazione a banchine, si incontrano casermoni simili universitari: grandi vetrate che lasciano curiosare scorci di vita quotidiana.

Aalborg
Aalborg mi è proprio piaciuta, cittadina tranquilla ma con un certo cravattino annodato bene. Strade ben curate e poca gente in giro. Odore di gabbiani e sapore di mare.

Hjorring
Hjorring. Che bello. Qui si inizia ad assaporare la vita ai confini del mondo. Ogni nazione ha un proprio confine del mondo. Dove la gente si fa più bitorzoluta, il tempo rallenta, la mente si distende.

Hirtshals
Che meraviglia la natura. Scogliere vive, dune, spiagge affacciate sul mare freddo del nord. Giornate indimenticabili. Qui partono i traghetti per la Norvegia e per l’Islanda (pensierino?). Qui mi fermo tre notti. Ne avevo preventivate due ma è un luogo troppo fuori dal mondo per restare così poco. Soggiorno nell’ostello cittadino Danhostel Hirtshals affacciato sulla scogliera. Poco frequentato, costo irrisorio, ben gestito. Cucinino invitante ed accogliente, gente simpatica.
Noleggio una bici e scopro l’allegro sistema di frenata danese: il freno si aziona pedalando all’indietro, e non agendo manualmente su manopole come siamo abituati qui in Italia. Qui nolleggiare una bicicletta per un giorno costa veramente una misera. Assaporare l’atmosfera pacata e soffice del tramonto in sella non ha prezzo. Inoltrarsi nella periferia, raggiungere gli anfratti più isolati, le dune più tartassate dal vento non ha davvero prezzo.
Simpatica l’invasione di coccinelle in tutto il nord del paese, qui mi sollazzo ampiamente, nell’inevitabile calpestio di putride coccinelle sociali lungo la scogliera cittadina.

Skagen
Graziosa cittadina turistica, animata da una forte corrente di artisti nata all’inizio dell’800. Il secondo polo turistico dopo Copenaghen. Un po’ troppo affollata per i miei gusti. Bellissimo il territorio circostante. Il panorama è per chi c’è.
Molto grande l’ostello, ma troppo affollato, mi ci fermo due notti. Vi do un consiglio: noleggiate una bici in centro a Skagen, dirigetevi in direzione Grenen.
Lungo la strada ciclabile fermatevi ad esplorare due fari: Det Hvide Fyr e Skagen Fyr. Inoltratevi nelle stradine di sabbia laterali. Dopo tre chilometri arriverete in un piazzale dove lasciare la bici e procedere a piedi. Qui inizia il lembo di sabbia chiamato Grenen!

 

skagen grenen

Questi due tizi avevano portato una sedia sulla spiaggia di Grenen, vai tu a sapere perchè? 😀 senzamotivo!


Skagen, Grenen
Troppo poetico questo punto. Da segnare nel proprio taccuino tascabile, o nel proprio atlante da camera. Qui si incontrano il mare del nord e il mar baltico, in una graziosa danza di onde rifrangenti. Navi cargo crescono sul filo dell’orizzonte.

Skagen, Damstedvej
Credo il punto più bello di tutta la Danimarca, che mi è capitato di vedere. Si scalano dune alte parecchie dozzine di metri, imponenti sul mare. Dietro, la cittadina di Skagen, colorata e ordinata. Dovunquealtro una distesa infinita di territorio dunesco, arbusti, pini… meravoglioso, imponente.

Frederikshavn
Da non trascurare la spiaggetta con le palme. Ci do solo uno sguardo veloce, e risalgo sul prossimo treno verso sud.

Fredericia
La stanchezza inizia a farsi sentire… mi faccio un giro a Fredericia, che sembra un nome un po’ da cane. Qui ritrovo le coccinelle, e chissà perchè tutti mi vedono curiosi con uno zaino sulle spalle. Girano pochi turisti evidentemente.

Kolding
Mmm entriamo in stazione, chissà che possibilità mi offre la gioiosa compagnia rotabile danese: 1. Amburgo, 2. Amsterdam. Assolutamente Amsterdam. Nel pomeriggio giro per la città, interessante. Una vecchina mi intima ad entrar in casa, mi chiama dalla strada con uno schiamazzo daneseggiante. Non capisco una cippa ma entro ugualmente, lascio la mia roba all’ingresso (mi deruberà?), la seguo su in cucina, e la povera vecchina, mimando, mi mostra un gesto dalla dubbia interpretazione, ok come quello di quando si cambia una lampadina. Ok salgo su nel tavolo, svito e sostituisco. La vecchina ringrazia, ma senza ricompensa. Nell’arrivar della sera inizia a far freddino e mi rintano in stazione. Qui treni frequenti per Esbjer. Mi viene voglia di farci una visitina ma ormai la prenotazione era stata fatta. Mi abbuffo di banane. Avevo spiccioli danesi da finire, prima di lasciare il paese. Si parte con il buio.

Colonia
Sono tre volte nella mia vita che passo in treno per questa città, tutte e tre le volte di mattina presto, verso la conclusione di una lunga tratta notturna. Tutte e tre le volte avvolta da una leggera nebbia, grigia, grandi e imponenti cattedrali che si impongono sullo skyline, nere di inquinamento. Maledettamente affascinante.

Utrecht
Notte rigorosamente su sedile passeggero. Accompagnato da tipico padre danese festaiolo e figlia sedicenne un po’ contadina: vino a volontà. Qui non si scende, dritti verso Amsterdam.

Amsterdam
Che bordello. Una notte è sufficiente.

Parigi
Bella no? Mi piace 🙂 Ahhhhhh un po’ di atmosfera metropolitana ci vuole dopo tutto questo girar per campi!

Provenza
La provenza. Che bel paesaggio si vede dal treno. Passare in un paio di giorni dal brullo e fresco-ventoso nord della Danimarca all’afoso sud francese fa il suo effetto. Il rosso della terra contrasta piacevolmente con l’azzurro del mare.

Nizza
Qui arrivo di mattina, sul presto. L’aria condizionata non mi lascia scampo: mal di gola e febbre per oggi.

Ventimiglia
Prima di prendere il treno che mi riporterà ufficialmente in territorio italiano, c’è il tempo per una rotolata in spiaggia.

XMPP disco#info from server messenger.live.com, chat.facebook.com, google.com

xmpp stream xml viewer

Utile analizzatore di stream xml integrato nel programma cudumar-xmpp, permette di osservare lo scambio di pacchetti tra client e server.

Tanto per gustarci un po’ di cose “tricky” sui vari server e servizi XMPP diffusi ultimamente nella rete, qui una lista di risposte disco#info (XEP-0030: Service Discovery) aggiornate al 6 giugno 2012:

messenger.live.com

<iq from="messenger.live.com" id="3" to="xxx@messenger.live.com/{af7ed31f-5f9b-4198-b745-ae613ce63c2a}" type="result">
  <query xmlns="http://jabber.org/protocol/disco#info">
    <identity category="server" type="im" />
    <feature var="http://jabber.org/protocol/disco#info" />
    <feature var="vcard-temp" />
    <feature var="urn:xmpp:ping" />
    <feature var="jabber:iq:roster" />
    <feature var="http://messenger.live.com/xmpp/jidlookup" />
    <feature var="urn:xmpp:archive:auto" />
  </query>
</iq>

chat.facebook.com

<iq from="chat.facebook.com" to="xxx@chat.facebook.com/cudumar-xmpp_a389d347_4C1CCC07E13F9" id="3" type="result">
  <query xmlns="http://jabber.org/protocol/disco#info">
    <identity category="server" type="im" name="Facebook Jabber" />
    <feature var="http://jabber.org/protocol/commands" />
  </query>
</iq>

google.com (gtalk)

<iq to="xxx@gmail.com/cudumar-xmA4CD5484" from="xxx@gmail.com" id="3" type="result">
  <query xmlns="http://jabber.org/protocol/disco#info">
    <identity category="account" type="registered" name="Google Talk User Account" />
    <feature var="http://jabber.org/protocol/disco#info" />
    <feature var="http://jabber.org/protocol/disco#items" />
    <feature var="msgoffline" />
  </query>
</iq>

 
Il server GTalk di google non supporta query disco#info client-to-server (restituisce ), ma solo client-to-client.

Facebook invece viceversa, supporta solo richieste disco#info client-to-server.

Windows Live Messenger invece supporta correttamente richieste client-to-server. Nel caso di richieste client-to-client il server restituisce una risposta standard dal dubbio significato e dalla dubbia utilità:

<iq from="messenger.live.com" id="5" to="xxx@messenger.live.com/{2ddd7d77-0687-49ba-a6c4-efe52ad54b34}" type="result">
  <query xmlns="http://jabber.org/protocol/disco#info">
    <identity category="account" type="registered" />
    <feature var="http://jabber.org/protocol/disco#info" />
    <feature var="http://jabber.org/protocol/chatstates" />
  </query>
</iq>

Facebook chat XMPP vCard issue

E’ proprio bello quando capisci che gli standard aperti e gratuiti possiedono enormi potenzialità, peccato che servizi come Facebook e MSN Messenger facciano un uso non proprio corretto nelle loro implementazioni.

Devo ancora capire perchè il server XMPP di facebook (chat.facebook.com:5222) si emozioni così tanto da non rispondermi più, appena gli inoltro una semplicissima e banalissima richiesta per ottenere la propria vCard personale. Tutto conforme alle specifiche XEP-0054 (vcard-temp):

<iq id="5" type="get">
  <vCard xmlns="vcard-temp" />
</iq>

Qualcuno ha una anche banale ma simpatica idea per risolvere il problema?

Come renderizzare automi cellulari a due dimensioni con GDI e WPF

Ok, noi abbiamo il nostro automa cellulare bidimensionale, un divertente gioco della vita interattivo implementato in C# / WPF. Vediamo come estendere il rendering grafico ad armoniose e più interessanti varianti. Definiamo prima di tutto l’interfaccia IRender:

public interface IRender {
  int CellSize { get; set; }
  void SetColorPalette(IList<System.Drawing.SolidBrush> colorsPalette);
  void SetColorPalette(IList<System.Windows.Media.Color> colorsPalette);
  System.Windows.Controls.Image Render(byte[] buf, int width, int height);
}

 
Il rendering base, basato cioè sulla corrispondenza “cella” -> “1×1 pixel su schermo” viene implementato agevolmente utilizzando BitmapImage.Create():

class RenderBase : IRender {
  public int CellSize { get { return 1; } set { } }
  private BitmapPalette Palette = BitmapPalettes.BlackAndWhite;
  public void SetColorPalette(IList<System.Drawing.SolidBrush> colorsPalette) {
    Palette = new BitmapPalette(ImageUtils.ConvertPaletteInMediaColor(colorsPalette));
  }
  public void SetColorPalette(IList<System.Windows.Media.Color> colorsPalette) {
    Palette = new BitmapPalette(colorsPalette);
  }

  public System.Windows.Controls.Image Render(byte[] buf, int width, int height) {
    const double dpi = 96;
    return new Image() {
      Source = BitmapImage.Create((int)width, (int)height, dpi, dpi,
        PixelFormats.Indexed8, Palette, buf, (int)width)
    };
  }
  public override string ToString() {
    return "1x1 Pixel (fastest)";
  }
}

 
Per ottenere diversi render più complessi, basati sulla forma della singola cella e relativamente al bordo della stessa, creiamo una classe astratta RenderGraphics che utilizza le librerie grafiche GDI+ per il disegno delle singole celle e la composizione dell’ambiente.

abstract class RenderGraphics : IRender {
  public int CellSize { get; set; }
  protected IList<System.Drawing.SolidBrush> Palette { get; private set; }

  public void SetColorPalette(IList<System.Drawing.SolidBrush> colorsPalette) {
    foreach (System.Drawing.SolidBrush brush in Palette)
      brush.Dispose();
    Palette = colorsPalette;
  }
  public void SetColorPalette(IList<System.Windows.Media.Color> colorsPalette) {
    Palette = ImageUtils.ConvertPaletteInDrawingBrush(colorsPalette);
  }

  public System.Windows.Controls.Image Render(byte[] buf, int width, int height) {
    using (Bitmap b = new Bitmap(width * CellSize, height * CellSize)) {
      using (Graphics g = Graphics.FromImage(b)) {
        g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.None;
        g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
        g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
        g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighSpeed;
        for (int i = 0; i < width * height; i++) {
          int x = (int)(i % width);
          int y = (int)(i / width);
          Draw(g, Palette[buf[i]], x, y);
        }
      }

      return ImageUtils.ConvertToWpfImage(b);
    }
  }

  protected abstract void Draw(Graphics g, System.Drawing.SolidBrush brush, int x, int y);
}

 
I diversi rendering grafici si ottengono estendendo RenderGraphics e implementando il metodo Draw():

class RenderFilledRects : RenderGraphics {
  public override string ToString() { return "Filled Rects without border"; }
  protected override void Draw(Graphics g, System.Drawing.SolidBrush brush, int x, int y) {
    g.FillRectangle(brush, x + (CellSize - 1) * x, y + (CellSize - 1) * y, CellSize, CellSize);
  }
}
class RenderFilledRectsBorder : RenderGraphics {
  public override string ToString() {	return "Filled Rects with border"; }
  protected override void Draw(Graphics g, System.Drawing.SolidBrush brush, int x, int y) {
    g.FillRectangle(brush, x + (CellSize - 1) * x, y + (CellSize - 1) * y, CellSize - 1, CellSize - 1);
  }
}
class RenderFilledDots : RenderGraphics {
  public override string ToString() { return "Filled Dots without border"; }
  protected override void Draw(Graphics g, SolidBrush brush, int x, int y) {
    g.FillEllipse(brush, x + (CellSize-1) * x, y + (CellSize-1) * y, CellSize+1, CellSize+1);
  }
}
class RenderFilledDotsBorder : RenderGraphics {
  public override string ToString() { return "Filled Dots with border"; }
  protected override void Draw(Graphics g, SolidBrush brush, int x, int y) {
    g.FillEllipse(brush, x + (CellSize - 1) * x, y + (CellSize - 1) * y, CellSize-1, CellSize-1);
  }		
}
class RenderEmptyDots : RenderGraphics {
  public override string ToString() { return "Empty Dots"; }
  protected override void Draw(Graphics g, SolidBrush brush, int x, int y) {
    g.DrawEllipse(new Pen(brush, 1), x + (CellSize - 1) * x, y + (CellSize - 1) * y, CellSize - 2, CellSize - 2);
  }		
}
class RenderEmptyRects : RenderGraphics {
  public override string ToString() { return "Empty Rects"; }
  protected override void Draw(Graphics g, SolidBrush brush, int x, int y) {
    g.DrawRectangle(new Pen(brush, 1), x + (CellSize - 1) * x, y + (CellSize - 1) * y, CellSize - 2, CellSize - 2);
  }
}
game of life animated gif

Gioco della vita renderizzato a cubetti

Lo sviluppo del cudumar friulano procede spedito verso il successo!

Sono diversi mesi che seguiamo un progetto davvero interessante: cudumar-xmpp. Si tratta di un client XMPP gratuito, innovativo per la sua leggerezza e usabilità.
Nato in terra friulana da un anno e qualche mese, già si è inserito di gran prepotenza tra i client più utilizzati ed apprezzati.
Dopo una prima intervista di qualche mese fa, siamo di nuovo qui a dare la voce ad uno degli ideatori nonchè sviluppatori del progetto, in previsione dell’imminente rilascio della nuova versione del client:

Abbiamo lavorato moltissimo al supporto dello standard vCard, in modo tale da ottene informazioni sempre aggiornate dai propri contatti, visualizzarne avatar personali e impostandone di propri.

– commenta Daniele Tenero.

cudumar xmpp source code

cudumar-xmpp è sviluppato in WPF, C# .Net Framework 4

Il lavoro è stato svolto nel rispetto dei notri tre principi: leggerezza, stabilità, usabilità. Attualmente siamo in fase di test, abbiamo pianificato l’uscita della nuova release stabile a fine giugno 2012, vi terremo aggiornati!

xmpp sasl mechanisms source code

cudumar-xmpp supporta la maggior parte dei sistemi di autenticazione SASL utilizzati attualmente: ANONYMOUS, PLAIN, DIGEST-MD5, X-GOOGLE-TOKEN, X-OAUTH2, X-MESSENGER-OAUTH2, X-FACEBOOK-PLATFORM

Un’altra importante novità riguarda il supporto di nuovi meccanismi di autenticazione, per citarne alcuni: X-GOOGLE-TOKEN, X-OAUTH2, X-MESSENGER-OAUTH2. Soprattutto l’ultimo, il quale permette l’accesso al network MSN (Live Messenger) di Microsoft. In questo modo sarà possibile connettersi ad MSN anche senza il pesante e variopinto Windows Live Messenger.

Bellissima questa ultima notizia, è davvero emozionante che anche Microsoft si sia aperta a standard liberi come XMPP e che giovani friulani subito raccolgano questa opportunità per aprire nuovi orizzonti al proprio progetto.

Per finire, abbiamo l’onore di pubblicare in anteprima il changelog della prossima versione che verrà rilasciata il prossimo mese:
cudumar-xmpp changelog v0.0.3 #
- disco#info support (XEP-0030: Service Discovery)
- caps support (XEP-0115: Entity Capabilities)
- vcard-temp (XEP-0054: vcard-temp)
- vcard-temp:x:update (XEP-0153: vCard-Based Avatars)
- SASL X-GOOGLE-TOKEN authentication supported
- SASL X-MESSENGER-OAUTH2 authentication supported
- urn:xmpp:ping support (XEP-0199: XMPP Ping)

Da questa pagina ospitata su google code è possibile scaricare l’ultima versione e i “source code” del progetto: download cudumar-xmpp.

Calcolo parallelo applicato agli automi cellulari

Un piccolo esempio per tastare la praticità e l’eleganza delle nuove funzionalità di calcolo parallelo introdotte dal .NET Framework 4. La classe Parallel fornisce semplicemente e senza tante complicazioni metodi statici che permettono di sfruttare al meglio l’archittettura multicore in cui viene eseguita l’applicazione. Vediamo un esempio applicato agli automi cellulari, più precisamente al gioco della vita:

public override bool Next() {
  GenerationCount++;
  Environment2D etmp = new Environment2D(Env.Width, Env.Height);
  Parallel.For(0, Env.Width, x => {
    Parallel.For(0, Env.Height, y => {
      etmp.SetValue(x, y, ComputeRule(x, y));
    });
  });
  Env = etmp;
  return true;
}		

dove Next() calcola la nuova generazione dell’automa, computando per ogni cella dell’ambiente il nuovo valore, che come tutti sapranno, dipende dallo stato delle celle dell’intorno.

Vediamo ora la versione non parallela, formata semplicemente da due cicli for annidati, che spazzano in sequenza le celle dell’ambiente.

public override bool Next() {
  GenerationCount++;
  Environment2D etmp = new Environment2D(Env.Width, Env.Height);
  for (int x = 0; x < Env.Width; x++)
    for (int y = 0; y < Env.Height; y++)
      etmp.SetValue(x, y, ComputeRule(x, y));
  Env = etmp;
  return true;
}				

Simpatico e divertente, non come implementare una logica basata su thread che poi chissà cosa ti combinano questi furbi e malandrini thread 😦 bella questa classe System.Threading.Tasks.Parallel!

Per la cronaca, su un Intel Core2 Quad Q6600 (2,40Ghz) con quattro core separati e RAM da 3Gb, il mio algoritmo risulta tre volte più veloce!

Dei ragazzi di Udine e Pordenone suonano gli Opeth!

Sono forti questi ragazzi! I Mirror Ghost, friulani Doc, sono di fatto la prima Opeth Tribute Band di Italia. Dal 2009 hanno intrapreso un meraviglioso tributo agli Opeth, band scandinava progressive folk death metal. Un progetto decisamente interessante, data la complessità delle canzoni come The Drapery Falls, o Bleak, o la graziosa Face of Melinda o ancora la rugosa Ghost of Perdition.

Qui il myspace dei Mirror Ghost, e la pagina facebook.