Wednesday, April 25, 2012

Post-hackathon thoughts

It has been a few days, and we have (sort of) landed.

I shall call this year's Oslo.pm Perl 6 Patterns hackathon a success, judging by how the participants seemed to enjoy themselves during the hackathon, and the inspired blogging afterwards.

Salve (sjn) and Rune (krunen) have, on behalf of Oslo.pm, delivered to standards that I am a bit worried that guests now will come to expect ;), and although I did not have capacity to help with much, I am happy with how everything turned out, except for one thing:

Damian caught a cold, and was essentially out of the loop for most of the hackathon.

Darnit.

But he delivered a kick-ass talk on Thursday, and was very helpful and a very good resource before he somewhat reluctantly accepted the thrown towel.

I did not do much hacking this year myself, but I managed to revive some of my Perl 6 skills. I even fiddled a bit with the cookbook (dormant for three years or so, and therefore slightly out-of-date in some respects). I hope to contribute more to that piece of documentation in the coming months.

The bonus if I manage to work my way through it, is that I will be pretty much up to speed with the language. Win!

My thanks go to all the participants of the Hackathon, without you, Perl 6 would be much the poorer!

Sunday, April 22, 2012

Oslo.pm Patterns Hackathon pictures


Hacking: sjn, moritz (back), pmichaud, jnthn, masak, tadzik, sergot, bjarneh



Hacking: imarcusthis, infosophy



Posing, back to front, left to right:
infosophy, moritz, arnsholt, sjn, krunen, masak
tadzik, jnthn, frettled, pmichaud

Friday, April 13, 2012

Oslo.pm Perl 6 Patterns Hackathon 2012

In one week (2012-04-20 – 2012-04-22), a bunch of bright people will attend the Perl 6 Patterns Hackathon in Oslo.

Perl 6 – both its specification and implementations – will become one of the Great Ones. I admit that we are not quite there yet, but to me, Perl 6 is a language for the long term.

In one of the meetings krunen, sjn and I had this winter, we discussed this, and how to get there. I hope the Perl 6 Patterns Hackathon will contribute significantly, and I also hope that in 30-60 years, we will look back and be happy about most of the choices made around this time! I truly believe that we can get there!

Call for sponsor matching

In this spirit, Ingvoldstad IT decided to sponsor this hackathon with NOK 5,000 (≈ EUR 650), and I hereby call for other companies who develop software* to match this amount. Oslo.pm will put those money to good use!


I hope to see you in Oslo in a week!


* I did not write "Perl" here, because I think that is largely irrelevant. Perl 6 is an amalgam of many of the most interesting programming language features, and offers a very compelling path to those who want a next-generation language after the current versions of e.g. Perl, Python, and Ruby.

Monday, July 25, 2011

A warm and powerful time in unity

Occasionally, I have faith in my fellow Norwegians.

This afternoon was one of those times.

As international media will tell you, this afternoon was very special for those of us living in Oslo.

It started with a Facebook event, that rapidly spread via national media, friends talking and whatnot. If it hadn't been a planned event, it would have been a very large flash mob.

It was with some trepidation that my colleague and I walked towards RÄdhusplassen (the city hall square), as we well knew that a gathering of tens of thousands of people would be a very decent terrorist target.

The general idea was that people would gather there, carrying roses, and then walk peacefully to somewhere else (I've forgotten where). The plan did not survive. One of the major suppliers of plants and flowers said they would sponsor free roses. Every florist was out of flowers in no time, except for potted ones, it looked almost like locusts had passed by.



As we walked on, the crowd density increased, until it exceeded anything I have ever experienced. We Norwegians are very fond of going downtown for our constitution day May 17, or supporting events like the Nordic World Ski Championships or the Winter Olympics in 1994, and the crowds are enormous for a small country such as ours. Those days and events cannot compare.



The sea of flowers, the human warmth and compassion, the sense of unity of purpose – it was almost overpowering, and when Maria Mena started singing Ole Paus's Mitt lille land, I let the tears flow. At the end, we were asked to leave slowly, take care of eachother, and take our flowers – which the arrangers had planned to be placed in a single, potently meaningful place – and leave them all over Oslo.

If you weren't there, I wish you were.

Friday, December 24, 2010

Christmas Star

I grew up with my parents, the only child.

I also grew up with friends, and had very tight and warm family ties with my father's sister's children - my cousins, my brothers in spirit.

About twenty years ago, my father's health had declined so much that he could hardly work. He had recently been laid off, as a part of cutbacks just before his employer went bankrupt. Physical labour was hard on him, and we, his family, did not understand why, how, or how much. He received unemployment benefits as long as that was permissible, and then he got a job with an old friend, who owned a technical clothing store. That did not work out very well, because it was really tough on father to walk among aisles and restocking clothes. He even fainted once.

The late eighties and nineties were wondrous times in many ways, but the medical profession had hardly heard about ME or COLD/COPD as we know these classifications today. Getting medical recognition that my father was effectively unable to work was almost impossible, particularly considering that he – as so many from his generation – was a smoker. If you have any kind of problems with general shortness of breath, and a doctor asks you, "do you smoke", answering "yes" was then (and apparently still is) a very, very bad idea. The smoking then becomes the only focus, and the rest of the patient's problems seem pretty irrelevant.

But my father did get his disability pension.

In 1994, his father - my grandfather - fell in the snow and froze to death. He had been a widower for five years. Father and his sister inherited a small farm house with a little bit of land, in Vang in Hedmark. My parents sold our house in Oslo, bought my aunt's share, and moved. I moved to an apartment in a more central location in Oslo.

It was strange to not see my parents every day anymore, but it was also a sort of relief - a young grown-up probably benefits from moving, and I think I did. I certainly felt it was over due. :) But I kept regularly in touch with my parents, visited them every month or so, and we continued spending Christmas together every year, with my surviving grandmother, as we had for every Christmas since I was born in 1972.

