Today we tested a web application in the new Microsoft Edge browser. To our surprize, the site failed where Internet Explorer, Chrome, Firefox and even Safari worked perfectly well. I narrowed the problem to the navigator.geolocation.getCurrentLocation which wasn't working. The site would see navigator.geolocation, ask for the current location, the user would be prompted to allow the site to access location and after that would silently fail. What I mean by that is that neither the success or the error callbacks were called, even if the options object specified one second for the timeout. I don't have access to a lot of Windows 10 machines and I assume that if a lot of people met with this problem they would invade the Internet with angry messages, but so far I've found no one having the same issue.

Bottom line: forced to take into consideration the possibility that the geolocation API would silently fail, I changed the code like this:
if (navigator.geolocation) {
var timeoutInSeconds=1;
var geotimeout=setTimeout(function() {
handleNoGeolocation();
},timeoutInSeconds*1000+500); //plus 500 ms to allow the API to timeout normally
navigator.geolocation.getCurrentPosition(function (position) {
clearTimeout(geotimeout);
var pos = doSomethingWith(position.coords.latitude, position.coords.longitude);
}, function () {
clearTimeout(geotimeout);
handleNoGeolocation();
},{
enableHighAccuracy:true,
timeout: timeoutInSeconds*1000
});
} else {
handleNoGeolocation();
}

In the handleNoGeolocation function I've accessed the great service FreeGeoIp, that returns vague coordinates based on your IP and fell back to a static latitude, longitude pair if even this call failed.

Note: for the first time the function is called for your site, a browser dialog will appear, requesting permission to share the location. During the display of the dialog the timeout will fire, then, based on the user choice (and browser) a success/error handler will be called or nothing (like in this case), so make sure your code can handle running handleNoGeolocation followed by doSomethingWith.

and has 0 comments
A day ago there was a "leak" of three TV series pilots. I know, it sounds like someone out there is pissing TV series, but a look at most of them and you start seeing the truth of it. I don't really believe they were stolen or anything, either. I think they were deliberately distributed to gauge viewer reaction. The three shows in question are Blindspot, Lucifer and Minority Report. What do they all have in common? Law enforcement. It gets ridiculous from here on, you've been warned.

Blindspot is about a young woman (lovely Jaimie Alexander - the actress playing the Asgardian warrior Lady Sif in the Thor Marvel universe) found naked, without memories and tattooed all over her body. The tattoos are clues about future crimes and our Jane Doe helps the FBI solve them. The series has the obvious hallmarks of the post Lost era, with just enough artificial mystery to keep one guessing, but not really caring. Anyway, all I can say is that if you make a show about Jaimie Alexander found naked you should bloody show her naked! Stupid Americans! The French should start remaking these shows and demonstrate how it is done!

Lucifer is about... the devil. He comes to Earth because he got tired of ruling Hell - which was his divine punishment from his father, God. And by Earth I mean Los Angeles. Yes, very subtle. He teams up with another lovely (Lauren German) who is a police detective. Why, you might ask? Devil may care, he just loves solving crimes and has daddy issues. The show is so ridiculously pompous that it raises hackles. It reminds me of the well deservedly cancelled The Transporter series.

Minority Report is based on a movie about "precogs" used to stop crime by predicting it, leading to the paradox of arresting and incarcerating people because of crimes they did not commit. Yet. I haven't watched it. Yet. But since the movie was based itself on the works of famous paranoid sci-fi writer Phillip K. Dick, it is the only one that I have hopes for. Of course the detective will be a young attractive person, teamed with another young attractive person with some special power that helps solving some type of crisis, probably crimes and possibly related to terror attacks. I can see it... in the future...

Update: I was right. One of the precogs in the movie helps a young black female police detective to prevent crimes. This is a horrible perversion of the film, which ended with showing the precog system not working and putting innocent people in jail. In the series, the police is frustrated that the precog era has ended and is convinced that every released arrestee from the program would have become a killer. Yuck!

and has 0 comments
Another great Star Trek novel placed in the Kirk era, Star Trek Prime Directive keeps the reader/listener on the edge of their seat. It starts with a disgraced Kirk, a scattered crew and a scrapped Enterprise. It shows the dark, bureaucratic side of the Federation, cruel and merciless when you are not the lucky wearer of the golden captain uniform or, even better, an admiral. How did it come to this? The answer is both captivating, original and with deep roots in the Star Trek basic tenant: the Prime Directive.

