To be frank, I never intended this to last too much. I have been (and proudly, like a true hipster) avoiding creating a Facebook account and the Twitter one I only opened because I wanted to explore it as a machine to machine messaging system and never looked back after that idea bombed. So this year I went on Facebook and reactivated my interest in Twitter, now with a more social focus. The reason doesn't really matter, but I'll share it anyway: I had an asshole colleague that refused to talk to me on anything else other than Facebook Messenger. Now we barely talk to each other, anyway. So, what have I learned from this experience? Before I answer that question, I want to tell you about how I thought it would go when I went in.

What I thought going in


I have been keeping this blog since 2007, carefully sharing whatever I thought important, especially since I am a very forgetful person and I needed a place to store valuable tidbits of information. So when Facebook blew up I merely scoffed. Have other people use some sort of weird platform to share what they think; let them post cat videos and share whenever they go to the toilet: I am above this. I carefully study and solve the problem, read the book, research new stuff, link to everything in the information that I think relevant. I have my own template, I control the code on my blog, people can chat with me and others directly, comment on whatever I have done. I can also edit a post and update it with changes that I either learn as I evolve. My posts have permanent links that look like their title, suckers! I really don't need Facebook at all.

And Twitter. Phaw! 140 characters? What is this, SMSes online? If you really have something to say, say it in bulk. It's a completely useless platform. I might take a second look at it and use it as a chat system for the blog, at most (I actually did that for a while, a long time ago). I am not social, I am antisocial, suckers! I really don't need Twitter at all.

There you go. Superior as fuck, I entered the social media having a lot of smug preconceptions that I feel ashamed for. I apologize.

Facebook


So what did I learn from months on Facebook? Nothing. Hah! To be honest, I didn't disrespect Facebook that much to begin with. I had high hopes that once I connect with all my friends I would share of their interesting experiences and projects, we would communicate and collaborate better, we would organize more parties or gettogethers, meet up more frequently if we are in the same area. Be interesting, passionate; you know... social. Instead I got cute animal videos, big pointless images with texts plastered all over them - like this would give more gravitas to bland clichés, pictures of people on vacation or at parties - as if I care about their mugs more than the location, political opinion bile, sexist jokes, driving videos, random philosophical musings, and so on and so on. Oh, I learned a lot from Facebook, most of it being how many stupid and pointless things people do. Hell, I am probably friends with people I don't really know for a good reason, not just because I am an asshole who only thinks about himself!

Not everything is bad, clearly. The messenger is the only widespread method of online communication outside email. I know when people's birthdays are (and what day it is currently). People sometimes post their achievements, link to their blog posts, share some interesting information that they either stumbled upon on the Internet (most of the time) or thought about or did themselves, there are events that I learn about from other people going there, like concerts and software meetings and so on. Oh, and the Unfollow button is a gem, however cowardly it is! However, I am no longer "reading my Facebook", I am scrolling at warp speed. I've developed internal filters for spammy bullshit and most of the time, after going through three days worth of stuff, I have only five or six links that I opened for later, one of them being probably a music video on YouTube. It still takes a huge amount of time sifting through all the shit.

Twitter


What about Twitter? Huge fucking surprise there! Forced to distill the information they share, people on Twitter either share links to relevant content or small bits of their actual thoughts, real time, while they are thinking them. There is not a comfortable mechanism for long conversations, group conferences or complicated Like-like mechanism. You do have a button to like or retweet something, but it's more of a nod towards the author that what they shared is good, not some cog in an algorithm to tell someone what YOU need. More work stuff is being shared, books that have been read and enjoyed, real time reactions to TV or cinema shows, bits of relevant code, all kind of stuff. In fact, very few people that spam Facebook are even active on Twitter. Twitter is less about a person than about the moment; it's more Zen if you want to go that way. You are not friends with folks, you just appreciate what they share. It's less personal, yet more revealing, a side effect that I had not expected. And when you reply to a tweet, you are aware of how public it is and how disassociated from the post you reply to it is. There is no ego trip on posting the most sarcastic comment like on Facebook.

Not everything is rosy there, either. They have a similar Facebooky thing that shows the title and the image/video of a shared link so you can open them directly there. So if I want to emulate the same type of behaviour on Twitter, you can by endlessly posting links to stupid stuff and follow other people who do that. You can Follow whoever you want and that means that if you are exaggerating, you end up with a deluge of posts that you have no chance of getting out of. I still haven't gotten used to the hashtag thingie. I only follow people and I only use the default Twitter website, so I am not an "advanced user", but I can tell you that after three days worth of Twitter posts that I have missed, I open around 50 links that I intend to follow up on.

So?


Some of the mental filters developed apply to both situations. The same funny ha-ha video that spams the Facebook site can be ignored just as well on the Twitter page as well. Big font misspelled or untranslatable text smacked on top of a meaningless picture is ignored by tradition, since it looks like a big ad I already have a trained eye for from years of browsing the web before ad blockers were invented.

Some of the opinion pieces are really good and I wouldn't have had the opportunity to read them if all I was looking for was news sites and some RSS feed, yet because of the time it takes to find them, I get less time in which I can pay attention to them. I catch myself feeling annoyed with the length of a text or skipping paragraphs, even when I know that those paragraphs are well researched pieces of gold. I feel like I still need to train myself to focus on what is relevant, yet I am so fucking unwilling to let go of the things that are not.

With tweaking, both platforms may become useful. For example one can unfollow all his friends on Facebook, leaving only the messaging and the occasional event and birthday notification to go through. It's a bit radical, but you can do it. I haven't played with the "Hide post (show fewer posts like this)" functionality, it could be pretty cool if it works. Twitter doesn't have a good default filtering system, though, even if I get more useful information from it. That doesn't mean that specialized Twitter clients don't have all kinds of features I have not tried. There is also the software guy way: developing your own software to sift through the stuff. One idea I had, for example, was something that uses OCR to restore images and videos to text.

Bottom line: Facebook, in its raw form, it's almost useless to me. I remember some guy making fun of it and he was so right: "Facebook is not cool. Parents are on it!". You ask someone to connect with you, which is a two directional connection, even if they couldn't care less about you, then you need to make an effort to remove the stuff they just vomit online. The graphical features of the site make it susceptible to graphical spam - everything big and flashy and lacking substance. Twitter is less so and I have been surprised to see how much actual usable information is shared there. The unidirectional following system also leads to more complex data flow and structure, not just big blobs of similar people sharing base stuff that appeals to all.

But hey! "What about you, Siderite? What are you posting on Facebook and Twitter?" You'll just have to become friends and follow me to see, right? Nah, just kidding. My main content creation platform is still Blogger and I am using this system called If This Then That to share any new post on both social networks. Sometimes I read some news or I watch some video and I use the Facebook sharing buttons to express my appreciation for the content without actually writing anything about it and occasionally I retweet something that I find really spectacular on Twitter. Because of my feelings towards the two systems, even if I find an interesting link on Tweeter, I just like it then share it on Facebook if I don't feel it's really something. So, yeah, I am also spamming more on Facebook than on Twitter.