Through the years, my father's health kept declining, and he became less and less active. Traveling became a chore.

In 2001, a very good friend of mine was diagnosed with particularly aggressive melanoma, but there was hope.

Around the same time, my father's health was so bad that he hardly walked around, and he didn't drive a car anymore because he thought it was irresponsible and unsafe. My parents sold the farm house and the land in 2002, and moved to an apartment in central Hamar. The apartment was fairly well suited for the elderly and disabled, and it saved my mother lots of house and garden work - which of course my father could take no part in.

My friend's cancer spread.

I still celebrated Christmas with my parents, every after grandmother died in 2003. The same year, my friend collapsed in my arms in a seemingly epileptic fit. That was a brain tumour. The same spring, they discovered that the cancer had spread to his colon. A few friends and I were visiting him a fine May day, when he suddenly panicked, started hyperventilating, pressed his pain pump's button repeatedly and pulled the alarm string. We were ushered out by the nurses. Five minutes later, he died, shortly before his family came to see him.

A couple of years later, my father was completely dependent on an electrical wheelchair, a chair or a bed - standing unaided was a risky affair. My mother and father rarely left Hamar, socially or otherwise. This was a pretty heavy burden for us to bear, my parents were both socially active before, and had many good friends. My mother was diagnosed with operable breast cancer in 2005, and the tumour and lymph cysts were surgically removed within a couple of weeks.

I had started sleeping with my phone next to my pillow.

We still celebrated Christmas together, and in 2007, my father took a chance, and visited his sister in Oslo for her 70th birthday. It was a wonderful day.

I never went anywhere without my cellphone, and made sure that I had the wireless house phone with me even in the bathroom.

In the summer of 2008, my father's brother-in-law, my uncle, was admitted to hospital because of what he thought was severe constipation. It wasn't, it was cancer. I visited him about half-way into his first week in hospital, and he was already so weak that he couldn't sit up and had to wear an oxygen mask, but he was fairly lucid. But he looked no healthier than my friend did just before he died, and right enough, a week later, my uncle was dead. My aunt and my cousins still came for my father's 70th birthday shortly afterwards, and it was a very fine celebration, despite that I had to drive my father home early because he was too tired.

My father went through a lot in those later years. He broke his hip from a fall indoors, and he needed extensive home care. He was frequently in the hospital for emergency care. I started having trouble sleeping, and was constantly worried for The Phone Call.

Late in 2008, my father was admitted to palliative care at Prestrud in Hamar, it was now too hard and difficult to care for him at home. My father had probably already suffered brain damage from lack of oxygen - which was untreated, because, hey, he was a smoker, and he just couldn't stop smoking - his withdrawal symptoms were too bad. And, hey, if you don't stop smoking, you don't get proper medical care.

My mother and I still hoped that we could celebrate Christmas in their apartment, but it was soon obvious that it would be impossible. So we prepared to celebrate part of Christmas with him at Prestrud.

I recall that Christmas Eve more vividly than most. My mother and I followed most of the old routine. The TV was on, and the traditional movie "The Journey to the Christmas Star" was showing as it always is. A character, Sonja, sings the song "Christmas Star, come to me", and I start crying.

We visited father at Prestrud, had Christmas cookies, biscuits, hot chocolate with cream and a good time, all considering.

A day in February, my mother called me at work. Father had pneumonia. I told my boss that I had to go, and went home to pack. Shortly afterwards, my mother called again; father was dead.

It was a strange funeral. Warm and melancholic, a wonderful priest - Helge Hognestad - who had an exceptional grasp of the humanity of it all. The first part of the funeral was tough going for me, but then I held my speech for father, and talked about many of the good things and times that I associate with him. Carrying his casket was tough, too, but when the hearse drove off, I was so relieved that I couldn't stop smiling.

Father's suffering was over. Mother's suffering was over. My suffering was over, too.

But then came the double whammy: in late spring, mother was diagnosed with pancreatic cancer, the kind which has seen an amazing increase in surviving patients, then at an estimated whopping 5%. It was a very hard blow, but then my mother and I started talking about it, and she decided to live her life in full, for however long that was.

In spite of awful side effects from chemo therapy, in spite of bloody vomit and other unsavory details, she kept on going. We went traveling together twice, my mother went alone or with others several times. She sometimes had to cancel before going, sometimes had to abort the vacation half way, but she never really gave up. We kept more in touch than before, talking at least every week, and meeting once or twice a month. We talked about good things and bad, and had a stronger relationship than in many years.

She started dancing swing again. She took up bridge, which she thought she was awfully bad at after so many years. She did almost all the things she couldn't do while father was too ill to go anywhere, or too ill to be left alone.

Her health kept declining, in some ways much as my father's had, but far quicker and therefore more visibly. Nobody blamed smoking, though.

She got help from Hospice Sangen, a day facility for people with severe illnesses, particularly cancer patients. She had an "open return" at Hamar hospital, in case she needed medical care, there was always room there. She got home care from nurses, whenever necessary, and at regular intervals with increasing frequency.