I actually listened to the audiobook, also on YouTube (see embedded video), which was very well narrated. If I had any problems with the story was that it was clearly very biased. Kirk is always thinking of the poor alien species that are like humans, but seems to have no qualms to experiment with phaser fire and even slightly torture other alien beings if they are bug like. Also Spock seems very little a Vulcan in this.

Bottom line is that the idea was intriguing and original and the style of the writing was very good. One of the best ST novels so far.

I've come upon this strange Not enough storage is available to complete this operation ArgumentException when creating an instance of EventSource derived classes. This class is responsible for creating entries in Windows logs. Strangely enough, there are very few articles on the Internet connecting the class with this particular exception, so I started to investigate. One important thing to notice is that the exception is intermittent. Basically you can cycle a few times with a try/catch block and get a valid instance. That seems to indicate some sort of race condition. So far, this is the easy solution I could find. However, I really wanted to know why does it happen.

If I remove the EventSource class from the searches I get more pages reporting the same exception and one of the reasons that people say it happens is related to the size of the registry. Retrospectively it makes sense, but it never occurred to me that the system registry has a maximum size. But is that the problem? Looking with the EventViewer summary I see something like this:

Of course, the most obvious thing there is the exact size of each log category: 20.00 MB. If one right-clicks on any of the log groups and goes to Properties, the size limit for each is clearly shown and configurable. So is that the problem?

The exception is thrown almost exclusively when the logging is heavy: multiple threads trying to log stuff at the same time. Since retrying usually solves the problem, my guess is that the exception is thrown somewhere between the request for a new log entry and the process that eliminates old entries to allow for new ones. Unfortunately I don't see any configuration option for how many entries to eliminate. I would have liked to clear, let's say, 20% of the log when it is full to make this problem less relevant. Perhaps hidden in the bowels of the system registry there is a way to set this, but at this time I don't know it. Nor is it clear if I have the option to remove more of the less important events rather than just the oldest. Clearly the EventLog class in .NET supports deleting individual log entries, so this is feasible if it ever becomes a real problem.

So far, my solution is to just try again when the error is thrown:
LoggerEventSource eventSource = null; //EventSource derived class (see documentation)
for (var i = 0; i < 5 && eventSource == null; i++)
{
try
{
eventSource = new LoggerEventSource();
}
catch (ArgumentException)
{
Thread.Sleep(100);
}
}

and has 0 comments
Star Trek: Strangers from the Sky is an audiobook read by George Takei and Leonard Nimoy. While it is a typical ST The Original Series plot, with god like aliens, travel back in time to significant moments of Earth's history and a focus on high moral values that, in the end, save the day, I felt that it was a little bit more subtle, deeper than a typical episode of any of the series. Was it because of the introspection of the characters, or the wonderful narration of Nimoy and Takei, I do not know. What I can say is that I enjoyed listening to the story quite a lot and I recommend it highly for any Star Trek fan.

I also don't know if it is in the public domain or not, all I can say is that I listened to it on YouTube and so can you:
Of course you cannot listen to it on YouTube anymore. Some lawyers saw to that.

and has 0 comments
This is the third writing of Esther Friesner that I've read, after The Shunned Trailer and Druid's Blood, both excellent and funny, combining fantasy elements with the present or other realistic historical settings. Gnome Man's Land does the same thing, but I have to say I didn't find it as funny or as good as the others I mentioned. I also attempted to start Here Be Demons, another of her books, but couldn't really enjoy it enough to go past the first chapter. Probably she is one of those authors who, when they are good are really good and when they are not, well...

The book is the first of a trilogy starring Tim Desmond, a young boy of Irish descent who finds himself in a strange situation when the veil between our world and the land of the fey is punctured and more and more fantastic creatures go through. They come and attach themselves to mortals, as many of them are creatures who's very reason for existing is serving their masters. Stuff like banshees, Mongolian ancestors, goblins, kobolds, Greek demigodesses, Russian bath spirits, sprites, elves and so on and so on just sprout from the rupture, bringing annoyance and confusion more than anything. Tim somehow gets tricked into becoming the champion of the Fey on Earth and he does the job mainly because he feels all of these supernatural creatures need his help (plus the girl he secretly loves supports this and his banshee is a hot redhead to boot).