What else?


I haven't touched Google+, which I feel is a failed social platform and only collects various YouTube comments without accurately conveying my interests. I also haven't spoken about LinkedIn, which I think is a great networking platform, but I use it - as I believe it should be - exclusively for promoting my work and finding employment. I've used some strong language above, not because I am passionate about the subject but because I am not. I find it's appropriate though and won't apologize for it. I couldn't care less if people go or don't go on social networks and surely I am not an trendsetter so that Zuckerberg would worry. I only shared my own experience.

For the future I will probably continue to use both systems unless I finally implement one of the good ideas that would allow me to focus more on what matters, thus renouncing parts of my unhealthy habits. I am curious on how this will evolve in the near future and after I leave my current hiatus and go look for employment or start my own business.

The focus of Writing Tools is more on the journalist than on the novel writer. Of course there is a lot of overlap, but some of the tools there may feel either not relevant or truly gold, since book writers would not write about them so easily.

Roy Peter Clark lists the 50 tools (55 if you have the revised edition) in four categories:
  • Nuts and Bolts - about the use of language: verbs, adverbs, phrase length, punctuation and so forth
  • Special Effects - various creative ideas that give inspiration and direction to writing
  • Blueprints - overall planning
  • Useful Habits - various solutions for common problems or for improvement
I will list the entire 50 entries at the end of the review.

What I liked about the book is that it is direct, to the point, listing the tools so that you can always pick up the book and refresh your memory on how to use them. Being so many, it is impossible to just skim through the book, unless you already know and employ most of the ideas there. I feel like I have to practice, practice, practice in order to absorb everything there is inside the material. It's not a huge thing, though, like something Kendall Haven might have written, but still it is packed with information.

I am unable to understand if the source material is still under copyright or maybe Clark made it available for free. The book is sold on Amazon, but you can also read it as PDF online or listen to it freely on iTunes.

Now, for a list of the tools, something that I have shamelessly stolen from another review, because I am lazy:
  • Part One: Nuts and Bolts
    • Begin sentences with subjects and verbs.
    • Order words for emphasis.
    • Activate your verbs.
    • Be passive-aggressive.
    • Watch those adverbs.
    • Take it easy on the -ings.
    • Fear not the long sentence.
    • Establish a pattern, then give it a twist.
    • Let punctuation control pace and space.
    • Cut big, then small.
  • Part Two: Special Effects
    • Prefer the simple over the technical.
    • Give key words their space.
    • Play with words, even in serious stories.
    • Get the name of the dog.
    • Pay attention to names.
    • Seek original images.
    • Riff on the creative language of others.
    • Set the pace with sentence length.
    • Vary the lengths of paragraphs.
    • Choose the number of elements with a purpose in mind.
    • Know when to back off and when to show off.
    • Climb up and down the ladder of abstraction.
    • Tune your voice.
  • Part Three: Blueprints
    • Work from a plan.
    • Learn the difference between reports and stories.
    • Use dialogue as a form of action.
    • Reveal traits of character.
    • Put odd and interesting things next to each other.
    • Foreshadow dramatic events and powerful conclusions.
    • To generate suspense, use internal cliffhangers.
    • Build your work around a key question.
    • Place gold coins along the path.
    • Repeat, repeat, and repeat.
    • Write from different cinematic angles.
    • Report and write for scenes.
    • Mix narrative modes.
    • In short works, don’t waste a syllable.
    • Prefer archetypes to stereotypes.
    • Write toward an ending.
  • Part Four: Useful Habits
    • Draft a mission statement for your work.
    • Turn procrastination into rehearsal.
    • Do your homework well in advance.
    • Read for both form and content.
    • Save string.
    • Break long projects into parts.
    • Take an interest in all crafts that support your work.
    • Recruit your own support group.
    • Limit self-criticism in early drafts.
    • Learn from your critics.
    • Own the tools of your craft.

I have been a professional in the IT business for a lot of years, less if you consider just software development, more if you count that my favorite activity since I was a kid was to mess with a computer or another. I think I know how to develop software, especially since I've kind of built my career on trying new places and new methods for doing that. And now people come to me and ask me: "Can I learn too? Can you teach me?". And the immediate answer is yes and no (heh! Learnt from the best politicians that line) Well, yes because I believe anyone who actually wants to learn can and no because I am a lousy teacher. But wait a minute... can't I become one?

You may think that it is easy to remember how it was when I was a code virgin, when I was writing Basic programs in a notebook in the hope that some day my father will buy me a computer, but it's not. My brain has picked up so many things that now they are applied automatically. I may not know what I know, but I know a lot and I am using it at all times. A few weeks ago I started thinking about these things and one of the first ideas that came to me was FizzBuzz! A program that allegedly people who can't program simple can't... err... program. Well, I thought, how would I write this best? How about worst? I even asked my wife and she gave me an idea that had never occurred to me, like not using the modulo function to determine divisibility.

And it dawned on me. To know if your code is good you need to know exactly what that code has to do. In other words, you can't program without having an idea on how to use or test it afterwards. You have to think about all the other people that would be stumbling unto your masterwork: other developers, for example, hired after you left the company, need to understand what they are looking at. You need to provide up to date and clear documentation to your users, as well. You need to handle all kinds of weird situations that your software might be subjected to. To sum it up: as a good developer you need to be a bit of all the people on the chain - users, testers, documenters, managers, marketers, colleagues - and to see the future as well. After all, you're an expert.

Of course, sketches like the one above are nothing but caricatures of people from the viewpoint of other people who don't understand them. After all, good managers need to be a little of everything as well. If you think about it, to be good at anything means you have to understand a little of everybody you work with and do your part well - exactly the opposite of specialization, the solution touted as solving every problem in the modern world. Anyway, enough philosophy. We were talking programming here.

What I mean to say is that for every bit of our craft, we developers are doing good things for other people. We code so that the computer does the job well, but we are telling it to do things that users need, we write concisely yet clear so that other developers can work from where we leave off, we write unit tests to make sure what we do is what we mean and ease the work of people who need to manually check that, we comment the code so that anyone can understand at a glance what a method does and maybe even automate the creation of documents explaining what the software does. And we draw lines in a form of a kitten so that marketers and managers sell the software - and we hate it, but we do it anyway.

So I ask, do we need to learn to write programs all over again? Because, to be frank, coders today write in TDD style because they think it's cutting edge, not that they are doing it for someone; they work in agile teams not because they know everybody will get a better understanding of what they are doing and prevent catastrophic crashes caused by lack of vision, but because they feel it takes managers off their backs and they can do their jobs; they don't write comments for the documentation team, but because they fear their small attention span might make them forget what the hell they were doing; they don't write several smaller methods instead of a large one because they believe in helping others read their code, but because some new gimmick tells them they have too much cyclomatic complexity. And so on and so on.