This fall, she was admitted to Hospice Lovisenberg, Sangen's "mother" facility in Oslo, for help with her significant pain medication problems; the medication just wouldn't take. She was fairly active while she stayed at Lovisenberg. Two Saturdays, she went shopping with me, the first time also with her elder sister. Lovisenberg got the pain sorted out, and on Monday a month ago - my birthday - I drove her home to Hamar again, thinking that she seemed a bit tired and reduced, but all understandable, since she had been stressing herself out a bit with packing and whatnot. Besides, she had been getting enough morphine to kill grown men several times over, on a regular basis, for weeks.

The following Wednesday, we talked on the phone again. She was more tired, and felt a bit unsteady on her legs, and had therefore gotten a four-wheel walker. I decided that I wanted to check up on her after the coming weekend, which was full of plans for myself - birthday party, roleplaying, etc. I told her I was coming the following Monday, and she was happy that I wanted to.

I called again on Friday during lunch hour, and my mother said: "I don't have much time left now, Jan. Can you talk to my sister?" and handed the phone over to her sister (not the same who went shopping with us just two weeks earlier). She explained to me that mother was lying on the couch (as she often did when she felt tired), but that she had hardly eaten that day, and my aunt didn't dare leave her alone. I said I'd try to get there this weekend.

I talked to my boss again, tidied up a few pressing tasks at work, went home and packed. I cancelled the party and notified others that I was not coming for roleplaying or other social events. I then told my mother and aunt that I was coming that evening, got into the car, and did as I said.

When I got there, we got help from a nurse so that mother could get to bed and sleep there. She was very tired, and barely coherent, though she heard and understood us.

The following morning, mother couldn't even sit up without aid, and she could not drink and swallow her pills without help. My aunt came back during the day, and we convinced a supervising nurse to have a look at my mother's now fairly swollen legs. We then convinced the nurse to call for an ambulance, and had mother admitted to the hospital that Saturday night.

At hospital, I called my youngest cousin, the closest person I've had to a brother, and told him briefly how it was. He said he'd come and keep me company.

During the night, mother had occasional pain in spite of the better pain medication and well-adjusted morphine pump, and occasionally lucid moments. Her breathing was laboured, but when the nurses managed to adjust the morphine dosage up by a third and the bolus frequency limit down by a third, she was well relieved. I had to push the button, though, because my mother could not.

In the early morning, her breathing slowed and became weaker. She was sleeping or dozing all the while, and I was holding her hand, and my cousin was holding mine.

Her face was tilted slightly towards me, and one eyelid was slightly ajar, the pupil aligned with my face. She died so peacefully that I can't say exactly when it was. It was beautiful, and I wouldn't have missed it for the world.

But I miss you, mother, and most of all today, and now I think of Sonja's song and cry.

Sunday, August 1, 2010

Community boost

It is now three days since the release of Rakudo Star.

Everything has met my personal expectations, except for one major thing:

There is a bunch of new people on #perl6, who are actively engaged in trying out Rakudo Star/Perl 6, in testing, submitting bug reports, patch suggestions, asking for help, providing help, helping themselves…

I really do not have anything profound to say, but I can say this:

Now we are really getting somewhere!

Thursday, July 29, 2010

Rakudo Star is here

The wait is over, and a usable Rakudo-based Perl 6 distribution is ready for early adopters. Yay!

More and more of Perl 6 is implemented in Perl 6. That is a very good tendency.

Thursday, March 4, 2010

Coding styles that make me twitch, part 8

One of the worst programming habits I know of, is assuming that everything will work out; you just perform the command/function call, and it has to work. In other words: do not bother checking for error conditions or propagating them, because they are not going to happen anyway. right?

Wrong.

But the code works. Mostly. Except when an error condition occurs. And it will, eventually.

In some instances, such code is a glorified shell script. I have ranted about that before. But catching error conditions properly can be tricker than with in-Perl functions and modules. Especially if you have no control over what the external program does, but the original programmer did.

Even with in-Perl functions and modules, you might run into, ehrm, interesting usage.

Usually, the root of the problem is that the original programmer did not foresee that some his code could grow into something else.

While it may have been a good idea to create an SQL query wrapper to hide parts of what DBI does for auto-committing statements:
sub do_sql {
my $qry = shift;
my $ignore = shift;
if (!$dh) {
&slogin();
return if (!$dh);
}
my $sh = $dh->prepare($qry);
if ($sh && !$sh->execute) {
if ($sh->errstr =~ /(MySQL server has\
gone away)|(Lost connection to MySQL server)/) {
&log("Lost MySQL, reconnecting.");
&slogin();
return if (!$dh);
$sh = $dh->prepare($sqlstmt);
undef $sh if ($sh && !$sh->execute);
} else {
undef $sh;
}
}
&log("SQL failed: '$qry'.") if (!$sh && !$ignore);
return $sh;
}

that is no guarantee that the implementation will be future-proof, when the subroutine is used like this:
my $sh=&do_sql("SELECT * FROM tab1 WHERE\
x<>'$cgi->{data}' AND y<>42");
if (my $res=$sh->fetchrow_hashref) {
$cgi->{ref}=$res->{ref};
}
&do_sql("UPDATE tab1 SET x='$cgi->{newdata}',\
y=23, z='$cgi->{ref}'");
&do_sql("UPDATE tab2 SET tab1_changed='yes'");
&log("Updated tab1, ready for externals");
# Process the changes made above:
system("/usr/local/bin/changestuff.pl");
&log("Finished processing");