Some hilarity ensues, but often feeling a bit artificial, while the actions of the characters involved are simplistic, inconsistent and dragging on, like the author wanted to tell a joke and she ended up writing an entire book. The crises are not that good either, oscillating between childishly funny and dead bloody serious. The ending was disappointing as well, leaving a very traumatic event just in the wind, like an afterthought, pending Tim's recovery of some of his memory. I really wanted to like the book, too, but in the end I just forced myself to reach the end and I am confident I will not read the other two books in the series. I have some hopes for the Princesses series, which I understand is one of Friesner's better works.

Change Data Capture is a useful mechanism for tracking data changes in Microsoft SQL Server. Once you enable it for a database and some of its tables, it will create a record of any change to the data of those tables. In order to use the captured data, Microsoft recommends using the table functions provided by the mechanism, mainly [cdc].[fn_cdc_get_all_changes_dbo_<table name>] and [cdc].[fn_cdc_get_net_changes_<table name>]. However, when you use them, your very first experience might be an error that looks like this: Msg 313, Level 16, State 3, Line 20 An insufficient number of arguments were supplied for the procedure or function cdc.fn_cdc_get_all_changes_ ... . Since this is an error message everyone associates with missing a parameter for a function, one might assume that the documentation is wrong and one must add another parameter. You try adding a bogus one and you get Msg 8144, Level 16, State 3, Line 9 Procedure or function cdc.fn_cdc_get_all_changes_dbo_<table name> has too many arguments specified. which brings confusion. One hint is that if we use one less parameter than in the documentation, the error is slightly different Msg 313, Level 16, State 3, Line 9 An insufficient number of arguments were supplied for the procedure or function cdc.fn_cdc_get_all_changes_dbo_<table name>. In this error message, the tracked table name is specified in the function name, as opposed to the other where ... is used instead. What is going on?

The documentation for the function (which, as usual, nobody reads past the usage syntax and the code examples - just read the Remarks section) says this: If the specified LSN range does not fall within the change tracking timeline for the capture instance, the function returns error 208 ("An insufficient number of arguments were supplied for the procedure or function cdc.fn_cdc_get_all_changes.")., which of course is the explanation for this weird behaviour, but why and when does it happen?

The why comes from a Microsoft Connect page where an overly honest developer explains that the reason for the obscure error message is the antiquated error and function system used in T-SQL: The issue here is the inability to do raiseerror from within a function that prevents us from bubbling up meaningful error message. If one looks at the source of cdc.fn_cdc_get_all_changes_dbo_<table name>, one sees that the error is thrown from another function, a system one, called [sys].[fn_cdc_check_parameters]. Doing a select on it we get the same original error which is now slightly humourous, since it comes from a completely different function than the one in the message. Since it is a system function this time, there is no source code for it.

The when is more tricky and it shows that they didn't think this through much. First of all, whenever you send a NULL or an empty (0x0000...) value to the function as the begin or end LSN you get this error message. The code examples from Microsoft always show these mysterious LSN values being received from functions like sys.fn_cdc_get_min_lsn('<schema name>_<table name>'), sys.fn_cdc_get_max_lsn(), sys.fn_cdc_map_time_to_lsn('largest less than or equal', GETDATE()) and so on, but they are hardly easy to understand, as they return an empty value for wrong parameters. For example, a common reason why your code fails is from getting the LSN like this: sys.fn_cdc_get_min_lsn('MyWonderfulTable') when in fact you need to use the schema in the name as well: sys.fn_cdc_get_min_lsn('dbo_MyWonderfulTable'). You have to use this syntax everywhere. Funny enough, if the tracked table is empty, you get the lowest LSN for the entire database, but if you use a wrong database name (or without the schema, or NULL, etc) you get an empty LSN. How an empty LSN is not the minimum LSN is beyond me.

My solution? Just select from the tables directly. Yeah, I know, it's bad, unrecommended by Microsoft, reinventing the wheel. But it works and I don't get weird functions messing up my flow with obscure error messages. Just remember to take a look at the cdc.* functions and see how they are written.

So, to summarize: The error message is misleading and it's all they could do within the confines of the T-SQL function error system. Remember to use the schema in the string defining the table in the cdc functions (ex: dbo_MyTable). In case you really want to be flexible, interrogate the cdc tables directly.

I had this situation where I had to execute large SQL script files and the default sqlcmd tool was throwing exceptions rather than execute them. So I created my own tool to read the scripts and execute them transactionally. Everything went smoothly, except at the end. You see, I didn't use TransactionScope.Complete from the beginning in order to see how the program would cope with a massive rollback. Not well, apparently.