What if we would learn (and teach) that writing software is nothing but an abstraction layer thrown over helping all kinds of people in need and that even the least rockstar ninja superhero developer is still a hero if they do their job right? What if being a good cog in the machine is not such a bad thing?

While writing this I went all over the place, I know, and I didn't even touch what started me thinking about it: politics and laws. I was thinking that if we define the purpose of a law when we write it and package them together, anyone who can demonstrate that the effect is not the desired one can remove the law. How grand would that be? To know that something is applied upon you because no one could demonstrate that it is bad or wrong or ineffective.

We do that in software all the time, open software, for example, but also the internal processes in a programming shop designed to catch flaws early and to ensure people wrote things how they should have. Sometimes I feel so far removed from "the real world" because what I am doing seems to make more sense and in fact be more real than the crap I see all around me or on the media. What if we could apply this everywhere? Where people would take responsibility individually, not in social crowds? Where things would be working well not because a lot of people agree, but because no one can demonstrate they are working bad? What if the world is a big machine and we need to code for it?

Maybe learning to code is learning to live! Who wouldn't want to teach that?

During one revamp of the blog I realized that I didn't have images for some of my posts. I had counted pretty much on the Blogger system that provides a post.thumbnailUrl post metadata that I can use in the display of the post, but the url is not always there. Of course if you have a nice image in the post somewhere prominently displayed, the thumbnail URL will be populated, but what if you have a video? Surprisingly, Blogger has a pretty shitty video to thumbnail mechanism that prompted me to build my own.

So the requirements would be: get me the image representing a video embedded in my page, using Javascript only.

Well, first of all, videos can be actual video tags, but most of the time they are iframe elements coming from a reliable global provider like YouTube, Dailymotion, Vimeo, etc, and all the information available is the URL of the display frame. Here is the way to get the thumbnail for these scenarios:

YouTube


Given the iframe src value:

// find youtube.com/embed/[videohash] or youtube.com/embed/video/[videohash]
var m = /youtube\.com\/embed(?:\/video)?\/([^\/\?]+)/.exec(src);
if (m) {
// the thumbnail url is https://img.youtube.com/vi/[videohash]/0.jpg
imgSrc = 'https://img.youtube.com/vi/' + m[1] + '/0.jpg';
}

If you have embeds in the old object format, it is best to replace them with the iframe one. If you can't change the content, it remains your job to create the code to give you the thumbnail image.

Dailymotion


Given the iframe src value:

//find dailymotion.com/embed/video/[videohash]
var m=/dailymotion\.com\/embed\/video\/([^\/\?]+)/.exec(src);
if (m) {
// the thumbnail url is at the same URL with `thumbnail` replacing `embed`
imgSrc=src.replace('embed','thumbnail');
}

Vimeo


Vimeo doesn't have a one URL thumbnail format that I am aware of, but they have a Javascript accessible API.

// find vimeo.com/video/[videohash]
m=/vimeo\.com\/video\/([^\/\?]+)/.exec(src);
if (m) {
// set the value to the videohash initially
imgSrc=m[1];
$.ajax({
//call the API video/[videohash].json
url:'https://vimeo.com/api/v2/video/'+m[1]+'.json',
method:'GET',
success: function(data) {
if (data&&data.length) {
// and with the data replace the initial value with the thumbnail_medium value
replaceUrl(data[0].thumbnail_medium,m[1]);
}
}
});
}

In this example, the replaceUrl function would look for img elements to which the videohash value is attached and replace the url with the correct one, asynchronously.

TED


I am proud to announce that I was the one pestering them to make their API available over Javascript.

// find ted.com/talks/[video title].html
m=/ted\.com\/talks\/(.*)\.html/.exec(src);
if (m) {
// associate the video title with the image element
imgSrc=m[1];
$.ajax({
// call the oembed.json?url=frame_url
url:'https://www.ted.com/services/v1/oembed.json?url='+encodeURIComponent(src),
method:'GET',
success: function(data) {
// set the value of the image element asynchronously
replaceUrl(removeSchemeForHttpsEnabledSites(data.thumbnail_url),m[1]);
}
});
return false;
}

video tags


Of course there is no API to get the image from an arbitrary video URL, but the standard for the video tag specifies a poster attribute that can describe the static image associated with a video.

// if the element is a video with a poster value
if ($(this).is('video[poster]')) {
// use it
imgSrc=$(this).attr('poster');
}

and has 0 comments
The book was nothing if not captivating, its pace much better than for the Magicians trilogy, but as in those books, it was really really difficult to empathize with any of the characters.

The story in Codex is about this investment banker who is having the first vacation in years, actually a small transition time between switching from his US job to a London based one. This makes him feel disconnected and somehow gets tangled in a project to arrange the library of a very wealthy family. The problem with this character is that he doesn't seem to chose anything. Things just happen to him, kind of like with Quentin in the Magicians, and he goes with them, only to get disappointed or surprised at the end. His friends, the people he randomly meets, even his adversaries appear at the exact time when the story requires them, making the book feel like a string of unlikely happenstances a rather aimless character just stumbles through.

There are some interesting parallels in the book, analogies between the beginning of romantic literature and the emergence of computer game fantasy, and probably the literary and historical details in the book hide some deeper meaning as well, but it's Lev Grossman's infuriatingly detached, almost dreamlike perspective that made me not care about it at all. Strangely, all the literary research going on in the book and the altered mood made me think of House of Leaves, only that was orders of magnitude weirder and better written.

As for the ending, I think I can safely say now that it's typical Grossman: the main character becomes aware of the delusions he was living under, both relating to his goals and the people around him. The veil gets lifted and the world goes back to the usual confusing pointless drag that it is for most of us. The author doesn't seem to care about the need of the reader for a happy ending, and I would normally applaud that, yet to use a depressingly realistic ending to a story that felt torn out of a night's dream seems a bit pointless to me.

Bottom line: I actually enjoyed it better than The Magicians, perhaps because it was shorter, better paced and I could relate to the main character a bit more. However, it is not something I would recommend to people. It felt too much like describing a man during a heatstroke, always dazed and confused, spinning wildly out of control of the things happening around him, a hapless victim of his immature feelings and a situation he is out of his depth in.

I came upon a StackOverflow question today that sounded plain silly to me. In it someone was complaining that parsing a command line like "x\" -y returns a single argument, not two. And that is ridiculous, since the operating system doesn't do that.

Just to prove myself right (because I love being right) I created a batch file that displays all command line parameters:
@ECHO OFF 
SET counter=1
:loop
IF "%1"=="" EXIT
ECHO %counter% %1
SET /A counter=counter+1
SHIFT
GOTO loop