Imagine now that changestuff.pl also performs changes in the database tables mentioned above, and that the code above is called in a cron job every minute or so.

Here is an attempt at listing the worst parts:
  • do_sql only pretends to do proper error checking, it mostly does not do anything useful about the error situations.
  • The query result seems of little consequence.
  • There is an obvious need for bound variables in the prepared statement, but do_sql does not support that. So the code pretends the problem does not exist.
  • When do_sql is used for updates, there is no check whether the returned statement handle ($sh) is empty or not, there is no way of knowing whether we are clobbering the database.
  • Why do we not care whether the external commands succeeds or not?
  • SQL transactions, anyone?
  • Yeah, other parts of the style sucks, too.
Now imagine the example above multiplied to thousands of lines of inter-dependant code.

I am happy to say that I do not see things like this too often.

However, cleaning up code like this is a PITA, and it is often easier just to close your eyes, add your own code, and leave well enough alone.

Thursday, February 25, 2010

Coding styles that make me twitch, part 7

Parentheses and precedence

This week, I will strive to be better at explaining the problem scope, while heroically and miraculously maintaining brevity.

I used to be annoyed at seeing extraneous parentheses with the ternary conditional operator pair ? :, but then I discovered that the PHP language designers decided to break precedence (see example #3). So I have stopped twitching as much as I used to when seeing parentheses galore in that context.

In Perl Best Practices, Damian Conway notes that even though the low-precedence logic operators and, not and or may seem nicer, they can confuse the reader regarding the intended meaning of the code. But he does not — as far as I can recall or find — address how these relates to parentheses and precedence (I suppose that should be "parentheses && precedence").

I start twitching when someone insists on using parentheses like this (imagine that the example was more convoluted):
if (expr1 ||
(expr2 && expr3) ||
expr4
...)
That does not help understanding. It confuses me, as the read, regarding your intentions. Is there a piece of code missing, perhaps a little bit of || expr2b or || expr3b?

Sometimes, I even see misguidedly mixed-in letter-literal operators:
if (expr1 or
(expr2 && expr3) or
(!expr4)
...)

I much prefer seeing
if (expr1 ||
expr2 && expr3 ||
expr4
...)
or
if (expr1
|| expr2 && expr3
|| expr4
...)
depending on what floats your boat in the most stylish way imaginable.

I would have thought that the logical and/or/not part of operator precedence would be easy to understand. It is essentially the same in most programming languages: Ruby, Python, Perl, Java, C, ... and not even PHP managed to mess this one up.

The chance that anyone is going to be confused by your code because of these parentheses not being there is far, far smaller than the chance that they are going to be confused by their presence.

I have heard the defense "but the code is so non-obvious that I had to add them!" Well, make your code obvious instead.

Thursday, February 18, 2010

Coding styles that make me twitch, part 6

Edit: There are, apparently, strong feelings that I should not post my personal preferences. Reader discretion advised: this post expresses my personal opinions regarding a limited use case for file handling and filehandles, and must not be read as general advise on how to deal with filehandles in Perl, and so on.

Today's theme is: unnecessary variable clutter.
my $fh = new Filehandle("/usr/bin/somecmd someargs |");
while (my $l=<$fh>) {
if ($l=~m/foo bar zot/) {
# lots of code that does not depend on
# a variable file handle, nor creative
# usage of $l where $_ could not be used
# implicitly just as easily

}
}
Sure, there are situations where it makes sense to assign filehandles to variables, or using $l instead of $_, but the above example is not one of them. I found no particular reason why the original programmer had used new Filehandle, either.

Perl 5 has, on purpose, made this easier for us than in the above example:
open my $FH, '-|', '/usr/bin/somecmd someargs'
or croak "OMG\n";
while (<$FH>) {
if (/foo bar zot/) {
# lots of code
}
}

Thursday, February 11, 2010

Missing feature

A few hours ago, I suddenly had a bright(?) idea, or desire if you will:

Proper (Unicode) exponents in Perl.

That is, I want to be able to write 22, 4137, 3-9, etc. and have Perl understand them.

For Perl 5, I suspect someone would use a source filter to implement it.

For Perl 6, PerlJam++ suggested introducing each of the exponents as postfix operators, using this example for squaring:
our &postfix:<2> := &infix:<**>.assuming(b => 2);
But then a negative exponent would complicate things a bit.

It's a thought, anyway, and not one that I'd want to distract more pressing implementation concerns.

And ifwhen someone decides that this is a good idea to have in the language core, I'll start nagging about Knuth's up-arrow notation. Not that I'd want anyone attempt calculating 4↑↑↑↑4.

Thursday, February 4, 2010

Spooky

This is just a small anecdote.

Tonight, I finished a small Perl 5 script that I've been wanting to complete for a while, but where I was a bit nervous that I'd fsck it up right and good.

It was a script designed to handle two tab-separated text sources; one a list of tournament IDs and tournament names, the other a list of player results, one line per result with the player ID, tournament name, position and score achieved.

I achieved this by creating a hash of hashes for each file, referencing the first while parsing the other, and bravely inserting the data into a single database table.

I tested my code piece for piece while building it, which is sensible in itself, but what spooked me was this:

There was not a single bug. The script did what it was supposed to do, all along.

That's not supposed to happen.

I need a drink.

Friday, January 29, 2010

Rakudo ng - what will it mean for us?

If you've been hanging around the right blogs and the #perl6 IRC channel on Freenode, then you've probably seen references to a slightly mysterious "ng", or "Rakudo ng".

That's the upcoming (next) version (generation) of Rakudo, which will form the basis for Rakudo *.

In essence, this is a refactoring/rewrite of Rakudo for the purpose of better compliance with the specification and performance improvements (yay). The old Rakudo master made it difficult — if not impossible — to implement several essential parts of the Perl 6 spec and top priorities on the Rakudo roadmap.

In January, this has led to less focus on the current Rakudo version's bugs and gotchas, and instead on working to prepare ng as the new master branch — that is, the Rakudo that you will be downloading the next time.

For those of us who do some Perl 6 coding in Rakudo, this means that we can expect a nice little bunch of incompatibilities as compared to the current master. And yes, it's very close, so it's time to prepare.

Here's a list of the blindingly obvious things I think we need to watch out for:
  • Older Rakudo was not in line with parts of the spec that ng will be.
  • The spec has changed. (ng development has uncovered several necessary changes.)
  • Older Rakudo is in line with parts of the spec that ng perhaps isn't.
  • Rakudo ng is, of course, not feature complete when it replaces older Rakudo as the master.

In other words: let's not fool ourselves into thinking that we all of a sudden have a new Rakudo that's both compatible with the older as well as being spec compliant.

The good news about Rakudo ng

If you judge by the above paragraphs, you'd think that Rakudo ng was bad for Perl 6 developers. But that's far off the mark. I prodded #perl6 and Patrick Michaud before publishing this post, and here's a brief summary of (most of) the improvements we can see coming with Rakudo ng as opposed to the current implementation.

  • Most of the top priorities of the Rakudo roadmap will be implemented!
  • Laziness will mostly work (the spec is undergoing change)
  • Performance improvements, many due to laziness
  • Array/List/Parcel/etc. will be compliant with the updated spec
  • Protoregexes
  • Better longest token matching
  • Meta-operators are really meta, and generated on demand
  • The base object metamodel is far closer to the spec than before
  • Major portions of the metamodel are implemented in Perl 6
  • Array and hash vivification will work properly
  • Lexical subs and variables work properly
  • Operators have the correct names (with angles)
  • Subs have the correct sigils (with ampersands)
  • Phasers work, and the phaser model is much improved

Our programs will need a bit of attention. I recommend subscribing to perl6-language for up-to-date information about changes to the specification and language discussions.

There's still a lot of work to be done, and I'm sure the Perl 6 developers are happy for any help they can get.

Thursday, January 21, 2010

"Your Unix Is Leaking Perl"

That has to be one of the weirdest statements I've read in, oh, at least fifteen minutes.[1]


(The image is a link to the original strip; if you've got javascript enabled, you can see this bonus strip by hovering over the burgundy red button below to the left.)


A huge thanks to Saturday Morning Breakfast Cereal for this piece of wisdom, but I'm afraid that Zach Weiner got it backwards when he thought that would be expensive.

May I suggest that when a computer "leaks Perl", it does so because the (hopefully brilliant) Perl programmer is contributing a lot to CPAN?

;)


Yes, I've been communicating with customers lately, how did you guess?

Thursday, January 14, 2010

feather.perl6.nl - a Sysadminish Tale

<@Juerd> frettled: Blog about the mess you found when
you first logged in on feather yesterday :)