The exception was thrown at rollback: Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding. I had set the TransactionOptions.Timeout to TransactionManager.MaximumTimeout and the SqlCommand.CommandTimeout to 0 (meaning never end) and I still got the exception. Apparently, the problem was the SqlConnection.ConnectTimeout which is a readonly property with a default value of 15 seconds. The value can be changed via the connection string, by adding something like Connect Timeout=36000 (10 hours) and many articles on the Internet suggest doing that. However, that is just really ugly. A better solution is to set the value of the timeout programmatically and this is how to do it:
var timeout = TimeSpan.FromHours(10);
SqlConnectionStringBuilder csb = new SqlConnectionStringBuilder(connectionString);
csb.ConnectTimeout = (int)timeout.TotalSeconds;
connectionString = csb.ConnectionString;

As you can see, the nice SqlConnectionStringBuilder helps us validate, parse and change the values in the connection string. One can imagine other interesting uses, like adding MARS to the connection string automatically or restricting the use to a list of databases or disallowing weak passwords, etc.

and has 0 comments
If you were born before the 80s, Ready Player One is going to fill you with melancholy. Ernest Cline combines several classical young adult themes - like a battle versus an oppressive corporate evil, true and pure love, villainy and lack of honor defeated through friendship and good feelings - with (often obscure) geek memes of the 70s and 80s. If you are the kind of person who likes to impress by quoting lines from movies or telling of your adventures in games that are older than your children, this is the book for you. OK, I won't be mean, the book is going to be fun no matter when you were born, but the level of enjoyment may vary.

However, the book is still a young adult book at its core and, besides the overall message that you actually have to make an effort to reach your goals - an often neglected tidbit in young adult books and movies - it reads like one. Young heroes, with enough skill to pass through the challenges of the story, but awkward enough to also be endearing, manage to save the world through the power of their dedication and ideals. Also Chekhov's Gun has been used so much that it left gaping holes in the story. Amazing how random things in the story come perfectly together at the end. Let a bitter Harry Potterish aftertaste.

But let's start with the plot, which is pretty fun. It all happens in a dystopian world where energy reserves dwindled, gasoline became way too scarce and expensive, Elon Musk never happened and most people live their lives in a virtual world called OASIS, created by a brilliant yet reclusive visionary who made sure the system will remain secure and anonymous. Kind of like the Internet, but without the MPAA or the NSA. Yeah, it already sounds like an impossible dream, doesn't it? Well, the maker of the game world dies and leaves his entire estate (hundreds of billions of dollars and complete control over OASIS) to whoever finds the Easter Egg he his inside the game. The heroes of the story are young "egg hunters", while the villains are corporate drones who have been hired to find the egg for their company.

The writing style irked me a little. I know it is Cline's first book, and it certainly was a decent effort, but it had that way of explaining things that I call "fake past" in which the narrator explains things as if he is telling a story from the past. "The OASIS was...". Since this is supposed to happen in the future, it took a while until I could stop feeling irritated by it. However this has the advantage of being very easy to read.

I think it matters a lot if the reader is into cultural references. I could understand some, I could remember some, most of the references in the book, though, were ancient or obscure enough that even I didn't recognize them, and I am a pretty geeky person. I felt rewarded when I could "get it" and frustrated when I didn't, so probably it will be the same for most readers. If you don't care about these things, I think it is better to wait for the movie.

...which is in the works, with Steven Spielberg attached to the project. It might be difficult to put the story on the screen, though, since the book made an effort to describe a future world where everybody is obsessed with this specific period of the late 20th century, kind of like the Star Trek episodes that happened in the past or that required Kirk or Picard to know some specific book from the school curriculum. There is even a Ready Player One web site, that might have some Easter eggs in it (they would be dumb not to program some) but to me it seems both way too geeky and way to social at the same time.

Bottom line: a fun book for geeks. I hope it inspires the younger generations to look at the world a little bit differently, but I don't have my hopes up. My guess is that they will go all 'Meh' on a story that references anything that happened last century.

Update: after another very useful comment from NULLable, I tried several new ideas:

  • range queries - trying to specify that the child StartIp, for example, is not only greater or equal to the parent StartIp, but also less or equal to the parent EndIp. In my case the query didn't go faster and adding new indexes as recommended in the comment made is slower. I believe it is because the range values are not static or just because clustering the start/end IP index is really way faster than any logical implementation of the search algorithm
  • cursor hints - obviously a very important hint that I should add to almost any cursor is LOCAL. A GLOBAL cursor can be accessed from outside the stored procedure and weird things can happen when running the stored procedure twice at the same time. NULLable recommended also STATIC READ_ONLY and FORWARD_ONLY. In truth the performance of the query doesn't really depend on the speed of the cursor, anyway, but I found an article that discusses the various cursor hints and ends up recommending LOCAL FAST_FORWARD. Check it out, it is very informative. My tests showed no real difference in this particular scenario.
  • RI-Tree implementation in SQL - the article that NULLable linked to is amazing! I just don't get it :) I will update this more when I gain more IQ points.