I ran the batch file with the command line supplied in the SO question: -p -z "E:\temp.zip" -v "f:\" -r -o -s –c and the result was
1 -p
2 -z
3 "E:\temp.zip"
4 -v
5 "f:\"
6 -r
7 -o
8 -s
9 –c
See? I was right! The command line is properly parsed. But just to be sure, I created a .NET console application:
static void Main(string[] args)
{
for (var i=0; i<args.Length; i++)
{
Console.WriteLine(i + " " + args[i]);
}
}
and the result was... different!
0  -p
1 -z
2 E:\temp.zip
3 -v
4 f:" -r -o -s -c
Never would I have imagined that .NET console applications would do different things from system applications, especially since they are both made by Microsoft.

Investigating the problem, I found a page that explained the rules of parsing command line arguments. It was for C++, but it applied perfectly. Apparently the caret (^) is treated just as any other character (not like by the operating system that treats it as an escape character) and a quote preceded by a backslash is considered an ordinary character as well (not like the operating system that ignores it).

So, how do I get the command line the same way the operating system does? First of all I need the raw unprocessed command line. I get that using Environment.CommandLine. Then I need to split it. Of course, I can make my own code, but I want to use the same stuff as the operating system - in this case Windows, we are not discussing .NET Core or Mono here - so I will be "Pinvoking" the Windows CommandLineToArgvW function.

And, of course, it didn't work. What I did here was basically recreating the Environment.GetCommandLineArgs method, which returns the exact same result as the args array!

Now that I had already gone through the rabbit hole, I got to this very informative link about it: How Command Line Parameters Are Parsed. In it, you may find the very aptly named chapter Everyone Parses Differently which shows that there are even differences between how C and VB programs parse the command line.

Bottom line: while you may be able to get the command line from the Environment class, there is no "standard" for parsing command line arguments, instead each compiler and operating system version implements their own. Consequently, I suggest that the only way to be consistent in how you parse command line arguments is to parse them yourself.

I had this crazy idea that I could make each word on my page come alive. The word "robot" would walk around the page, "explosion" would explode, "rotate" would rotate, color words would appear in the color they represent, no matter how weird named like OliveDrab , Chocolate , Crimson , DeepPink , DodgerBlue and so on, "radioactive" would pulse green, "Siderite" would appear in all its rocking glory and so on. And so I did!

The library is on GitHub and I urge you to come and bring your own ideas. Every effect that you see there is an addon that can be included or not in your setup.



Also see directly on GitHub pages.








Almost a month ago I got started being active on StackOverflow, a web site dedicated to answering computer related questions. It quickly got addictive, but the things that I found out there are many and subtle and I am happy with the experience.

The first thing you learn when you get into it is that you need to be fast. And I mean fast! Not your average typing-and-reading-and-going-back-to-fix-typos speed, but full on radioactive zombie attack typing. And without typos! If you don't, by the time you post your contribution the question would have been answered already. And that, in itself, is not bad, but when you have worked for minutes trying to get code working, looking good, being properly commented, taking care of all test cases, being effective, being efficient and you go there and you find someone else did the same thing, you feel cheated. And I know that my work is valid, too, and maybe even better than the answers already provided (otherwise I feel dumb), but to post it means I just reiterate what has been said before. In the spirit of good sportsmanship, I can only upvote the answer I feel is the best and eventually comment on what I think is missing. Now I realize that whenever I do post the answer first there are a lot of people feeling the same way I just described. Sorry about that, guys and gals!

The second thing you learn immediately after is that you need to not make mistakes. If you do, there will be people pointing them out to you immediately, and you get to fix them, which is not bad in itself, however, when you write something carelessly and you get told off or, worse, downvoted, you feel stupid. I am not the smartest guy in the world, but feeling stupid I don't like. True, sometimes I kind of cheat and post the answer as fast as possible and I edit it in the time I know the question poster will come check it out but before poor schmucks like me wanted to give their own answers. Hey, those are the rules! I feel bad about it, but what can you do?

Sometimes you see things that are not quite right. While you were busy explaining to the guy what he was doing wrong, somebody comes and posts the solution in code and gets the points for the good answer. Technically, he answered the question; educationally, not so much. And there are lot of people out there that ask the most silly of questions and only want quick cut-and-pastable answers. I pity them, but it's their job, somewhere in a remote software development sweat shop where they don't really want to work, but where the money is in their country. Luckily, for each question there are enough answers to get one thinking in the right direction, if that is what they meant to do.

The things you get afterwards become more and more subtle, yet more powerful as well. For example it is short term rewarding to give the answer to the question well and fast and first and to get the points for being best. But then you think it over and you realize that a silly question like that has probably been posted before. And I get best answer, get my five minutes of feeling smart for giving someone the code to add two values together, then the question gets marked as a duplicate. I learned that it is more satisfying and helpful to look first for the question before providing an answer. And not only it is the right thing to do, but then I get out of my head and see how other people solved the problem and I learn things. All the time.

The overall software development learning is also small, but steady. Soon enough you get to remember similar questions and just quickly google and mark new ones as duplicates. You don't get points for that, and I think that is a problem with StackOverflow: they should encourage this behavior more. Yet my point was that remembering similar questions makes you an expert on that field, however simple and narrow. If you go to work and you see the same problem there, the answer just comes off naturally, enforced by the confidence it is not only a good answer, but the answer voted best and improved upon by an army of passionate people.

Sometimes you work a lot to solve a complex problem, one that has been marked with a bounty and would give you in one shot maybe 30 times more points than getting best answer on a regular question. The situation is also more demanding, you have to not only do the work, but research novel ways of doing it, see how others have done it, explaining why you do things all the way. And yet, you don't get the bounty. Either it was not the best answer, or the poster doesn't even bother to assign the bounty to someone - asshole move, BTW, or maybe it is not yet a complete answer or even the poster snubs you for giving the answer to his question, but not what he was actually looking for. This is where you get your adrenaline pumping, but also the biggest reward. And I am not talking points here anymore. You actually work because you chose to, in the direction that you chose, with no restrictions on method of research or implementation and, at the end, you get to show off your work in an arena of your true peers that not only fight you, but also help you, improve on your results, point out inconsistencies or mistakes. So you don't get the points. Who cares? Doing great work is working great for me!

There is more. You can actually contribute not by answering questions, but by reviewing other people's questions, answers, comments, editing their content (then getting that edit approved by other reviewers) and so on. The quality of my understanding increases not only technically, but I also learn to communicate better. I learn to say things in a more concise way, so that people understand it quicker and better. I edit the words of people with less understanding of English and not only improve my own skills there, but help them avoid getting labelled "people in a remote software development sweat shop" just because their spelling is awful and their name sounds like John Jack or some other made up name that tries to hide their true origins. Yes, there is a lot of racism to go around and you learn to detect it, too.

