He començat aquesta sèrie de llibres del Robert Jordan desprès de trobar-ne alguna recomanació pels Internetes. I aquest no és el primer, és una preqüela. Es a dir, el Robert Jordan va escriure uns quants llibres, i desprès va escriure aquest com l'inici de tot plegat. Va sortir publicat entre el llibre 8 i el 9.
Aquest autor, Robert Jordan, va morir el 2007 abans de finalitzar la seva sèrie, però com va deixar unes notes de com acabaria aleshores Brandon Sanderson, un altra autor conegut de llibres de fantasia, va escriure els 3 últims.
[Spoilers] El llibre tracta de com es coneixen la Moraine Dramored i el Lan Mandragoran. Descriu lentament i detalladament el món on es desenvolupa l'acció. Hi ha una mena de monges que fan màgia anomenades Aes Sedai, i la Moraine pasa de ser una novicia a fer la prova d'accés i convertir-se en maga.
Els homes no poden fer màgia, i descriu el Lan en una batalleta i després com l'hereu i rei d'un regne perdut a mans del mal.
El llibre parla de la profecia on hi haurà un home, the Dragon reborn, capaç de fer màgia i que portarà la guerra i la fi del món. Per això la Moraine surt a buscar-lo per tal de conduir-lo pel bon camí. I ensopega amb el Lan que es convertirà amb el seu Warder o guardià, després d'uns quants tira i afluixa.[/Spoilers]
El llibre és tranquil, sense gaire acció. Molt descriptiu, fins al punt que a vegades no saps ben bé que està descrivint. Com no enganxa gaire i és molt reposat he llegit poc a poc, però ja va bé un llibre així de tant en tant, a més aquest és agradable, encara que reconec que per algú altra pot arribar a ser avorrit. A mi m'ha agradat, ara vaig a pel següent.
Ahir vaig anar a veure aquesta pelic de super herois. Mmmmm... Es deixa veure i distreu, però (sempre hi ha un però) té un algo que... no se, ni fu, ni fa, ni bona ni dolenta. Però clar, ja hem va distreure que és el que ha de fer. És d'aquelles pelis que dius és dolenta? No. És bona? No. Aaaaahhh... ja començo a trobar el que li falla, el dolent. No és un dolent creïble ni que faci por la seva maldad.
[Spoilers] Un meteorit de vibranium cau a Africa i permet que unes tribus evolucionin tecnològicament un munt, fent un país que es diu "Wakanda". Es mantenen ocults per no compartir el seu vibranium amb el món i que ningú en faci un mal ús. Així el món no té vibranium excepte que el que té el Capità Amèrica. Després de la mort del rei, el seu fill després d'un combat ritual es coronat.
Però resulta que hi ha un dolent que va posar la bomba del rei, i va robar vibranium i a més a més el rei vell, quan era jove, va matar al seu germà que vivia en un ghetto dels USA i va deixar el fill orfe a la seva sort.
Aquest fill orfe torna per reclamar el tron, i fa un combat ritual que guanya. El rei jove i bo casi mor però el salven i torna, lluita amb el dolent i guanya. I el rei bo decideix millorar el món compartint el vibranium. (es que passen més coses però fa mandra escriure-les i he resumit a sac).[/Spoilers]
Bons efectes, guió pse-pse, dolent pse-pse, peli ni fu ni fa. Però distreu. Thor: Ragnarok molt millor.
No tinc una Raspberry, però m'agradaria. És molt bufona i barateta, 35 USD. El cas és que no se que en faria, o que hi podria programar o d'on trauria el temps per dedicar-hi. Hi ha tantes coses boniques per jugar i per fer, i jo amb tan poc temps, ainsssss. Però sempre és maco veure coses xulis que van evolucionant. Hauré de pensar algo que fer amb aquestes coses pels peques. Doncs bé ha sortit la Raspberry Pi 3 B+ que incorpora força millores mantenint el preu.
Segueixo pulint el tema del programa que controla el bit-rotting i la coherència de la còpia de seguretat. Tinc una tasca que triga força en executar-se i per no deixar l'interface d'usuari sense activitat (que et sorgeix el dubte... s'ha penjat o està fent algo?) aleshores millor mostrar un percentatge de progres.
El procés s'executa en un thread diferent del de l'interface d'usuari i consisteix en un bucle que executa consultes contra la BBDD. Es sap quantes consultes cal fer i dins del bucle que les fa es sap quantes en portes. Aleshores hi ha l'opció de calcular el percentatge a cada volta de bucle, però això és fer el càlcul massa sovint, també vaig fer l'opció de calcular cada "n" voltes de bucle però això depèn de si hi ha moltes consultes o poques. Aquestes dues opcions no em van agradar, jo volia que cada cert temps em digui el progres i aleshores vaig pensar en un timer. Cada n segons, 5 per exemple, que em digui que tal va.
I clar, com es posa un timer en un thread en C#? El cert és que m'ha resultat més fàcil del que hem pensava. Això de programar per que et ve degust està molt bé, perquè fas el que vols amb el temps que vols, es a dir fins que et canses. Podria haver estat un problema més difícil i tindria que haver dedicat més temps, però no, fàcil, fàcil. D'aquí poc com l'Arguiñano, rico, rico :D
Cal posar el using dels Timers, les variables globals que gestionen el càlcul del progres, la variable del Timer, inicialitzar-ho tot plegat, i fer la rutineta que fa el càlcul (UpdateProgress) i presto! Un Timer. No està de més, en catch de quan el Thread està sent abortat aturar el timer.
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
namespace Dir
{
class clsBuscaRepes
{
public frmInterface Interface = null;
publicdecimal TantPerCentProgress = 0;
privateint Progress = 0;
privateint Total = 0;
private System.Timers.Timer Tmr = new System.Timers.Timer();
publicvoid BuscaRepes()
{
try
{
clsConfig Config = new clsConfig();
string SQL = "";
DataTable TBLParaules, TBLDuplicats, TBLFitxer, TBLVerificats;
string CadConn = "";
bool UseBBDD = false;
bool Primer = true;
SqlConnection Conn = null;
string IdFitxerActual = "", IdFitxerAnterior = "";
int NumRepes = 0;
string HashActual = "";
string HashAnterior = "";
clsSQLServer SQLSvr = new clsSQLServer();
Tmr.Interval = 1000;
Tmr.Elapsed += new ElapsedEventHandler(UpdateProgress);
Config.Initialize();
UseBBDD = bool.Parse(Config.GetVal("UseBBDD"));
Interface.Log("Començant buscar fitxers repetits");
if (UseBBDD)
{
Conn = newSqlConnection();
CadConn = Config.GetVal("CadConn");
Conn.ConnectionString = CadConn;
Conn.Open();
Interface.Log("Conectat a BBDD: " + Conn.DataSource);
SQLSvr.CadConn = CadConn;
SQLSvr.Conn = Conn;
Progress = 0;
Total = 0;
SQL = "DELETE FROM ResultatsDuplicats";
SQLSvr.ExecNonQuery(SQL);
Interface.Log("Iniciant duplicats per hash");
SQL = "SELECT * FROM Fitxers WHERE Hash IN(SELECT Hash FROM fitxers "
SQL += "GROUP BY Hash HAVING ( COUNT(Hash) > 1 )) ORDER BY Hash";
TBLDuplicats = SQLSvr.Exec(SQL);
foreach (DataRow DR in TBLDuplicats.Rows)
{
HashActual = DR["Hash"].ToString();
if (HashActual == HashAnterior)
{
IdFitxerActual = DR["IdFitxer"].ToString();
SQL = "SELECT * FROM Verificats WHERE IdFitxer=" + IdFitxerAnterior + " ";
SQL += "AND IdFitxerVerificat=" + IdFitxerActual;
TBLVerificats = SQLSvr.Exec(SQL);
if (TBLVerificats.Rows.Count == 0)
{
SQL = "SELECT * FROM Fitxers WHERE IdFitxer=" + IdFitxerAnterior;
TBLFitxer = SQLSvr.Exec(SQL);
Interface.Log("Duplicat, fitxer actual: " + TBLFitxer.Rows[0]["IdFitxer"].ToString());
Interface.Log(", " + TBLFitxer.Rows[0]["Nom"].ToString());
Interface.Log("Duplicat: " + DR["IdFitxer"].ToString() + ", " + DR["Nom"].ToString());
Interface.Log("--------------------------------------------------");
SQL = "INSERT INTO ResultatsDuplicats (IdFitxer, IdFitxerPossibleDuplicat) "
SQL += "VALUES (" + IdFitxerAnterior + ", " + DR["IdFitxer"].ToString() + ");";
SQLSvr.ExecNonQuery(SQL);
NumRepes++;
}
}
else
{
HashAnterior = HashActual;
IdFitxerAnterior = DR["IdFitxer"].ToString();
}
}
SQL = "SELECT Paraula, IdFitxer FROM Paraules ORDER BY IdFitxer";
TBLParaules = SQLSvr.Exec(SQL);
SQL = "";
IdFitxerAnterior = "";
IdFitxerActual = "";
Total = TBLParaules.Rows.Count;
//Començar el timer
Tmr.Start();
foreach (DataRow Paraula in TBLParaules.Rows)
{
IdFitxerActual = Paraula["IdFitxer"].ToString();
if (IdFitxerActual == IdFitxerAnterior || Primer)
{
SQL += " AND Nom LIKE '%" + Paraula["Paraula"].ToString().Replace("'", "''") + "%'";
if (Primer)
{
Primer = false;
IdFitxerAnterior = IdFitxerActual;
}
}
else
{
SQL = "SELECT * FROM Fitxers WHERE IdCarpeta IN ";
SQL += "(SELECT IdCarpeta FROM Carpetes WHERE Duplicats=1) ";
SQL += "AND IdFitxer<>" + IdFitxerAnterior + " " + SQL;
TBLDuplicats = SQLSvr.Exec(SQL);
foreach (DataRow Duplicat in TBLDuplicats.Rows)
{
SQL = "SELECT * FROM Verificats ";
SQL += " WHERE IdFitxer=" + IdFitxerAnterior + " ";
SQL += "AND IdFitxerVerificat=" + Duplicat["IdFitxer"].ToString();
TBLVerificats = SQLSvr.Exec(SQL);
if (TBLVerificats.Rows.Count == 0)
{
SQL = "SELECT * FROM Fitxers WHERE IdFitxer=" + IdFitxerAnterior;
TBLFitxer = SQLSvr.Exec(SQL);
Interface.Log("Duplicat, fitxer actual: " + TBLFitxer.Rows[0]["IdFitxer"].ToString());
Interface.Log(", " + TBLFitxer.Rows[0]["Nom"].ToString());
Interface.Log("Duplicat: " + Duplicat["IdFitxer"].ToString() + ", " + Duplicat["Nom"].ToString());
Interface.Log("--------------------------------------------------");
SQL = "INSERT INTO ResultatsDuplicats (IdFitxer, IdFitxerPossibleDuplicat) "
SQL += " VALUES (" + IdFitxerAnterior + ", " + Duplicat["IdFitxer"].ToString() + ");";
SQLSvr.ExecNonQuery(SQL);
NumRepes++;
}
}
SQL = " AND Nom LIKE '%" + Paraula["Paraula"].ToString().Replace("'", "''") + "%'";
IdFitxerAnterior = IdFitxerActual;
}
Progress++;
}
}
Tmr.Stop();
Interface.Log("Total repetits: " + NumRepes);
Interface.BuscaRepesFinished();
}
catch (ThreadAbortException Ex)
{
if (Tmr.Enabled) Tmr.Stop();
}
catch(Exception Err)
{
Interface.Log("Error: " + Err.Message);
}
}
publicvoid UpdateProgress(object sender, System.Timers.ElapsedEventArgs e)
{
try
{
TantPerCentProgress = (decimal)(Progress * 100) / (decimal)Total;
Interface.Log("Processades " + TantPerCentProgress.ToString("N2") + "% de paraules");
}
catch(Exception Err)
{
}
}
}
}
#13/03/2018 18:35 Programació C# Autor: Alex Canalda
Depenent del projecte on estem a vegades no cal muntar classes d'accés a dades, capes i capes de software inútil per executar una mera consulta. També cal valorar la mantenibilitat, allò de que les capes afavoreixen el manteniment, jo sempre he trobat que entorpeixen el manteniment... Però sí que crec necessari que les consultes, encara que siguin un string en el codi, siguin gestionades de forma centralitzada. És en aquest punt quan va sorgir la clsSQLServer. D'això ja fa 5 o més anys... però no se per que no l'he posat al blog fins ara. Bé de fet, l'he ampliat fa pocs dies, portava des del 2013 sense modificacions.
Aquesta classe com el seu nom indica gestiona les consultes al servidor de base de dades. De fet no se com Microsoft no l'han fet ells mateixos. Vull dir que com programador el que vull és executar una sentència SQL i tenir una taula de retorn, sense preocupar-me de si és un Adapter o un Command o X, però bé, ja que MS no s'inspira ho fet jo. Té uns quants mètodes principals i sobrecarregats:
Exec: Executa un consulta SQL i retorna una taula. Es pot escollir entre no preocupar-se per la connexió, o sí, o afegir-hi una transacció.
ExecInsertWithIdentity: Executa un INSERT contra una taula que tingui una clau primària (PK) de tipus identitat. I un cop fet l'INSERT retorna el valor de la PK que ha creat com un long.
ExecNonQuery: Serveix per executar consultes que no retornen res, tipus UPDATEs, DELETEs o INSERTs que no cal recuperar la PK. Retorna els registres afectats per la consulta.
ExecScalar: Serveix per executar consultes que retornen un valor sencer, com un màxim, un mínim, un COUNT etc... De moment no m'ha fet falta un altra tipus de dada en el retorn.
FDateSQL: Aquesta és una utilitat per treballar amb dates en SQL Server. Retorna la data en un string en format ISO 8601: yyyy-mm-ddThh:mi:ss. Aquest format el bo que té és que no depèn dels regional settings.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data;
using System.IO;
using System.Configuration;
namespace Viewer
{
publicclass clsSQLServer
{
public clsSQLServer()
{
Conn = null;
}
publicSqlConnection Conn { get; set; }
privatestring _Ver = "07/03/2018";
publicstring Ver
{
get
{
return _Ver;
}
}
publicstring CadConn { get; set; }
publicstring FDateSQL(DateTime D)
{
//ISO 8601: yyyy-mm-ddThh:mi:ssreturn D.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss");
}
/// <summary>/// Executa una SQL que retorna resultats contra una conexió, no modifica l'estat de la conexió ni de la transaccio/// </summary>/// <param name="SQL">Sentència SQL a executar</param>/// <param name="SqlConn">Conexió a BBDD, ha d'estar oberta</param>/// <param name="SqlTrann">Transacció ja creada sobre la conexió (admet null)</param>/// <returns>Retorna un NEW DataTable</returns>publicDataTable Exec(string SQL, SqlConnection SqlConn, SqlTransaction SqlTrann)
{
DataTable TBL = newDataTable();
SqlCommand SqlComm = newSqlCommand();
SqlDataReader SqlReader;
SqlComm.Connection = SqlConn;
if (SqlTrann != null) SqlComm.Transaction = SqlTrann;
SqlComm.CommandText = SQL;
SqlComm.CommandType = CommandType.Text;
SqlReader = SqlComm.ExecuteReader();
TBL.Load(SqlReader);
return TBL;
}
/// <summary>/// Executa una SQL que retorna resultats contra una conexió, no modifica l'estat de la conexió/// </summary>/// <param name="SQL">Sentència SQL a executar</param>/// <param name="SqlConn">Conexió a BBDD, ha d'estar oberta</param>/// <returns>Retorna un NEW DataTable</returns>publicDataTable Exec(string SQL, SqlConnection SqlConn)
{
return Exec(SQL, SqlConn, null);
}
/// <summary>/// Executa una sentència SQL que retorna resultats, si està informada la variable Conn la fa/// servir de conexio (ha d'estar oberta), si no crea una i la tanca/// </summary>/// <param name="SQL">Sentència SQL a executar</param>/// <returns>Retorna un NEW DataTable</returns>publicDataTable Exec(string SQL)
{
DataTable TBL;
SqlConnection SqlConn;
bool Local = false;
if (Conn != null)
{
SqlConn = Conn;
}
else
{
Local = true;
SqlConn = newSqlConnection();
SqlConn.ConnectionString = CadConn;
SqlConn.Open();
}
TBL = Exec(SQL, SqlConn);
if (Local) SqlConn.Close();
return TBL;
}
/// <summary>/// Executa un INSERT en una taula que té PK identitat. Retorna la identitat creada. /// Obre i tanca conexió a BBDD (la que retorna GetConnStr)/// </summary>/// <param name="SQL">Sentència SQL a executar</param>/// <returns>Identitat creada</returns>publiclong ExecInsertWithIdentity(string SQL)
{
long Identity = 0;
SqlConnection SqlConn;
bool Local = false;
if (Conn != null)
{
SqlConn = Conn;
}
else
{
Local = true;
SqlConn = newSqlConnection();
SqlConn.ConnectionString = CadConn;
SqlConn.Open();
}
Identity = ExecInsertWithIdentity(SQL, SqlConn);
if (Local) SqlConn.Close();
return Identity;
}
/// <summary>/// Executa un INSERT en una taula que té PK identitat. /// Retorna la identitat creada. No modifica l'estat de la connexió/// </summary>/// <param name="SQL">Sentència SQL a executar</param>/// <param name="SqlConn">Conexió a BBDD, ha d'estar oberta</param>/// <returns>Identitat creada</returns>publiclong ExecInsertWithIdentity(string SQL, SqlConnection SqlConn)
{
long Identity = 0;
Identity = ExecInsertWithIdentity(SQL, SqlConn, null);
return Identity;
}
/// <summary>/// Executa un INSERT en una taula que té PK identitat. Retorna la identitat creada/// </summary>/// <param name="SQL">Sentència INSERT SQL a executar</param>/// <param name="SqlConn">Conexió a BBDD, ha d'estar oberta</param>/// <param name="SqlTrann">Transacció ja creada sobre la conexió (admet null)</param>/// <returns>Identitat creada</returns>publiclong ExecInsertWithIdentity(string SQL, SqlConnection SqlConn, SqlTransaction SqlTrann)
{
long Identity = 0;
SqlCommand SqlComm = newSqlCommand();
SqlComm.Connection = SqlConn;
if (SqlTrann != null) SqlComm.Transaction = SqlTrann;
if (!SQL.EndsWith(";")) SQL += ";";
SQL += " SELECT SCOPE_IDENTITY();";
SqlComm.CommandText = SQL;
SqlComm.CommandType = CommandType.Text;
Identity = (long)(decimal)SqlComm.ExecuteScalar();
return Identity;
}
/// <summary>/// Executa una sentència SQL que no retorna resultats, només els registres afectats. /// Obre i tanca conexió a BBDD (la que retorna GetConnStr)/// </summary>/// <param name="SQL">Sentència SQL a executar</param>/// <returns>Registres afectats</returns>publicint ExecNonQuery(string SQL)
{
int Results = 0;
SqlConnection SqlConn;
bool Local = false;
if (Conn != null)
{
SqlConn = Conn;
}
else
{
Local = true;
SqlConn = newSqlConnection();
SqlConn.ConnectionString = CadConn;
SqlConn.Open();
}
Results = ExecNonQuery(SQL, SqlConn);
if (Local) SqlConn.Close();
return Results;
}
/// <summary>/// Executa una sentència SQL que no retorna resultats/// </summary>/// <param name="SQL">Sentència SQL a executar</param>/// <param name="SqlConn">Conexió a BBDD, ha d'estar oberta</param>/// <returns>Registres afectats</returns>publicint ExecNonQuery(string SQL, SqlConnection SqlConn)
{
return ExecNonQuery(SQL, SqlConn, null);
}
/// <summary>/// Executa una sentència SQL que no retorna resultats/// </summary>/// <param name="SQL">Sentència SQL a executar</param>/// <param name="SqlConn">Conexió a BBDD, ha d'estar oberta</param>/// <param name="SqlTrann">Transacció ja creada sobre la conexió (admet null)</param>/// <returns>Registres afectats</returns>publicint ExecNonQuery(string SQL, SqlConnection SqlConn, SqlTransaction SqlTrann)
{
int Results = 0;
SqlCommand SqlComm = newSqlCommand();
SqlComm.Connection = SqlConn;
if (SqlTrann != null) SqlComm.Transaction = SqlTrann;
SqlComm.CommandText = SQL;
SqlComm.CommandType = CommandType.Text;
Results = SqlComm.ExecuteNonQuery();
return Results;
}
/// <summary>/// Executa una sentència SQL que no retorna resultats, només la primera columna del primer registre./// Obre i tanca conexió a BBDD (la que retorna GetConnStr)/// </summary>/// <param name="SQL">Sentència SQL a executar</param>/// <returns>Registres afectats</returns>publicint ExecScalar(string SQL)
{
int Results = 0;
SqlConnection SqlConn;
bool Local = false;
if (Conn != null)
{
SqlConn = Conn;
}
else
{
Local = true;
SqlConn = newSqlConnection();
SqlConn.ConnectionString = CadConn;
SqlConn.Open();
}
Results = ExecScalar(SQL, SqlConn);
if (Local) SqlConn.Close();
return Results;
}
/// <summary>/// Executa una sentència SQL que no retorna resultats, només la primera columna del primer registre./// </summary>/// <param name="SQL">Sentència SQL a executar</param>/// <param name="SqlConn">Conexió a BBDD, ha d'estar oberta</param>/// <returns>Registres afectats</returns>publicint ExecScalar(string SQL, SqlConnection SqlConn)
{
return ExecScalar(SQL, SqlConn, null);
}
/// <summary>/// Executa una sentència SQL que no retorna resultats, només la primera columna del primer registre./// </summary>/// <param name="SQL">Sentència SQL a executar</param>/// <param name="SqlConn">Conexió a BBDD, ha d'estar oberta</param>/// <param name="SqlTrann">Transacció ja creada sobre la conexió (admet null)</param>/// <returns>Registres afectats</returns>publicint ExecScalar(string SQL, SqlConnection SqlConn, SqlTransaction SqlTrann)
{
int Results = 0;
object objResult;
SqlCommand SqlComm = newSqlCommand();
SqlComm.Connection = SqlConn;
if (SqlTrann != null) SqlComm.Transaction = SqlTrann;
SqlComm.CommandText = SQL;
SqlComm.CommandType = CommandType.Text;
objResult = SqlComm.ExecuteScalar();
if (objResult != null && objResult != DBNull.Value)
{
Results = int.Parse(objResult.ToString());
}
return Results;
}
}
}
#08/03/2018 12:46 Programació C# SQLServer Autor: Alex Canalda
Segueixo amb aquesta sèrie del Peter F. Hamilton, aquest cop només té dos llibres, llargs (no tan com The Night's Dawn). Trobo que la longitud és adequada. Segueix encaixant amb la sèrie Void de forma coherent, encara que l'acció és completament diferent.
[Spoilers] L'acció arranca tot just acaba l'altra llibre. Resulta que el Void té una capa de defensa on les races que el molesten són detectades i expulsades. Aleshores com en Nigel ha fet explotar una bomba quàntica el planeta Bienvenido és expulsat a un sistema solar en mig del no res (l'estrella no pertany a cap galaxia), d'aquí el títol.
Poc després el Void acaba a l'espai normal, en els altres llibres. Com resulta que el planeta ha anat a parar a un sistema amb planetes raros, plens de races hostils, la recent recuperada Laura Brandt ha de lluitar contra un planeta ple de Primes (la raça xunga del llibre la Estrella de Pandora). Un cop els liquida morint el seu cos en l'intent queden els Fallers.
Els Fallers que han sobreviscut a la bomba d'en Nigel del primer llibre ara són pocs, però van envaint el planeta lentament. Passen 250 anys i la societat del planeta és una mena de comunisme xungo però van llançant míssils contra el Forest matant arbres. En un d'aquests arbres hi ha encastat un mòdul de supervivència d'en Nigel i a dins hi ha un bebé. El mòdul cau al planeta i el bebé el recull en Florian, una guardabosc. Aleshores el llibre és una cursa entre les autoritats comunistes liderades per en Chaing que volen mantenir el status quo, els Fallers que volen matar-ho tot, la Kisandra (que té poders de la Commonwealth que li va donar en Nigel al primer llibre) i lluita per la raça humana de forma separada del govern i en Florian amb el bebé que creix ràpid.
Finalment el bebé madura a l'edat adulta en un mes i resulta que és un clon de la Paula Myo, la super-investigadora de la sèrie Void. La Paula amb els seus coneixements i poder deductiu, amb l'ajuda de la Kisandra, aconsegueixen trobar les restes de una altra nau colonitzadora enterrada a l'àrtic. Amb aquesta tecnologia aconsegueixen fer front als Fallers visitant de forma ràpida els altres planetes i parlant amb les diferents races que estan en ells. L'objectiu és alliberar als Raiel empresonats a un planeta que té una barrera tipus Void.
Els Raiel són les restes l'armada que van enviar a atacar el Void i que una de les naus va caure a Querencia. Amb l'ajuda dels Raiel aconsegueixen derrotar als Fallers i tornar a la Commonwealth. El final del llibre està molt bé ja que es lliguen tots els caps.[/Spoilers]
A mi el llibre m'ha agradat molt i m'ho he passat molt bé llegint-l'ho.
Aquest és el primer volum dels dos que hi ha. Una duologia? L'acció està ubicada en els events, entorn i societat de la Trilogia de la serie Void. De fet comparteix algun personatge.
[Spoilers] Una nau colonitzadora amb humans va a parar a dins del Void. Allí troba un Skylord que la guia la nau cap a un planeta. La nau es va degradant ja que dins del Void tot el tema elèctric/electrònic deixa de funcionar, aleshores els corre pressa aterrar al planeta. En orbita al planeta hi ha un conjunt de misterioses estructures gegants que fan que el Void sigui més normal. Li diuen the Forest i cada estructura Tree.
El personatge principal és Slvata o així, un militar que es dedica a exterminar "Fallers". Els "Fallers" o els caiguts són ous grans que cauen del cel procedents de les estructures misterioses. Un ou t'atreu perque el toquis i quan el toques et quedes enganxat i t'absorbeix poc a poc. Quan ja t'ha tragat sencer aleshores sobre i surt un clon teu però dolent. Els ous els llança contra el planeta the Forest.
De mentres a la Commonwealth, els humans estan ajudant als Raiel a derrotar el Void. I explica un tros petit de la sèrie Void. En Nigel Sheldon es clona i aconsegueix atravessar la barrera del Void per anar a Querencia a ajudar al Edeard. Però enlloc d'allí va a parar a Bienvenido, el planeta on va aterrar la nau colonitzadora.
Un cop allí investiga com derrotar al Void i per fer-ho investiga el Forest, ja que aquestes estructures desfan el Void, encara que no del tot. En Nigel descobreix que el Forest aquest és en realitat una raça alienígena que fa servir el mètode dels ous per envair planetes. Aleshores es dedica a ajudar al Slvata per fer un canvi de règim, d'un aristocràtic a un comunista. I en el caos robar unes bombes molt potents de l'antiga nau colonitzadora. Construeix un coet primitiu i aconsegueix detonar un bomba en el Forest tot morint en l'explosió. Això activa un mecanisme defensiu del Void que expulsa al planeta del seu interior. El planeta va a parar a una zona de l'espai normal que no té cap galaxia ni res aprop.
En el epíleg del llibre encaixa en la línia temporal de la trilogia Void, on explica que ja s'ha acabat el perill del Void.[/Spoilers]
Un llibre llarg, no tan com altres d'aquest autor, però ple d'acció, algunes naus, conflictes, amor, alguna cosa que grinyola però en general molt bé i recomanable.
Backblaze és una empresa que fa backups al núvol, té 500 PB i això són un munt de discs durs. Ja fa temps que vaig publicant els reports que fan perque trobo que són útils. De moment a casa vaig posant discs HGST i ja fa anys que funcionen 24/7 i no han fallat. Tal com surt a la gràfica de Backblaze. Ara ha publicat el report del Q4 2017.