Update 2: I kind of understood the Relational Interval Tree implementation, but I couldn't find a way for it to help me. The code there creates a computed column of the same type as the IP columns then makes a BETWEEN comparison and/or a join or an apply with two table functions. I can't imagine how it could help me since the original query is basically just two BETWEEN conditions. But still a very interesting article.

I wanted to have a database of all Ripe records, in order to quickly determine the Internet Service Provider for an IP. We are discussing IPv4 only, so the structure of the table in the database looked like this:

CREATE TABLE [dbo].[RipeDb](
[Id] [int] IDENTITY(1,1) NOT NULL,
[StartIp] [bigint] NULL,
[EndIp] [bigint] NULL,
[NetName] [nvarchar](450) NULL,
[StartTime] [datetime2](7) NULL,
[EndTime] [datetime2](7) NULL,
[ParentId] [int] NULL)


As you can see, I translate IPs into BIGINT so that I can quickly sort and select stuff. I also added a ParentId column that represents the parent ISP, as you have some huge chunk of IPs, split and sold to other ISPs, which in turn are selling bits of the IP range they own to others and so on. The data I receive, though, is a simple text file with no hierarchical relations.

The task, therefore, is to take a table like described above, with more than four million records, and for each of them find their parent, if any.

The simplest idea is to join the table with itself like this:

SELECT rp.Id as ParentId, 
r.Id
FROM RipeDb r
INNER JOIN RipeDb rp
ON rp.StartIp <= r.StartIp
AND rp.EndIp >= r.EndIp
AND rp.EndIp - rp.StartIp > r.EndIp - r.StartIp

This gets all ancestors for each record, so we need to use a RANK() OVER() in an inner select in order to select only the parent, but that's beyond the scope of the article.

Since we have conditions on the StartIp and EndIp columns, we need an index on them. But which?

Through trial and error, more than anything else, I realised that the best solution is a clustered index on StartIp,EndIp. That is why the first column (Id) is not marked as PRIMARY KEY in the definition of the table, because it has to look like this:

[Id] [int] PRIMARY KEY NONCLUSTERED IDENTITY(1,1) NOT NULL

. Yes, primary keys don't have to be clustered.

But now you hit the snag. The process is EXTREMELY slow. Basically on my computer this query would end in a few days (as opposed to twice as much with a nonclustered index). What the hell is going on?

I tried several things:

  • JOIN hints (Merge, Loop and Hash joins) - the query optimizer seems to choose the best solution anyway
  • Various index combinations - nothing beats a clustered index
  • Taking a bunch of records and joining only them in a WHILE loop - it doesn't fill up the temp db, but it is just as slow, if not worse


At this point I kind of gave up. Days of work trying to figure out why this is going so slow reached a simple solution: 4 million records squared means 16 thousand billion comparisons. No matter how ingenious SQL would be, this will be slow. "But, Siderite, I have tables large like this and joining them is really fast!" you will say. True, with equality the joins are orders of magnitude faster. Probably there is either place for improvement in the way I used the indexes or in the way they are implemented. If you have any ideas, please let me know.

So did I solve the problem? Yes, of course, by not relying on an SQL join. Think about how the ranges are arranged. If we order the IP ranges on their start and end values, you get something like this:



For each range, the following is either a direct child or a sibling. I created a stored procedure that called itself recursively, which should have worked, but then it reached the maximum level of recursion in SQL (32 - a value that one cannot change!) and so I had to do everything myself. How? With a cursor. Here is the final code:

DECLARE @ParentIds TABLE (Id INT,StartIp BIGINT, EndIp BIGINT)
DECLARE @ParentId INT
DECLARE @Id INT
DECLARE @StartIp BIGINT
DECLARE @EndIp BIGINT
DECLARE @OldParentId INT

DECLARE @i INT=0
DECLARE @c INT

DECLARE curs CURSOR LOCAL FAST_FORWARD FOR
SELECT r.Id, r.StartIp, r.EndIp, r.ParentId
FROM RipeDb r
WHERE r.EndTime IS NULL
ORDER BY StartIp ASC, EndIp DESC