I've found some interesting things while doing reviews, mostly that when I can't give the best edit, I usually prefer to leave the content as is, then before I know the content is subpar I can't really say it's OK or not OK, so I skip a lot of things. I just hope that people more courageous than me are not messing things up more than I would have. I understood how important it is for many people to do incremental improvements on something in order for it to better reach a larger audience, how important is that biases of language, race, sex, education, religion or psychology be eroded to nothing in order for a question to get the deserved answer.

What else? You realize that being "top 0.58% this week" or "top 0.0008% of all time" doesn't mean a lot when most of the people on StackOverflow are questioners only, but you feel a little better. Funny thing, I've never asked a question there yet. Does it mean that I never did anything cutting edge or that given the choice between asking and working on it myself I always chose the latter?

Most importantly, I think, I've learned a few things about myself. I know myself pretty well (I mean, I've lived with the guy for 39 years!) but sometimes I need to find out how I react in certain situations. For example I am pretty sure that given the text of a question with a large bounty, I gave the most efficient, most to the point, most usable answer. I didn't get the points, instead they went to a guy that gave a one liner answer that only worked in a subset of the context of the original question, which happened to be the one the poster was looking for. I fumed, I roared, I raged against the dying of the light, but in the end I held on to the joy of having found the answer, the pleasure of learning a new way of solving the same situation and the rightness of working for a few hours in the company of like-minded people on an interesting and challenging question. I've learned that I hate when people downvote me with no explanation even more than downvoting me with a good reason, that even if I am not always paying attention to detail, I do care a lot when people point out I missed something. And I also learned that given the choice between working on writing a book and doing what I already do best, I prefer doing the comfortable thing. Yeah, I suck!

It all started with a Tweet that claimed the best method of learning anything is to help people on StackOverflow who ask questions in the field. So far I've stayed in my comfort zone: C#, ASP.NET, WPF, Javascript, some CSS, but maybe later on I will get into some stuff that I've always planned on trying or even go all in. Why learn something when you can learn everything?!

My blog is hosted by Blogger, a Google site, and usually they are quite good, however this month they announced a change that, frankly, I think will hurt them in the short run because it was so sudden and leaves not only blog owners, but Blogger themselves unprepared. The news is about forcefully enabling Secure Hyper Text Transfer Protocol support for all free Blogspot sites. BTW, the link above that explains why Blogger forces HTTPS... doesn't work on HTTPS, which shows me a nice red error while editing this post.

The underlying idea is good: move everything to HTTPS, no matter how relevant it is for people to be safe and anonymous while reading my blog :). In theory, everything should be working the same as with HTTP, with some small issues that are easily fixed. In practice, we are talking about templates that people have installed without modifying or scripts that one can only find on HTTP sites or images and other resources that can only be found on unsecured web sites. For example, Google's default blog bar itself is causing an error in the console because it is trying to search the blog with an HTTP URL, even if the bar frame is loaded from an HTTPS location.

I had several problems:
  • The PGN Viewer that I use for chess games is only found on an HTTP site, therefore Google Chrome blocks loading those scripts when in HTTPS. I had to copy stuff in Google Drive and change the PGN Viewer scripts to use alternate URLs when under HTTPS and host files from Google Drive. I hope it will not reach some hosting limit and randomly fail.
  • Many thumbnails loaded for the related posts list and the blog main page are also loaded via HTTP, causing mostly annoying errors in the console. I tried to fix it programatically, but it relies on knowing which sites support HTTPS and which don't.
  • Videos, pictures and resources inside the blog posts themselves! I can't possibly change all the posts on my blog. There are over 1300 separate posts. While I don't have any posts that load remote scripts through HTTPS, it is still damn scary because I can't manually check everything. It would take me forever!
  • Caching. It is a myth that HTTPS requests cannot be cached, but it does depend on the server headers. If the HTTPS servers that I am blindly connecting to are misconfigured, people are going to perceive it as slowing down. Also, there is an interesting post that explains why loading scripts from third parties is breaking HTTPS security.

With this in mind, please help me test the blog with HTTPS and let me know if you find any issues with it. I've done what I could, but I am a developer, not a tester, so let me know, OK? Thanks!

While it is simple for blog owners to use a small Javascript in order to force users to go to the HTTP URL, not allowing this from the get go is a pretty ballsy, but asshole move. Will it make the internet safer? We'll just have to see.

I've noticed an explosion of web sites that try to put all of their stuff on a single page, accessible through nothing else than scrolling. Parallax effects, dynamic URL changes as you scroll down, self arranging content based on how much you have scrolled, videos that start and stop based on where they are placed in the viewbox, etc. They're all the rage now, like web versions of pop-up books. And, as anything that pops up at you, they are annoying! I know creativity in the design world means copying the hell out of whoever is more fashionable, but I really really really would want people to stop copying this particular Facebook++ type, all slimy fingers on touchscreens abomination.

Take a look at inc.com, for example. Reading about brain hacking and scrolling down I get right into Momofuku, whatever that is, and self playing videos. It's spam, that's what it is. I am perfectly capable of finding links and clicking (or tapping, whatever the modern equivalent of pressing Enter after a few Tab keys is now) to follow the content I am interested in. What I do NOT want is for crappy design asswipes to shove their idea of interesting content down my throat, eyes, ears or any other body organs. Just quit it!

If you are not convinced, read this article that explains how parallax scrolling web sites have become mainstream and gives two different links that list tens of "best web sites" using this design method. They are all obnoxious, slow to load, eye tiring pieces of crap. Oh look, different parts of the same page move at different speeds! How cool, now I have to scroll up and down just in order to be able to pay attention to them all, even if they are at the same bloody place!

Am I the only one who feels that way? Am I too old to understand what the cool kids like nowadays or is this exactly what I think it is: another graphical gimmick that values form over substance?

and has 0 comments
I will be reviewing all three books in The Magicians trilogy, by Lev Grossman, as they are one complete story with a beginning and an end, as well as an overarching moral. My review of the first book only, from the perspective of someone who enjoys the (very different!!) TV show, stands.

To understand The Magicians you need to understand who Lev Grossman is: a book critic for Time magazine. As such, he must have had a very strange experience trying to write after probably demolishing a lot of other writers for their lack of skill or overuse of tropes. Therefore some sort of alarm bells must sound when he undertakes to writing a "trilogy of fantasy books", a concept that is a meta-trope in itself. I believe he attempted to break the mould of the genre by using flawed every day characters on a journey that is less heroic as closer to real life: random things happening to you, bad things which you can't avoid, defeat or change, even if you try, which sometimes you don't, because you are scared or bored or selfish. At the end of said journey you are altered, but is it a better you, or just an old damaged version of the dreamer kid you started out as?