Sure.

This will, incidentally, also explain why Trac is kindof unavailable now.

feather.perl6.nl is a Xen guest (a virtual machine, hereafter "VM") that's hosting several important services for the Perl 6 community. There's SVN web access, a Trac installation, and a bunch of other stuff I honestly don't know the half of.

Recently, the VM started running out of memory too often for comfort. What was going on? Juerd asked for help in tracking down the problem, as he didn't have the time to do so himself. And needing some distraction from work -- something to help me procrastinate -- I volunteered.

By now, you're probably banging your head on your keyboard in sympathy with me for saying something that may have been slightly less than brilliant. You know the feeling; Matt Trout reaches his right hand towards you, the world is suddenly in slow-motion, you see his hand closing in on you, his grin widening, and a voice saying "thhhhhaaaaannnnnkssss ffffooooorrr vooooluuunnnteeeerrriiiinnnnng", and you're basically up that creek with all the mud and dirt in it.

After handing over an SSH public key and getting sudo access (yeah, yeah, I know), I had a look anyway.

First, I went on a brief but wild goose chase, finding some error messages regarding ConsoleKit which appeared to be more frequent just before the server went out of memory, checked the Debian version (an unholy mix of Debian unstable and Debian experimental with lots of package updates pending someone's attention), and generally tried to get a feel of how the system was configured.

We already knew that Apache somehow might be responsible for gobbling up available memory, so my first action was to have a look at the last 100,000 lines of the Apache access log, using a simplistic log analysis script.

But which log? There were three Apache log directories to choose from. I (correctly) guessed that the one called simply /var/log/apache2 might be the interesting one, the others seemed to be legacy directories which should have been removed ages ago.

According to the script, there were 0 accesses in the last 100,000 lines.

Knowing the script, that was not so strange, because it makes a few assumptions regarding the log format, using a regexp belonging to the days before named captures and whatnot:
while (<>) {
if (/^(\S+) (\S+) - - \[[^\]]*\] \"(GET|POST) \S*
HTTP(|\/1\.[01])\" \d{3} (\d+) \"/) {
The regexp line has been split for the sake of the line width of this blog. There's nothing to be proud of here.

Anyway, I first had to remove the first capture; feather's logs weren't showing the virtualhost as the first column, and access types were most certainly not limited to only GET and POST:
frettled@feather:~$ sudo awk '{print $6}' /var/log/apache2/access.log|
sort -u
"CHECKOUT
"CONNECT
"DELETE
"GET
"HEAD
"MERGE
"MKACTIVITY
"OPTIONS
"POST
"PROPFIND
"PROPPATCH
"PUT
"REPORT
Right.

After straightening that up (and adding %v to the LogFormat specifications in the Apache config for future use), I got the following result:
Use of uninitialized value $size in addition (+)
at /usr/local/sbin/bandwidthips line 39, <> line 1002.
Use of uninitialized value $size in addition (+)
at /usr/local/sbin/bandwidthips line 40, <> line 1002.
Use of uninitialized value $size in addition (+)
at /usr/local/sbin/bandwidthips line 44, <> line 1002.
AAAARRGH! Idiot! Imbecile! Inept half-wit! Yep, I'd forgotten to renumber my captures. See, this is why Perl should be in version 5.10.1 or 6 when fiddling with those bloody annoying regexps.
frettled@feather:~$ sudo tail -100000 /var/log/apache2/access.log|
/usr/local/sbin/hitips|head
193.200.132.146: Bytes = 14329487 (3.44%), Hits = 51503 (51.82%)
66.249.71.2: Bytes = 132116084 (31.73%), Hits = 18111 (18.22%)
66.249.71.37: Bytes = 50846948 (12.21%), Hits = 6236 (6.27%)
93.158.149.31: Bytes = 54880221 (13.18%), Hits = 1894 (1.9%)
71.194.15.106: Bytes = 460200 (0.11%), Hits = 1894 (1.9%)
209.9.237.232: Bytes = 433388 (0.1%), Hits = 1686 (1.69%)
193.200.132.135: Bytes = 1726871 (0.41%), Hits = 1635 (1.64%)
193.200.132.142: Bytes = 429358 (0.1%), Hits = 1609 (1.61%)
208.115.111.246: Bytes = 8461415 (2.03%), Hits = 1238 (1.24%)
67.218.116.133: Bytes = 18945415 (4.55%), Hits = 1126 (1.13%)
So, uhm, around 52% of the hits come from feather3.perl6.nl, and nearly 25% from Google's indexer. Lovely.

Looking at the accesses from feather3, I quickly saw that they mostly had to do with svnweb.

Juerd had already stopped Apache, but someone -- I don't know who -- started it again at 12:00, probably anxious that SVN and such didn't work.

I then followed the running processes using the top command, updating each second (top d1), sorting by memory usage (typing M while top was running), hoping to catch some quickly growing processes.

Nopes. None, zilch, nada. Nothing that appeared horribly wrong. Sure, the apache2 processes used some memory (30-60 MB resident set, 50-100 virtual), but nothing appeared to be out of the ordinary. I changed the update frequency to each third second -- top sometimes uses an inordinate amount of CPU, depending on magic -- and waited. After a while, a couple of apache2 processes were using more CPU and memory than the others, around 60-90 MB resident. And they were growing. And according to lsof, they were active in the svnweb directory (and used a metric shitload of libraries). And after growing, they didn't release memory, they just kept on using it. But it wasn't enough to use up memory, there was still a bunch of free RAM.

So that was perhaps svnweb's fault, then?

Maybe.

But then my time ran out, and I had to drop the ball, leaving the top process running.

Five minutes later, the memory ran out again. It's just as if someone was waiting for me to go idle in order to produce the problem that I was looking for.

Sigh.



svnweb kindof remained the main suspect, until Juerd caught whatever was happening at the right time.

And catching what happens at the right time is bloody important.

Here's what he found, using Apache's server status:



Well, that's not svnweb. That's Trac. And the IP addresses belong to Google.



And that's spam, effectively creating a DoS or DDoS attack on our services as a side effect when search engines try to index the Trac webpages. It probably isn't intentional, but spammers just don't care.

So, what can we do to protect feather from suffering from such attacks in the future?

There's a lot that can be done. It takes effort. It takes time. It takes someone.

Here are a few suggestions on how to improve the robustness of the kind of services feather provides:
  • Add a captcha to the web form. The disadvantage is that this does not really save processing resources, but it probably should be done anyway.
  • Add an unnecessary and bogus input field to the web form, e.g. "Phone number". This input field should be hidden with CSS so that web browsers don't display it, and if someone submits anything with data with that field's name, then you can be nearly 100% certain it's spam from someone who's used a web scraper before automatically filling the form. Filter it out.
  • Change the webserver delegation architecture, so that each Apache process isn't loading tens of megabytes of libraries and keeping them in memory. Off-loading to shorter-living FastCGI daemons or similar solutions, or even sacrificing program startup speed by using CGI+suexec, etc., may be decent starting points.
  • Consider using a front-end proxy like Varnish to gloss over underlying nastiness.
  • Start with a new VM and migrate services to that one, gradually.
  • Document configuration choices and what each web service does/is there for, so that the next sysadmin coming along can make educated guesses quicker. :)
These tasks can rather easily be split into manageable one-person projects.

Does this sound interesting to you, or did I lose you at the third line of this blog entry?

Pop in on #perl6 on the freenode IRC network and say so.

Tuesday, January 5, 2010

Typing More Or Less

Not too long ago, there was a bit of minor cleanup in the Perl 6 specification regarding the use of whatever (*); there were some inconsistencies in how it behaved, depending on context.

The net result is that you now must use @arr[*-1] to get the last element, you cannot get away with simply using @arr[*].

Some may feel that this extra typing is bothersome, especially if you have a Unicode-friendly keyboard setup.

However, we can sneak our way past this problem by using a constant.

This also works with the current release of Rakudo, so it's not quite science fiction:
constant Ω = *-1;
Or, if you're feeling Cyrillic rather than Greek:
constant Ѡ = *-1;
Now we can substitute our nice constant for *-1 anywhere in the following code:
my @letters = 'a'..'z';
say '→'~@letters[*-1];
→z
Like so:
constant Ω = *-1;
my @letters = 'a'..'z';
say '→'~@letters[Ω];
→z
And, of course, you can do this with other things that are so tedious to type when you're dealing with maths:
constant π = pi;
say '→'~π
→3.14159265358979

Thursday, December 31, 2009

2009 In Perl

Repeat after me: I will not pretend to be an analyst or doomsayer, even though the end (of 2009) is nigh.

In 2009, Perl grew up a bit more, both as a language and as a community.

Language Development

Perl 5.10.1 came with a pony to those of us who fear the .0 releases.

The Perl 5.11 development tree got started, and it looks like it is rolling on rails. At this rate, we will see 5.12.0 quicker than you can say antidisestablishmentarianism.

... Perl 6 has made progress both on the specification side and in implementations -- yep, that is plural. It is sometimes confusing when naming changes under your feet, but it is acceptable while the spec is still settling.

Community

In 2009, I think I saw more openness regarding the internal conflicts in the Perl community as a whole; there were abundant admissions that we were not communicating nearly as well as we should, that there was at least a small amount of internal bickering over the present and future state of the onion -- onions, I must inject, tend to come in many shapes and flavours, and are not always the same inside -- really, which way we are going, are we having a conflict or not (yes we are -- no we are not -- huh, are we talking? -- pass the chips), and get off my lawn before I shoot or hug you.

In brief, it looks to me like 2009 was the year when the community showed renews signs of self-awareness.

But much more happened. We got a closer focus on Perl visibility, from my POV mainly owing to Matt S. Trout's lightning talk challenge from NPW 2009, plus a whole range of people working on other PR aspects for ourselves. And mst still keeps his hair colour. Wow.

Other Stuff

I made new friends, I learned a lot, I even got to help out a bit, and I hope that this will continue in 2010.

I hope you will too.

Happy new year!

Monday, December 21, 2009

Dice Roller Deconstructed

As promised, here are the elements of last week's dice rolling code:

use v6;
This is a nice way to say that we are in Perl 6 land.

subset D10 of Int where 1..10;
A "D10" is a 10-sided die, and it can only have integer values in the range 1..10. Subtyping Int is an acceptable way of taking care of that.

sub is_success (D10 $roll, D10 $target) {
Here, I am already using the subtype D10 of Int. This subroutine compares the rolled die $roll with the target number $target, and is called from the subroutine roll() for each die in the dice pool. I chose to create an explicit subroutine because it seems a bit clearer what happens in the special case of a rolled 10, which means that you get to re-roll that die for a potential new success.

    my $n = 0;
if ($roll == 10) {
say "10 again";
$n += roll 1,$target;
}
If we roll a 10, then the roll() subroutine is called with a dice pool of 1 and the same target number as we got originally for determining success.

    $roll >= $target ?? $n + 1 !! $n;
}
We always return the number of successes from the roll for the "10 again" rule (if it happened), and in case this roll was a success, we return an additional success.

sub roll (Int $poolsize where { $_ > 0 }, D10 $target? = 8) {
The dice pool size can of course not be negative, but it also cannot be zero; you always get to roll a die, so I have added a type constraint for that. The target number is optional, defaults to 8, and has to be possible with a D10.

    my D10 @rolls = (1..10).pick($poolsize, :replace);
From left to right:
  • @rolls is an array that will contain the results of the normal die rolls
  • (1..10).pick($poolsize is a way of picking $poolsize dice having possible values in the range 1..10 and "rolling" (randomizing) each of them.
  • pick($poolsize, :replace) means that we not only pick a result, but we also make it possible to achieve the same result again. Specifically, it is important for us that each die can have ANY value, not just values that have not been picked before. The semantics of pick() are explained in .pick your game (the 15th gift in the Perl 6 Advent Calendar).


    say "Roll: " ~ @rolls.sort.join(",");
@rolls.sort.join(",") sorts the elements of the @rolls array and stringifies them joined with a comma, e.g. "1,2,3,3,4" for @rolls = 4,1,3,2,3

    [+] @rolls.map: { is_success $_,$target };
}
This piece of code maps is_success $_,$target on every value in the @rolls array and creates a sum of those results. In other words, it sums up the number of successfull die rolls.

given @*ARGS.elems {
The @*ARGS array contains the command line arguments to the program, and .elems therefore is the number of arguments used.
    when 2   {
say "Target number: " ~ @*ARGS[1];
continue;
}
This block only runs in case we have two arguments, but it explicitly says that we may not be done yet: the continue statement counters the default implisit break to ensure that we can match the input value against other tests.
    when 1|2 {
my $n = roll |@*ARGS>>.Int;
say "Successes rolled: " ~ $n;
$n >= 5 and say "Exceptional success!";
}
We start off with a junction to say that either 1 or 2 is fine by us, we want both to match. Then we call roll() with the same arguments we got in, but each converted to Int. White magic. We store the value, and exclaim that the result is an exceptional success if it is.
    when *   {
$*ERR.say("roll.p6 poolsize [target]");
exit(64);
}
}
This is the equivalent of C's default, the catch-all that handles remaining uncaught cases. We print a helpful usage string to STDERR ($*ERR in Perl 6) and exit with the correct Unix exit code, praying that nobody uses a different kind of system.

Wednesday, December 16, 2009

Dice Rolls for Role-Players

I realize that the title of this post is a bit of an oxymoron, because a Real Role-Player of course doesn't roll dice often. ;)

But in the cases where the Real Role-Player does roll dice, wouldn't it be nice to have a computer program to forget at home rather than some even more easily mislaid dice?

The Perl 6 Advent Calendar provided some inspiration for this post.

A problem with many minor programming examples you see on the net, is that they do not take into account the needs of a role-player. Role-players play many different systems, with different criteria for success in dice rolls. D6 (the regular six-sided cubic dice used for playing Monopoly, Yahtzee, etc.) are not used much in the majority of systems.

Therefore, I'll look at the Storyteller System, which is used in the World of Darkness series of games.

The general principle is that you have a pool of dice to roll, and you count your successes, which in this system is the number of dice that have a value greater than or equal to a given target number for the roll. The standard target number is 8 in most implementations. Five successes in the same roll is an exceptional success. Obviously, it's nice to have many dice to roll!

Here's a real Perl 6 program that works with Rakudo today: it accepts two command line parameters, the first being the size of the dice pool, the optional second parameter defines the target number for success:
use v6;

subset D10 of Int where 1..10;

sub is_success (D10 $roll, D10 $target) {
my $n = 0;
if ($roll == 10) {
say "10 again";
$n += roll 1,$target;
}
$roll >= $target ?? $n + 1 !! $n;
}

sub roll (Int $poolsize where { $_ > 0 }, D10 $target? = 8) {
my D10 @rolls = (1..10).pick($poolsize, :replace);
say "Roll: " ~ @rolls.sort.join(",");
[+] @rolls.map: { is_success $_,$target };
}

given @*ARGS.elems {
when 2 {
say "Target number: " ~ @*ARGS[1];
continue;
}
when 1|2 {
my $n = roll |@*ARGS>>.Int;
say "Successes rolled: " ~ $n;
$n >= 5 and say "Exceptional success!";
}
when * {
$*ERR.say("roll.p6 poolsize [target]");
exit(64);
}
}

Thanks to moritz++ for ironing out two annoying mistakes!

Here are a few usage examples:
$ perl6 roll.p6
roll.pl poolsize [target]

$ perl6 roll.p6 5
Roll: 1,2,7,8,9
Successes rolled: 2

$ perl6 roll.p6 5 2
Target number: 2
Roll: 1,2,2,4,9
Successes rolled: 4

$ perl6 roll.p6 5 4
Target number: 4
Roll: 6,8,9,10,10
10 again
Roll: 8
10 again
Roll: 2
Successes rolled: 6 - Exceptional success!

There are no comments in this piece of code, I want people to try to understand it as-is, based on the Perl 6 Advent Calendar. If you have any questions, comments, corrections, etc., don't hesitate, just write!

In my next blog entry, I'll pick the program apart and comment on what I've done and why, and who knows, maybe someone has come up with an elegant solution to the same problem.

Wednesday, December 9, 2009

GCD - A Small Language Enthuser

fun gcd (x:int,y:int) : int =
case x of 0 => y
| _ => if x < 0 then gcd(y,0-x) else
if y < 0 then gcd(0-y,x) else
if y > x then gcd(y-x,x) else gcd(x-y,y);
"But that's not Perl!"
Yeah, yeah, I hear you.

I'll rectify that minor detail in a bit.

But first, an anecdote.

Back in the late nineteennineties, I was studying computer science, and one of the classes was about program specification and verification.

Several of the students already had a background with several programming languages, some were functional, some were imperative, and other languages were a bit confused about what they really were.

When studying program specification and verification, you either become rather obsessed with program correctness -- and hopefully elegance -- or you fail spectactularly.

There are several ways to muster enthusiasm when dealing with such studies; they can be rather, ehrm, theoretical.

I therefore flitted about, flirting with various programming languages, comparing them with the eagerness that young idealists do.

For some reason, I found Euclid's GCD algorithm to be particularly fascinating, for reasons unknown to men to this day.

The Perl version I saw was rather awful, and technically incorrect:
sub gcd {
if (!$_[0]) {
return $_[1];
}
if ($_[1] > $_[0]) {
return gcd ($_[1]-$_[0],$_[0]);
}
return gcd ($_[0]-$_[1],$_[1]);
}
Yikes. I mean, eep. And Perl does have a modulo operator.
sub gcd {
my ($x, $y) = @_;
$y ? gcd ($y, $x % $y) : abs $x;
}
I won't claim that the above code is the epitome of elegance, but it solves the problem in a general and easily read way (I admit a prejudice against $_[N]), while retaining correctness.

This is, BTW, one place where some golfers miss the boat; the GCD cannot be a negative integer. That's why the ML code at the top is so verbose.

Small challenges like these kept me going, and it can be an inspiring way to learn details in a new language. So, what would it look like in Perl 6?
sub gcd (Int $x, Int $y) {
$y ?? gcd($y, $x % $y) !! $x.abs;
}
What's your favourite algorithm for playtesting languages?