OPEN curs

FETCH NEXT FROM curs
INTO @Id, @StartIp, @EndIp, @OldParentId

WHILE @@FETCH_STATUS=0
BEGIN

DELETE FROM @ParentIds WHERE EndIp<@StartIp

SET @ParentId=NULL
SELECT TOP 1 @ParentId=Id FROM @ParentIds
ORDER BY Id DESC

SELECT @c=COUNT(1) FROM @ParentIds

IF (@i % 1000=0)
BEGIN

PRINT CONVERT(NVARCHAR(100),SysUtcDatetime())+' Updated parent id for ' + CONVERT(NVARCHAR(100),@i) +' rows. ' + CONVERT(NVARCHAR(100),@c) +' parents in temp table.'
RAISERROR ('', 0, 1) WITH NOWAIT

END
SET @i=@i+1

IF (ISNULL(@OldParentId,-1) != ISNULL(@ParentId,-1))
BEGIN
UPDATE RipeDb SET ParentId=@ParentId WHERE Id=@Id
END

INSERT INTO @ParentIds VALUES(@Id,@StartIp,@EndIp)

FETCH NEXT FROM curs
INTO @Id, @StartIp, @EndIp
END

CLOSE curs
DEALLOCATE curs


I will follow the explanation of the algorithm, for people hitting the exact issue that I had, but let me write the conclusion of this blog post: even if SQL is awesome in sorting and indexing, it doesn't mean that is the only solution. In my case, the SQL indexes proved to be a golden hammer that wasted days of my work.

So, the logic here is really simple, which makes this entire endeavour educational, but really frustrating to me:

  1. Sort the table by start IP ascending, then end IP descending - this makes the parents come before the children in the list
  2. Create a table variable to store the previous parents - so when you finished with a range you will automatically find yourself in its parent
  3. Use a cursor to move through all the items and for each one:
  4. Remove all parents that ended before the current item starts - removes siblings for the list
  5. Get the last parent in the list - that is the current parent range
  6. Set the parent id to be the one of the last parent


It's that deceptively simple and the query now ends in 15 minutes instead of days.

Another issue that might be interesting is that after the original import is created, the new records added to the table should be just a few. In that case, the first join and update might work faster! The next thing that I will do is count how many items I need to update and use one method or another based on that.

Hope that helps someone.

and has 0 comments
Villains by Necessity is not a masterpiece of literature, but it is a fun fantasy book that doesn't feel the need to be part of a trilogy or take itself too seriously. Perfect for when you want to pick up a book because you are tired, not because you want to work your brain to dust. First work of Eve Forward, it is rather inconsistent, moving from silly to dead serious and back and making the heroes of the story oscillate between pointlessly evil and uncharacteristically good.

The best part of the book, though, is the concept. The world enjoys an age of light and good after a bitter war that saw all the forces of darkness and evil be defeated. The world is filled with happy people, no conflict, beautiful weather, lush vegetation. In a word, it is fucking boring. An unlikely party of evildoers gets together to save the world by bringing darkness back!

Alas, it was a concept that was not really well used. The characters, borrowed from classical fantasy, are "evil" by their professions only, but not by behaviour. Sam is an assassin, but he doesn't enjoy the suffering of his victims and is proud of his prowess. Archie is a mischievous thief, but other than that he is an OK fellow. Even Valerie, the dark sorceress, eats sentient beings just because it is her race's culture and her evil is more often artificial. Not to mention Blackmail, who acts as the classic stoic hero. Similarly, the forces of good are blood thirsty thugs that want to either kill everything dark or brainwash them, as a humane solution. This basically makes our heroes... err... heroes, not villains, and viceversa.

Now, the book wasn't bad. The style was amateurish, but it is Eve Forward's first book, after all. I could read it and I got caught by the story. I was more attracted to the original concept, though, and I was very curious how it would go. It is so difficult to present bad people as the protagonists, I know, because many people, including writers as they write, want them to be redeemed somehow. In the end, the moral of the story - excruciatingly laid out in a few paragraphs that shouldn't have existed - felt really heavy handed and simplistic. Ok, good people can do bad things and bad people can do good things, but it is important to explore what makes them good and bad, not just lazily assign them dark fantasy classes and be done with it.

Bottom line: fun read, but nothing special.