For this belief alone, I say that the books were decent because they achieved their purpose. The topics approached are more adult, the characters different from the plethora of fantasy heroes, the elements that seem to randomly appear get resolved somewhere in the far future rather than in the confined timeframe of an "episode". I loved the concept and therefore I liked the books.

However, that doesn't mean everything is rosy in Fillory. The characters are barely built up, the reader starves for some understanding of why people do the things they do or even think or feel in a certain way. Important influences such as home, childhood, parents, siblings, good friends are being ignored and abandoned, while the action of the people in the books are more often described than explained. Satirical references to well known works in the fantasy and science fiction genres pepper the books, but those stories at least attempted some consistency, while The Magicians, especially the Fillory part, feels like an LSD trip of an autistic dork.

The worst sin the books commit, and that is in direct conflict with what I think their goal was, is to make the characters almost impossible to empathize with. All of them move through the story like pieces on a board, almost indifferent to their surroundings and the people that accompany them and mostly annoyed. Whatever deep feelings they do have come out as quirky and obsessive, rather than real. It was with great dissatisfaction that I realized that the character I most identified with and believed real was The Beast, which is a terrible villain for most of the first half of the story. People died, were hurt, tortured and violated, resurrected and I couldn't care less. Mythological monsters and weird random creations were epically battling at the end of the world, and I was just bored, waiting for something interesting to happen.

Bottom line: good idea, bad implementation. Interesting to read, but hardly something that I would recommend as good writing.

Update 29 August 2017 - Version 3.0.4: The extension has been rewritten in EcmaScript6 and tested on Chrome, Firefox and Opera.

Update 03 March 2017 - Version 2.9.3: added a function to remove marketing URLs from all created bookmarks. Enable it in the Advanced settings section. Please let me know of any particular parameters you need purged. So far it removes utm_*, wkey, wemail, _hsenc, _hsmi and hsCtaTracking.

Update 26 February 2017: Version (2.9.1): added customizing the URL comparison function. People can choose what makes pages different in general or for specific URL patterns
Update 13 June 2016: Stable version (2.5.0): added Settings page, Read Later functionality, undelete bookmarks page and much more.
Update 8 May 2016: Rewritten the extension from scratch, with unit testing.
Update 28 March 2016: The entire source code of the extension is now open sourced at GitHub.

Whenever I read my news, I open a bookmark folder containing my favorite news sites, Twitter, Facebook, etc. I then proceed to open new tabs for each link I find interesting, closing the originating links when I am done. Usually I get a number of 30-60 open tabs. This wreaks havoc on my memory and computer responsiveness. And it's really stupid, because I only need to read them one by one. In the end I've decided to fight my laziness and create my first browser extension to help me out.

The extension is published here: Siderite's Bookmark Explorer and what it does is check if the current page is found in any bookmark folder, then allow you to go forward or backwards inside that folder.

So this is my scenario on using it:
  1. Open the sites that you want to get the links from.
  2. Open new tabs for the articles you want to read or YouTube videos you want to watch,etc.
  3. Bookmark all tabs into a folder.
  4. Close all the tabs.
  5. Navigate to the bookmark folder and open the first link.
  6. Read the link, then press the Bookmark Navigator button and then the right arrow. (now added support for context menu and keyboard shortcuts)
  7. If you went too far by mistake, press the left arrow to go back.

OK, let's talk about how I did it. In order to create your own Chrome browser extension you need to follow these steps:

1. Create the folder


Create a folder and put inside a file called manifest.json. It's possible structure is pretty complex, but let's start with what I used:
{
"manifest_version" : 2,

"name" : "Siderite's Bookmark Explorer",
"description" : "Gives you a nice Next button to go to the next bookmark in the folder",
"version" : "1.0.2",

"permissions" : [
"tabs",
"activeTab",
"bookmarks",
"contextMenus"
],
"browser_action" : {
"default_icon" : "icon.png",
"default_popup" : "popup.html"
},
"background" : {
"scripts" : ["background.js"],
"persistent" : false
},
"commands" : {
"prevBookmark" : {
"suggested_key" : {
"default" : "Ctrl+Shift+K"
},
"description" : "Navigate to previous bookmark in the folder"
},
"nextBookmark" : {
"suggested_key" : {
"default" : "Ctrl+Shift+L"
},
"description" : "Navigate to next bookmark in the folder"
}
}
}

The manifest version must be 2. You need a name, a description and a version number. Start with something small, like 0.0.1, as you will want to increase the value as you make changes. The other thing is that mandatory is the permissions object, which tells the browser what Chrome APIs you intend to use. I've set there activeTab, because I want to know what the active tab is and what is its URL, tabs, because I might want to get the tab by id and then I don't get info like URL if I didn't specify this permission, bookmarks, because I want to access the bookmarks, and contextMenus, because I want to add items in the page context menu. More on permissions here.

Now, we need to know what the extension should behave like.

If you want to click on it and get a popup that does stuff, you need to specify the browser_action object, where you specify the icon that you want to have in the Chrome extensions bar and/or the popup page that you want to open. If you don't specify this, you get a default button that does nothing on click and presents the standard context menu on right click. You may only specify the icon, though. More on browserAction here.

If you want to have an extension that reacts to background events, monitors URL changes on the current page, responds to commands, then you need a background page. Here I specify that the page is a javascript, but you can add HTML and CSS and other stuff as well. More on background here.

Obviously, the files mentioned in the manifest must be created in the same folder.

The last item in the manifest is the commands object. For each command you need to define the id, the keyboard shortcut (only the 0..9 and A..Z are usable unfortunately) and a description. In order to respond to commands you need a background page as shown above.

2. Test the extension


Next you open a Chrome tab and go to chrome://extensions, click on the 'Developer mode' checkbox if it is not checked already and you get a Load unpacked extension button. Click it and point the following dialog to your folder and test that everything works OK.

3. Publish your extension


In order to publish your extension you need to have a Chrome Web Store account. Go to Chrome Web Store Developer Dashboard and create one. You will need to pay a one time 5$ fee to open it. I know, it kind of sucks, but I paid it and was done with it.

Next, you need to Add New Item, where you will be asked for a packed extension, which is nothing but the ZIP archive of all the files in your folder.

That's it.

Let's now discuss actual implementation details.

Adding functionality to popup elements


Getting the popup page elements is easy with vanilla Javascript, because we know we are building for only one browser: Chrome! So getting elements is done via document.getElementById(id), for example, and adding functionality is done via elem.addEventListener(event,handler,false);

One can use the elements as objects directly to set values that are related to those elements. For example my prev/next button functionality takes the URL from the button itself and changes the location of the current tab to that value. Code executed when the popup opens sets the 'url' property on the button object.

Just remember to do it when the popup has finished loading (with document.addEventListener('DOMContentLoaded', function () { /*here*/ }); )

Getting the currently active tab


All the Chrome APIs are asynchronous, so the code is:
chrome.tabs.query({
'active' : true,
'lastFocusedWindow' : true
}, function (tabs) {
var tab = tabs[0];
if (!tab) return;
// do something with tab
});

More on chrome.tabs here.

Changing the URL of a tab


chrome.tabs.update(tab.id, {
url : url
});

Changing the icon in the Chrome extensions bar


if (chrome.browserAction) chrome.browserAction.setIcon({
path : {
'19' : 'anotherIcon.png'
},
tabId : tab.id
});

The icons are 19x19 PNG files. browserAction may not be available, if not declared in the manifest.

Get bookmarks


Remember you need the bookmarks permission in order for this to work.
chrome.bookmarks.getTree(function (tree) {
//do something with bookmarks
});

The tree is an array of items that have title and url or children. The first tree array item is the Bookmarks Bar, for example. More about bookmarks here.

Hooking to Chrome events


chrome.tabs.onUpdated.addListener(refresh);
chrome.tabs.onCreated.addListener(refresh);
chrome.tabs.onActivated.addListener(refresh);
chrome.tabs.onActiveChanged.addListener(refresh);
chrome.contextMenus.onClicked.addListener(function (info, tab) {
navigate(info.menuItemId, tab);
});
chrome.commands.onCommand.addListener(function (command) {
navigate(command, null);
});

In order to get extended info on the tab object received by tabs events, you need the tabs permission. For access to the contextMenus object you need the contextMenus permission.

Warning: if you install your extension from the store and you disable it so you can test your unpacked extension, you will notice that keyboard commands do not work. Seems to be a bug in Chrome. The solution is to remove your extension completely so that the other version can hook into the keyboard shortcuts.

Creating, detecting and removing menu items


To create a menu item is very simple:
chrome.contextMenus.create({
"id" : "menuItemId",
"title" : "Menu item description",
"contexts" : ["page"] //where the menuItem will be available
});
However, there is no way to 'get' a menu item and if you try to blindly remove a menu item with .remove(id) it will throw an exception. My solution was to use an object to store when I created and when I destroyed the menu items so I can safely call .remove().

To hook to the context menu events, use chrome.contextMenus.onClicked.addListener(function (info, tab) { }); where info contains the menuItemId property that is the same as the id used when creating the item.

Again, to access the context menu API, you need the contextMenus permission. More about context menus here.

Commands


You use commands basically to define keyboard shortcuts. You define them in your manifest and then you hook to the event with chrome.commands.onCommand.addListener(function (command) { });, where command is a string containing the key of the command.

Only modifiers, letters and digits can be used. Amazingly, you don't need permissions for using this API, but since commands are defined in the manifest, it would be superfluous, I guess.

That's it for what I wanted to discuss here. Any questions, bug reports, feature requests... use the comments in the post.

Here is a very informative presentation about the internals of await/async, which makes things a lot clearer when you are trying to understand what the hell is going on there:

and has 0 comments
I'm seeing a pattern here already. After The Expanse, which surprised me with how good the TV show was compared to the books, now The Magicians does the same. There is something to be said about hindsight and when you are adapting a series of books for the small screen you get a lot of resources that the writer himself did not have when he began. I have a feeling that many things that happened in the first season of the TV series will not even happen in the second book. The plot has been changed as well, quite a lot, to the point that now I will be reviewing a book that has at most half of it to do with what you might have seen on TV and another half that you probably won't see even in the future.

In The Magicians, the first book in the series with the same name, Lev Grossman describes a pretty dorky character suddenly finding that magic is real and he is a magician. But while it starts like the typical fantasy story, it continues quite differently, with a school of magic that doesn't seem to care about its students much, a way of learning and doing magic that is never quite explained, but described as tedious and difficult, and an overall depressing view on the world. The main character isn't even very heroic, quite the opposite, he really does think and feel like a 'dork'. If anything, he is a coward and a person who's few feelings are confused and pretty much self involved. His friends are none the better and the entire thing soon started to take a toll on me, who failed to empathize with anything and anybody.

Another issue with the book is that it is rarely consistent. Things happen without much explanation and then they turn into others. Modern culture references mix with awe of magic and then seriously fucked up shit, only to slip into irony or even slapstick comedy. It gets the reader curious about what is going to happen next, but always on the brink of "why am I reading this?". Myself I am sometimes completely engrossed in a bit of the story only to see it end abruptly and leading to nowhere. Doors to other realms are opened and nobody really cares for it for any reason other than to become kings and party all the time. People die or characters do some really shitty things, but the others are all calm and going on with their lives.

So yeah, I don't know if I should recommend the books yet. The show is levels of magnitude better so far, in story, consistency and character development. Even if I could buy into the whole borderline autistic asshole of a main character, which I was ready to, the sudden and often context switch made me really difficult for me to enjoy the series so far. However it is original and I have not read a book that sees the world quite in the same way. If you are tired of the same old fantasy stuff, The Magicians is a bit more adult and hard to put in a clear box, touching real young people topics, like sexuality, alcohol, drugs, depression, uncertainty, the search for happiness.

I have found a new addiction: prowling StackOverflow and answering questions. It does teach a lot, because you must provide in record time a quality answer that is also appreciated by the person asking the question and by the evil reviewers who hunt you down and downvote you if you mess up. OK, they're not evil, they're necessary. Assholes! :) Anyway, in honor of my 1000th point, I want to share with you the code that I have been working on for one of the questions.

The question had a misleading title: How to inherit a textblock properties to a custom control in c# and had a 500 points reward on it (that's a lot) placed there by another person than the original requester. In fact, the question was more about how to use a normal TextBlock control, but also have it display outlined text, with a specific "stroke" and thickness. Funny thing, I had already answered this question a few days before. The bounty, though, was set on a more formal answer, one that would cover any graphical transformation on a TextBlock, considering that the control had sealed the OnRender overload and there was no way of reaching its drawing context.

We need to consider that WPF was designed to be modular, unlike ASP.Net or Windows Forms, for which inheritance was the preferred way to go. Instead WPF favors composition. That is why controls are sealing their OnRender implementation, because there is another way of getting to the drawing context and that is an Adorner. Now, it is also possible to use an Effect, but for the life of me I couldn't understand how to easily write one.