and has 0 comments
This is how reality stands right now: even if the danger of an asteroid hit is great, the risk of one hitting is small. That means that they hit (very) far apart and cause a lot of damage. Now, all governments in the world are run by politicians, who are by their very nature bureaucrats. They are reactive, not proactive, and they have insulated themselves from responsibility by manipulating laws and creating committees and departments that they can behead at any time, as they keep their fat asses on their chairs of power. This is not a rant, it's just the ugly truth, evolving, but never really changing since we were barely smarter than monkeys.

The logical conclusion of these facts is that politicians will not do anything about asteroids until we are hit by one. Even worse, since the probability that a really big one will hit without us knowing in advance has been reduced by space advances, the asteroid that will hit us will probably be small. The Tunguska and the Chelyabinsk events, real things that happened, changed nothing. The one that is going to change anything will be when something similar happens on top of a city.

This is not a doomsday prophecy, either. The probability that this will happen is extremely small. First of all the asteroid has to be small enough and/or fast enough so that we don't detect it in time. Then it has to hit at a certain angle to not be deflected by the atmosphere. Then it has to reach a populated area, which one would think is simple, since we can't seem to be able to fart without someone smelling it, but in truth, with the oceans and the human propensity of congregating for no good reason, it is less probable. However, with enough time, even a small probability becomes certainty.

So, the scenario goes like this: we all pretend to care, but we don't. We want less taxes, not asteroid protection. Politicians use our shortsightedness and our greed to enhance their own and do nothing. Then an asteroid hits, causing massive damage, death and loss of property. This is the moment when something happens. They implement new laws, launch asteroid defense programs, create new departments and committees. But, since the probability that an asteroid hits is small, the hype will fade, the budgets with it, politicians will rotate, people will forget. By the time the next asteroid hits, no one will be prepared for it any more than for the previous one.

In the end, the only things that ever made a dent in the probability that something will hurt us as a species or even as a larger group were technological. Not technology per se, just its price. Just more scientists with cheaper tech getting more done. When space launches become cheaper, satellites smaller, we can do more with them at the same relative price. That is why now we are discovering millions of asteroids in the Solar System, not because of some sort of scientific awakening. It's cheaper, probably as cheap as it was for amateur astronomers to buy telescopes in 1801, when Giuseppe Piazzi discovered the first asteroid, Ceres. I just hope this all gets cheap enough fast enough so we can do something by the time the big asteroid is coming. Well, if we don't destroy ourselves in some other way by then.

I know I'm a month late, but Happy Asteroid Day!