Anyway, adorners have their pros and cons. The pro is that you get to still use a TextBlock or whatever control you want to use and you just adorn it with what you need. It receives a UIElement in the constructor and in its OnRender method you get access to the drawing context of the control. Here is the code of the adorner that I presented in the StackOverflow question:
public class StrokeAdorner : Adorner
{
private TextBlock _textBlock;

private Brush _stroke;
private ushort _strokeThickness;

public Brush Stroke
{
get
{
return _stroke;
}

set
{
_stroke = value;
_textBlock.InvalidateVisual();
InvalidateVisual();
}
}

public ushort StrokeThickness
{
get
{
return _strokeThickness;
}

set
{
_strokeThickness = value;
_textBlock.InvalidateVisual();
InvalidateVisual();
}
}

public StrokeAdorner(UIElement adornedElement) : base(adornedElement)
{
_textBlock = adornedElement as TextBlock;
ensureTextBlock();
foreach (var property in TypeDescriptor.GetProperties(_textBlock).OfType<PropertyDescriptor>())
{
var dp = DependencyPropertyDescriptor.FromProperty(property);
if (dp == null) continue;
var metadata = dp.Metadata as FrameworkPropertyMetadata;
if (metadata == null) continue;
if (!metadata.AffectsRender) continue;
dp.AddValueChanged(_textBlock, (s, e) => this.InvalidateVisual());
}
}

private void ensureTextBlock()
{
if (_textBlock == null) throw new Exception("This adorner works on TextBlocks only");
}

protected override void OnRender(DrawingContext drawingContext)
{
ensureTextBlock();
base.OnRender(drawingContext);
var formattedText = new FormattedText(
_textBlock.Text,
CultureInfo.CurrentUICulture,
_textBlock.FlowDirection,
new Typeface(_textBlock.FontFamily, _textBlock.FontStyle, _textBlock.FontWeight, _textBlock.FontStretch),
_textBlock.FontSize,
Brushes.Black // This brush does not matter since we use the geometry of the text.
);

formattedText.TextAlignment = _textBlock.TextAlignment;
formattedText.Trimming = _textBlock.TextTrimming;
formattedText.LineHeight = _textBlock.LineHeight;
formattedText.MaxTextWidth = _textBlock.ActualWidth - _textBlock.Padding.Left - _textBlock.Padding.Right;
formattedText.MaxTextHeight = _textBlock.ActualHeight - _textBlock.Padding.Top;// - _textBlock.Padding.Bottom;
while (formattedText.Extent==double.NegativeInfinity)
{
formattedText.MaxTextHeight++;
}

// Build the geometry object that represents the text.
var _textGeometry = formattedText.BuildGeometry(new Point(_textBlock.Padding.Left, _textBlock.Padding.Top));
var textPen = new Pen(Stroke, StrokeThickness);
drawingContext.DrawGeometry(Brushes.Transparent, textPen, _textGeometry);
}

}

The first con is that you need to use it in code, there is no native way of using it from XAML. The second con, and the most brutal, is that when the control changes what it renders, the adorner doesn't follow suit! Someone answered it better than I can describe it here. Guess where? On StackOverflow, of course.

The first problem I have solved with another great WPF contraption: attached properties. Here is the code for the properties:
public static class Adorning
{
public static Brush GetStroke(DependencyObject obj)
{
return (Brush)obj.GetValue(StrokeProperty);
}
public static void SetStroke(DependencyObject obj, Brush value)
{
obj.SetValue(StrokeProperty, value);
}
// Using a DependencyProperty as the backing store for Stroke. This enables animation, styling, binding, etc...
public static readonly DependencyProperty StrokeProperty =
DependencyProperty.RegisterAttached("Stroke", typeof(Brush), typeof(Adorning), new PropertyMetadata(Brushes.Transparent, strokeChanged));

private static void strokeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var stroke= e.NewValue as Brush;
ensureAdorner(d,a=>a.Stroke=stroke);
}

private static void ensureAdorner(DependencyObject d, Action<StrokeAdorner> action)
{
var tb = d as TextBlock;
if (tb == null) throw new Exception("StrokeAdorner only works on TextBlocks");
EventHandler f = null;
f = new EventHandler((o, e) =>
{
var adornerLayer = AdornerLayer.GetAdornerLayer(tb);
if (adornerLayer == null) throw new Exception("AdornerLayer should not be empty");
var adorners = adornerLayer.GetAdorners(tb);
var adorner = adorners == null ? null : adorners.OfType<StrokeAdorner>().FirstOrDefault();
if (adorner == null)
{
adorner = new StrokeAdorner(tb);
adornerLayer.Add(adorner);
}
tb.LayoutUpdated -= f;
action(adorner);
});
tb.LayoutUpdated += f;
}

public static double GetStrokeThickness(DependencyObject obj)
{
return (double)obj.GetValue(StrokeThicknessProperty);
}
public static void SetStrokeThickness(DependencyObject obj, double value)
{
obj.SetValue(StrokeThicknessProperty, value);
}
// Using a DependencyProperty as the backing store for StrokeThickness. This enables animation, styling, binding, etc...
public static readonly DependencyProperty StrokeThicknessProperty =
DependencyProperty.RegisterAttached("StrokeThickness", typeof(double), typeof(Adorning), new PropertyMetadata(0.0, strokeThicknessChanged));

private static void strokeThicknessChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ensureAdorner(d, a =>
{
if (DependencyProperty.UnsetValue.Equals(e.NewValue)) return;
a.StrokeThickness = (ushort)(double)e.NewValue;
});
}
}
and an example of use:
<TextBlock
x:Name="t1"
HorizontalAlignment="Stretch"
FontSize="40"
FontWeight="Bold"
local:Adorning.Stroke="Red"
local:Adorning.StrokeThickness="2"
Text="Some text that needs to be outlined"
TextAlignment="Center"
TextWrapping="Wrap"

Width="600">
<TextBlock.Foreground>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Offset="0" Color="Green" />
<GradientStop Offset="1" Color="Blue" />
</LinearGradientBrush>
</TextBlock.Foreground>
</TextBlock>

Now for the second problem, the StrokeAdorner already has a fix in the code, but I need to be more specific about it, because as it is written now I believe it leaks memory. Nothing terribly serious, but still. The code I am talking about is in the constructor:
foreach (var property in TypeDescriptor.GetProperties(_textBlock).OfType<PropertyDescriptor>())
{
var dp = DependencyPropertyDescriptor.FromProperty(property);
if (dp == null) continue;
var metadata = dp.Metadata as FrameworkPropertyMetadata;
if (metadata == null) continue;
if (!metadata.AffectsRender) continue;
dp.AddValueChanged(_textBlock, (s, e) => this.InvalidateVisual());
}
Here I am enumerating each property of the target (the TextBlock) and checking if they are dependency properties and if they have in their metadata the AffectsRender flag, they I add a property change handler which calls InvalidateVisual on the adorner. Notice that in no part of the code do I remove those handlers. However, at this time I don't think it is a problem. Anyway, the code itself is more about the principles of the thing, rather than the implementation.

If I were to talk about the implementation, I would say that this code doesn't always work. Even if I use the padding of the element and its actual dimensions, the FormattedText sometimes renders things differently from the TextBlock, especially if one plays with TextWrap and TextTrimming. But that is another subject altogether. Yay! 1000 points on StackOverflow! "And what do you do with the points?" [my wife :(]