and has 0 comments
I needed to get all IP addresses in a range, so I applied the mask to my current IP and started to work through the minimum and maximum values of bytes to get the result. I had a code that looked like this:
for (var b = min; b <= max; b++) { //do stuff }
where min was 0 and max was 255.

The expected result: all values from 0 to 255. The result: infinitely running code. Can you spot why?

Yes, when min and max are bytes, b is also a byte, so when it gets to 255 and does b++ the value becomes 0 again. Fun, eh?

and has 2 comments
There are several stories happening at the same time in The White Luck Warrior, with almost no direct connection between them. There is the Great Ordeal, advancing slowly towards Golgoterath while being besieged by hordes of Sranc, also containing the story of this kid prince forced to march with it; then there is the palace life, with Esmenet left to rule the empire while Kellhus is away, while various factions are ready to take advantage of the lack of man power of the leadership and her half Dunyain children prove to be either insane or really insane; there is the trek of Achamian in search of the origin place of Kellhus. Among these there is a vague and a few paragraphs long subplot of The White Luck Warrior, a mysterious figure that seems to know all of its future, making him an automaton, I guess and some bits about the Fanim.

Why the smallest and insignificant portion of the book gave its title I do not know, but remember that the first book in the Aspect-Emperor series was called The Judging Eye, which is most prominently used or described in this volume. By far the most interesting and captivating storyline is that of Achamian, although I have to say that the logistics of long duration travel within enemy territory and the psychological factors involved seemed to me poorly described by Bakker.

What I knew will happen happened. I finished the book before the third volume in the series was released and now I am in withdrawal pains. That proves that the book captivated me. At very few moments I felt the need to "fast forward" and, considering the amount of distraction and that I had resolved to draw this book out a little bit in the hope that the third volume would be released, I finished it rather quickly.

Even if enjoyable, to me it felt more like a filler. I couldn't empathize with Esmenet or any of her demented children, nor could I care less what happened to Maithanet, who is one of the less fleshed out characters in the book. Similarly, the Sorweel story arch described a confused and frustrated teen, which was relatable, but uninteresting as a character. Unlike in the first four books, Kellhus sounds less godly and dominating and is mostly relegated to a minor role in the overall story. No, the most interesting characters and storyline revolve around Achamian, Mimara, The Captain and the mysterious Cleric, plus any of other members of the crazy bunch of mercenaries known as The Skin Eaters. And they just walk and walk and walk, only to end the book in a cliffhanger. While I await eagerly the sixth book, I have my misgivings and fears that it will not be as good as this one, just as this one felt a little bit short of the first.

and has 1 comment
This post will discuss the possibility of creating an SQL injection using the name of a parameter.

We have known about SQL injection since forever: a programmer is constructing an SQL command using user provided information and some malicious hacker inserts a specially crafted string that transforms the intended query into something that returns the content of a user table or deletes some data on the server. The solution for this, in the .NET world, is to use parameterized queries. Even if someone dynamically creates an SQL query, they should use parameter names and then provide the parameters to the SQL command. The idea behind this is that any value provided by the users will be escaped correctly using parameters. Today I found that this solution works perfectly for parameter values, but less perfectly for parameter names. Try to use a parameter with a name containing a single quote and you will get an error. Let's analyse this.

Here is a piece of code that just executes some random SQL text command, but it also adds a parameter containing a single quote in the name:
using (var conn = new SqlConnection("Server=localhost;Database=Test;UID=sa;Trusted_Connection=True;"))
{
conn.Open();
using (var comm = new SqlCommand())
{
var paramName = "a'";

comm.Connection = conn;

comm.CommandText = "SELECT 1";
comm.Parameters.Add(new SqlParameter(paramName, SqlDbType.NVarChar, 100)
{
Value="text"
});

comm.ExecuteNonQuery();
}
conn.Close();
}

As you can see, the text content of the SQL command is irrelevant. the name of the parameter is important and for this I just used a single quote in the name. Running SQL Profiler, we get this query string that is actually executed:
exec sp_executesql N'SELECT 1',N'@a'' nvarchar(100)',@a'=N'text'
In this example the name of the parameter is properly handled in the string defining the name and type of the parameters, but it is NOT escaped during the parameter value declaration. A small change of the code with paramName="a='';DELETE * FROM SomeTable --" results in an interesting query string in the SQL Profiler:
exec sp_executesql N'SELECT 1',N'@a='''';DELETE FROM SomeTable -- nvarchar(100)',@a='';DELETE FROM SomeTable --=N'text'
Strangely enough, when inspecting the SomeTable table, the values are still there, even if copying the text into SQL Management Studio actually deletes the values. A similar construction using stored procedures leads to a completely legal SQL that is recorded by SQL Profiler, but it doesn't really do anything:
using (var conn = new SqlConnection("Server=localhost;Database=Test;UID=sa;Trusted_Connection=True;"))
{
conn.Open();
using (var comm = new SqlCommand())
{
var paramName = "a='';DELETE FROM SomeTable --";

comm.Connection = conn;
comm.CommandText = "DoTest";
comm.CommandType = CommandType.StoredProcedure;
comm.Parameters.Add(new SqlParameter(paramName, SqlDbType.NVarChar, 100)
{
Value="text"
});

int k = 0;
using (var reader = comm.ExecuteReader())
{
while (reader.Read()) k++;
}
Console.WriteLine(k);
}
conn.Close();
}
... with the resulting SQL:
exec DoTest @a='';DELETE FROM SomeTable --=N'text'

I have demonstrated a method of sending a maliciously crafted parameter name to the SqlCommand class and managing to send to the SQL Server a query that should achieve a destructive result. So why doesn't it actually do anything?

The explanation is in the EventClass column of the SQL Profiler. While a normally executed SQL command (let's say from SQL Management Studio) has event classes of SQL:BatchStarting and SQL:BatchCompleted, the query resulting from my attempts have an EventClass of RPC:Completed. It appears that the RPC method of sending queries to the SQL Server doesn't allow for several commands separated by a semicolon. The result is that the first command is executed and the rest are apparently being ignored. The TDS protocol documentation shows that the RPC method is a system of executing stored procedures by sending a binary structure that contains stuff like the name of the procedure, the parameters and so on. Since an SQL text is actually translated into a call to the sp_executesql stored procedure, RPC is used for both types of SqlCommand: Text and StoredProcedure.

I don't have the time to explore this further, but I wonder if this can be used for any type of SQL injection. To make sure, try to check the names of the parameters, if they come from user input.