Prerequisites:

Run

sudo apt-get install build-essential devscripts ubuntu-dev-tools debhelper diff patch quilt fakeroot lintian libtool gnome-common gnome-doc-utils gtk-doc-tools

You should also have

deb-src http://archive.ubuntu.com/ubuntu/ jaunty main restricted

in your /etc/apt/sources.list (and then sudo apt-get update).

   1 [20:00] <didrocks> DING DONG, it's classroom time :)
   2 [20:00] <francescom> yep :-)
   3 [20:00] <didrocks> just to know a little about the audience, who is ready to update some packages? :)
   4 [20:01] <francescom> me
   5 [20:01] <blfgomes> I am!
   6 [20:01] <padawan> not yet still learning the basics
   7 [20:01] <include_pr> For sure
   8 [20:01] <TheMadBeaver> total package newbie
   9 [20:01] <Pollywog> I am ready
  10 [20:01] <gtomy> yes
  11 [20:02] <Pollywog> I am on Intrepid but have Jaunty in virtualbox
  12 [20:02] <Pollywog> will I need Jaunty for this?
  13 [20:02] <didrocks> great, some people there! For those who don't know the basics/can't practice, there will be a lot of copy/paste in pastebin so that you can follow the lesson :)
  14 [20:02] <didrocks> Pollywog: appart for last part, no, you can use your intrepid box
  15 [20:02] <gtomy> I have hardy intalled
  16 [20:02] <gtomy> installed
  17 [20:02] <didrocks> hardy has well be fine :)
  18 [20:02] <didrocks> as*
  19 [20:02] <didrocks> First and before the introduction, if not done yet, install theses packages :
  20 [20:03] <didrocks> sudo apt-get install build-essential devscripts ubuntu-dev-tools debhelper diff patch quilt fakeroot lintian libtool gnome-common gnome-doc-utils gtk-doc-tools.
  21 [20:03] <didrocks> (without the final dot, of course)
  22 [20:03] <francescom> didrocks: already done
  23 [20:03] <didrocks> You should also have "deb-src http://archive.ubuntu.com/ubuntu/ jaunty main restricted" in your /etc/apt/sources.list (and then sudo apt-get update).
  24 [20:03] <didrocks> tell me when I can begin my introduction during the download :)
  25 [20:04] <gtomy> done
  26 [20:04] <didrocks> (and yes, that's a bunch of packages ;))
  27 [20:05] <didrocks> I will begin with a very generalist introduction so that people can follow what will be in this lesson
  28 [20:05] <didrocks> As most of user want to live on the edge about what best the Open Source community has to offer, we are going to see how to update a package to offer the very last release to all ubuntu users.
  29 [20:05] <didrocks> First, be warned that once a release is out and for all supported releases (jaunty soon!), we never update a package to a new software version (appart from backports repository and ppa, when requested).
  30 [20:05] <didrocks> We only cherrypick bug and security fixes from a new release to adapt it an older version. This is intended to have as little breakage as possible.
  31 [20:06] <didrocks> So don't expect to have OpenOffice 3 in intrepid from the casual repositories, it will never happen. Jaunty, on the contrary, has it!
  32 [20:06] <Pollywog> does this mean I should not report bugs in Intrepid's kmail?
  33 [20:07] <didrocks> Pollywog: I'm more a GNOME packager than a KDE one. If a major bug in kmail happens, yes, report it
  34 [20:07] <slytherin> Pollywog: you should provided it does not say "please update to latest version"
  35 [20:07] <didrocks> (it's an extra bonus point if it's still happens in the last release)
  36 [20:07] <blfgomes> didrocks: which bugs should be fixed and which should be left for the next release?
  37 [20:07] <didrocks> but, it only concerns major crash/unusable version. If it's a major issue, no, it will not be updated
  38 [20:08] <didrocks> blfgomes: minor issues
  39 [20:08] <didrocks> for instance
  40 [20:08] <didrocks> ICQ has changed its protocol recentely
  41 [20:08] <didrocks> making it unusable fo pidgin
  42 [20:08] <didrocks> with*
  43 [20:08] <blfgomes> I see
  44 [20:08] <didrocks> so, we reported the patch in pidgin for every supported version
  45 [20:08] <didrocks> that is to say, dapper, gutsy, hardy, intrepid… and jaunty :)
  46 [20:09] <didrocks> that's a lot of work, even for a minor patch
  47 [20:09] <blfgomes> :)
  48 [20:09] <didrocks> that's why only major bugs are handled for stable releases
  49 [20:09] <didrocks> blfgomes: does this answer your question?
  50 [20:09] <slytherin> didrocks: with jaunty release gutsy will have end of life
  51 [20:09] <blfgomes> yes, it does! Thank you!
  52 [20:10] <didrocks> slytherin: yes, but we will have one more unstable version, so, no change for us :)
  53 [20:10] <didrocks> Today, we are going to update gnome-terminal. We will see quickly what are the different steps we have to handle generally to update packages, but the best is, of course, to practice!
  54 [20:10] <slytherin> right
  55 [20:10] <didrocks> Even if I use bzr-buildpackage now to work on, we will not use it today. The Unstoppable James Westby has given a great rocking introduction on this last week 
  56  (https://wiki.ubuntu.com/BeginnersTeam/FocusGroups/Education/Events/01172009).
  57 [20:11] <didrocks> Also, this lesson is not intended to teach you how to package. For this, see the corresponding courses in last developpers week session (https://wiki.ubuntu.com/UbuntuDeveloperWeek). Don't forget also the excellent packaginguide: https://wiki.ubuntu.com/PackagingGuide.
  58 [20:11] <didrocks> Well, ready? Let's download the old version: mkdir gnome-terminal && cd gnome-terminal && apt-get source gnome-terminal
  59 [20:11] <didrocks> This will download the last release present in jaunty, which is 2.26.0.
  60 [20:11] <didrocks> tell me when it's ok :)
  61 [20:12] <didrocks> Remember that you can interrupt the course at any level: even if you feel lost, we will find you! :-)
  62 [20:12] <francescom> I'm ready
  63 [20:12] <blfgomes> done
  64 [20:13] <didrocks> (let's wait for few seconds too ;))
  65 [20:14] <didrocks> ok, let's say that the others are too shy :) Let's get into the source package: cd gnome-terminal-2.26.0
  66 [20:14] <Pollywog> k I am ready too
  67 [20:14] <didrocks> To check if new release is available, if a debian/watch file is present, we just have to use: uscan --report --verbose.
  68 [20:14] <didrocks> The output should be something like this: http://paste.ubuntu.com/151393/. You can see there that a new version is available and corresponds to 2.26.1.
  69 [20:15] <didrocks> everyone has something similar to the pastebin?
  70 [20:15] <Pollywog> y
  71 [20:15] <Pollywog> yes
  72 [20:15] <francescom> yes, me too
  73 [20:15] <TheMadBeaver> yup
  74 [20:16] <didrocks> Excited by this new version? \o/ Let's get the new upstream code using uscan! This command just download the new archive, and extract its contents, whith the debian/ubuntu changes applied!
  75 [20:16] <didrocks> so, just executes uscan this time, with no option :)
  76 [20:17] <Pollywog> it is getting it
  77 [20:17] <didrocks> The output of the command is telling us that we have to do a "cd ../gnome-terminal-2.26.1" to get into the new package, let's do it (http://paste.ubuntu.com/151399/).
  78 [20:17] <didrocks> (yes, you can see that I prepared most of the lesson yesterday ;))
  79 [20:18] <francescom> done
  80 [20:18] <Pollywog> done
  81 [20:18] <TheMadBeaver> done
  82 [20:18] <didrocks> Easy, isn't it? Well, when the debian diff doesn't apply because of inline patch, it's getting more difficult, but most of packages are in good shape and every debian difference from vanilla version are 
  83  in debian/ directory.
  84 [20:18] <blfgomes> didrocks: what does it do under the hood to apply the diff?
  85 [20:19] <didrocks> blfgomes: it's downloading the vanilla tar file,
  86 [20:19] <didrocks> then, trying to apply ../gnome-terminal-2.26.0.diff.gz diff file
  87 [20:19] <didrocks> (this file contains the debian diff)
  88 [20:19] <blfgomes> and that's all?
  89 [20:20] <didrocks> exactly :)
  90 [20:20] <blfgomes> cool
  91 [20:20] <didrocks> it's also adding a new entry to debian/changelog
  92 [20:20] <didrocks> we will see that later :)
  93 [20:20] <blfgomes> ok!
  94 [20:20] <didrocks> Now begins the real packager work. We have to see what changed in upstream release reading the NEWS files (less NEWS and q to exit): http://paste.ubuntu.com/151409/
  95 [20:20] <Pollywog> do I need to apply a patch?
  96 [20:20] <Pollywog> or was it done for me?
  97 [20:20] <blfgomes> it was done for you
  98 [20:20] <didrocks> Pollywog: it was done for you
  99 [20:20] <Pollywog> k
 100 [20:20] <didrocks> Pollywog: seing the debian/ directory?
 101 [20:20] <didrocks> seeing*
 102 [20:21] <Pollywog> yes
 103 [20:21] <didrocks> this folder typically contains the changes from upstream to ubuntu :)
 104 [20:22] <didrocks> This is mostly a bugfix release. We will see later what have been fixed. Now, let's discover what changed in configure.{ac,in} file: diff -Nup ../gnome-terminal-2.26.0/configure.ac configure.ac
 105 [20:22] <didrocks> You will get http://paste.ubuntu.com/151411/
 106 [20:22] <didrocks> here are the changes from previous version to the last release
 107 [20:22] <didrocks> What is important in it? m4_define([gt_version_micro] change from 0 to 1 is to tell that a new version is available (2.26.0 to 2.26.1). That's just tell that upstream does a good job.
 108 [20:23] <didrocks> If it's not present, there is for librairies something like SHVER variable that you have to change in debian/rules. In every cases, it's good to give a look at debian/rules to see if the version number is 
 109  present or not.
 110 [20:23] <didrocks> Ok for everyone?
 111 [20:23] <blfgomes> yes
 112 [20:23] <francescom> didrocks: how do you know that only that file is changed?
 113 [20:24] <didrocks> francescom: no, I didn't say that :)
 114 [20:24] <didrocks> I just say that we have to look at this file, it's different :)
 115 [20:24] <francescom> didrocks: ok thanks
 116 [20:24] <didrocks> we will see why just after (all important changes for us are there)
 117 [20:25] <didrocks> ok for everyone, can we go on?
 118 [20:25] <Pollywog> yes
 119 [20:25] <TheMadBeaver> ok
 120 [20:25] <padawan> yes, following
 121 [20:25] <didrocks> What is most important here is the GTK_REQUIRED and VTE_REQUIRED change. That means that we have to bump the dependencies version request of the package (it will request now 2.14.0 for gtk and 0.20.0 for 
 122  vte librairies). This has to be changed in debian/control.in (or debian/control if there is not control.in file).
 123 [20:26] <didrocks> You can edit it with your prefered tool (vim ROCKS \o/) and change libgtk2.0-dev (>= 2.13.6) and libvte-dev (>= 1:0.19.1) to libgtk2.0-dev (>= 2.14.0) and libvte-dev (>= 1:0.20.0).
 124 [20:26] <blfgomes> didrocks: what's the difference between control.in and control?
 125 [20:27] <didrocks> blfgomes: control.in will generate control file. It just contains some automatisation ($GNOME-TEAM is remplaced by the team in charge, it also list the last uploaders of the package…)
 126 [20:28] <blfgomes> ok
 127 [20:28] <didrocks> So then, as there is a debian/control.in file, we have to generate a new debian/control file from it. This is proceed by executing: DEB_AUTO_UPDATE_DEBIAN_CONTROL=yes fakeroot debian/rules clean
 128 [20:29] <Pollywog> from which directory is that done?
 129 [20:29] <didrocks> Pollywog: from the source package one. You should list the debian/ folder from it
 130 [20:30] <slytherin> didrocks: won't control file generate automatically when you do debuild -S (I don't have source right now).
 131 [20:30] <didrocks> Pollywog: basically gnome-terminal-2.26.1
 132 [20:30] <Pollywog> k
 133 [20:30] <Pollywog> done
 134 [20:30] <didrocks> slytherin: most of the time, yes, when using bzr, it's good to generate it before
 135 [20:30] <didrocks> (because you will commit the previous revision)
 136 [20:31] <didrocks> Finally, inform of your change! dch -a and add to the file so that it will look like: http://paste.ubuntu.com/151422/. You see that the so kind uscan command has automatically created "gnome-terminal 
 137  (2.26.1-0ubuntu1) jaunty; urgency=low" for us.
 138 [20:31] <didrocks> tell me when it's done :)
 139 [20:32] <Pollywog> done
 140 [20:33] <didrocks> (this diff files between old and new configure.in files can also tell us from added/removed dependencies btw. There is no black magic there :D)
 141 [20:34] <didrocks> we lost everyone but Pollywog? :)
 142 [20:34] <Rail> we are here :)
 143 [20:34] <didrocks> great o/
 144 [20:34] <didrocks> Ok, now that build dependencies are ok, we have to see if ubuntu/debian patches still apply to the new version. The what-patch commands tells us that this package use cdbs. Let's try using cdbs-edit-patch 
 145  debian/patches/99_autoreconf.patch (the last patch in the queue).
 146 [20:34] <include_pr> were here
 147 [20:34] <didrocks> We exited in error in the debian/patches/30_honour_point_pixel_sizes.patch (http://paste.ubuntu.com/151427/).
 148 [20:35] <didrocks> That can means two things: either upstream has integrated the patch (or we took previously the patch from upstream svn), or that the code has been slightely modified and we can't apply it easily.
 149 [20:35] <didrocks> mean*
 150 [20:35] <didrocks> Looking at debian/changelog has to be the first thing to do: http://paste.ubuntu.com/151431/
 151 [20:36] <didrocks> In this case, we see a bug report LP: #345189 associated to the patch. Looking at it (https://bugs.launchpad.net/bugs/345189), we deduce that the change is present upstream, looking at the Fix Released 
 152  next to "gnome-terminal" upstream task.
 153 [20:36] <didrocks> Consequently, we can safely remove the patch, "rm debian/patches/30_honour_point_pixel_sizes.patch".
 154 [20:36] <blfgomes> question: should we always apply the last patch first?
 155 [20:37] <didrocks> blfgomes: no, but it's a good way to lost the less time as possible :)
 156 [20:37] <didrocks> you can apply them one by one
 157 [20:37] <Pollywog> I thought patches had to be applied in the order they were issued
 158 [20:37] <didrocks> but if you apply the last one, it will try to apply all the others before, in alphabetical order (for cdbs, quilt is quite different)
 159 [20:37] <Pollywog> issued > released
 160 [20:37] <didrocks> so, you know if it crashed or not
 161 [20:37] <blfgomes> oh, alright
 162 [20:38] <didrocks> Pollywog: when you apply the last patch in alphanumerical order with cdbs, it applies every others patches before
 163 [20:38] <Pollywog> oic
 164 [20:38] <Pollywog> didn't know that
 165 [20:38] <didrocks> that's why when applying 99_… it first failed on 30_… :)
 166 [20:39] <didrocks> So, here, patch is integrated upstream. That's why we removed it. If it wasn't the case and the cause was that upstream changed slightely its code, we had to cdbs ....patch and adapt it to make it apply 
 167  again.
 168 [20:39] <didrocks> That's why we have always to report our patch upstream (appart from specific ubuntu ones) :)
 169 [20:40] <didrocks> it's good for them, less work for us, everyone wins \o/
 170 [20:40] <didrocks> Ok, bring this information to debian/changelog: dch -a and report the change to make it look like that: http://paste.ubuntu.com/151442/
 171 [20:40] <didrocks> tell me when it's ok :)
 172 [20:41] <Pollywog> I will have to come back to it later... ready
 173 [20:41] <blfgomes> done
 174 [20:42] <didrocks> Ok! Let's go on with next patch: $ cdbs-edit-patch debian/patches/99_autoreconf.patch again.
 175 [20:42] <didrocks> The last patch doesn't apply /o\
 176 [20:43] <didrocks> That's pretty normal: autotools/autoconf/autoreconf patch are different from others patches. They basically consist of generating configure scripts from configure.in, makefile.in one (like 
 177  debian/control.in that generates debian/control file) and have to use generally the last revision of libtool to generate them
 178 [20:43] <didrocks> We have to exit first, without updating the patch: "exit 1"
 179 [20:44] <Pollywog> are you in a chroot?
 180 [20:44] <Pollywog> I do not understand the exit 1
 181 [20:44] <fenris-> 6 out of 478 hunks FAILED -- saving rejects to file configure.rej
 182 [20:44] <didrocks> fenris-: yes, that's why I told it failed
 183 [20:44] <didrocks> Pollywog: cdbs-edit-patch basically copy your files and drop you in a subshell
 184 [20:45] <Pollywog> oh
 185 [20:45] <didrocks> when exiting, it will diff /tmp/old /tmp/new > patch
 186 [20:45] <Pollywog> ic
 187 [20:45] <didrocks> (exiting with 0, if you exit in error, like exit 1, it will change nothing)
 188 [20:46] <didrocks> let me seek for a good introduciton about
 189 [20:46] <didrocks> introduction*
 190 [20:46] <didrocks> patch system
 191 [20:46] <fenris-> so : exit 1  ?
 192 [20:46] <didrocks> Pollywog: https://wiki.ubuntu.com/MeetingLogs/devweek0809/PackagePatches
 193 [20:46] <didrocks> fenris-: as just told previously, "exit 1" prevent from refreshing the patch
 194 [20:47] <didrocks> as it failed
 195 [20:47] <didrocks> we will regenerate the patch from scratch
 196 [20:47] <didrocks> this only work for this package with a jaunty box unfortunately (you need to have the last libtool version)
 197 [20:47] <Pollywog> ty
 198 [20:47] <didrocks> but I pastebin the result, so, you can follow
 199 [20:48] <didrocks> and as it is the last, but not least step, I have to show you this :)
 200 [20:48] <didrocks> so, what you can do, is to remove the patch: "rm debian/patches/99_autoreconf.patch"
 201 [20:48] <didrocks> Finally, $ "cdbs-edit-patch debian/patches/99_autoreconf.patch"
 202 [20:48] <didrocks> (it again drop you to a subshell)
 203 [20:48] <didrocks> and to generate the configure and makefiles: autoreconf
 204 [20:49] <didrocks> so, this takes Makefile.in to create Makfile, configure.in to create configure, and so on…
 205 [20:49] <didrocks> Once done (ignore the warnings), exit 0 to refresh the patch and document the change: dch -a to get http://paste.ubuntu.com/151449/
 206 [20:50] <didrocks> We have almost finished: every patches applies and build-dependencies are ok. Normally, you testbuild at this stage, but we won't do it as we are running out of time and not everybody has been abled to do 
 207  the previous steps
 208 [20:50] <Pollywog> k
 209 [20:50] <didrocks> Once done, a good practice is to put changes from the upstream NEWS file in the changelog. So, get the changes following the given link in the NEWS file and report it to the changelog. Extra bonus point 
 210  is given if you look at LP bugs corresponding to upstream correction and list them.
 211 [20:51] <didrocks> If this time-consuming work is well done, you will get this: http://paste.ubuntu.com/151454/
 212 [20:51] <didrocks> You can take a breath now! You have your new package updated! Think about testing it throughly and everything will be all right.
 213 [20:51] <didrocks> Now, rooms for remaining questions , just fire up! :)
 214 [20:51] <e-jat> sorry .. dc ..
 215 [20:51] <e-jat> didrocks: after exit 1
 216 [20:51] <didrocks> e-jat: yes ?
 217 [20:51] <didrocks> e-jat: if you have a jaunty box, you can do:
 218 [20:52] <didrocks> - rm debian/patches/99_autoreconf.patch
 219 [20:52] <didrocks> - cdbs-edit-patch debian/patches/99_autoreconf.patch
 220 [20:52] <didrocks> - autoreconf
 221 [20:52] <didrocks> - exit 0
 222 [20:52] <padawan> I followed _some_ of this, thanks for your time and sharing wisdom Didier
 223 [20:52] <didrocks> you will generate a new autoreconf patch
 224 [20:53] <Pollywog> I have the logs to go over and the links you gave
 225 [20:53] <didrocks> it was a please padawan. Take some time to look at basics for packaging first, hope you can refer to this afterwards :)
 226 [20:53] <didrocks> pastebin are not removed generally
 227 [20:53] <padawan> willdo, see you all soon, gnight
 228 [20:53] <didrocks> but be aware that few times after jaunty is out, this update 2.26.1 for gnome-terminal will be available
 229 [20:53] <blfgomes> didrocks: could you point us to a autoreconf/configuration files tutorial?
 230 [20:54] <didrocks> so, apt-get source gnome-terminal will download 2.26.1 :)
 231 [20:54] <didrocks> blfgomes: here is a great lesson about autools: http://www.lrde.epita.fr/~adl/autotools.html
 232 [20:54] <Pollywog> I thought it downloaded an older version
 233 [20:54] <didrocks> autotools* sorry
 234 [20:54] <Rail> didrocks: updating from upstream is OK, what about syncing from Debian?
 235 [20:55] <didrocks> Pollywog: yes, but when jaunty will be out, one of the first SRU will be this update :)
 236 [20:55] <Pollywog> oic
 237 [20:55] <e-jat> didrocks: after exit 0 ?
 238 [20:55] <didrocks> Rail: it all depends on the "project"
 239 [20:55] <Pollywog> I understand now
 240 [20:55] <blfgomes> didrocks: thanks!
 241 [20:55] <didrocks> e-jat: just update the changelog
 242 [20:55] <didrocks> e-jat: logs will be available soon :)
 243 [20:55] <didrocks> Rail: in desktop team, generally
 244 [20:55] <didrocks> as we are in advance from debian, why pushed changes back to debian with alioth svn
 245 [20:56] <didrocks> (removing specific ubuntu changes)
 246 [20:56] <e-jat> changelog in which folder ? debian @ gnome-terminal ?
 247 [20:56] <didrocks> e-jat: debian/changelog
 248 [20:56] <Pollywog> is alioth a PPA for Debian?
 249 [20:56] <didrocks> (one sec)
 250 [20:57] <didrocks> e-jat: http://paste.ubuntu.com/152293/
 251 [20:57] <slytherin> Pollywog: nope, it is the service where many teams from Debian maintain the packaging bits in version control systems (svn).
 252 [20:57] <Pollywog> oic
 253 [20:57] <didrocks> thanks slytherin ;)
 254 [20:58] <francescom> didrocks: thank you
 255 [20:58] <didrocks> Pollywog: some non debian developper can gain commit access to this svn
 256 [20:58] <Pollywog> ic
 257 [20:58] <blfgomes> one last question: why hasn't gnome-terminal been frozen yet?
 258 [20:58] <didrocks> blfgomes: gnome-terminal is frozen
 259 [20:58] <didrocks> we are at 2.26.0 in jaunty
 260 [20:59] <blfgomes> but you said there will be a 2.26.1
 261 [20:59] <blfgomes> in jaunty
 262 [20:59] <didrocks> you can see my pending request there : https://bugs.edge.launchpad.net/ubuntu/+source/gnome-terminal/+bug/361053
 263 [20:59] <slytherin> blfgomes: most of the gnome packages have standing freeze exception. when I say gnome packages it means the ones identified as official modules of gnome.
 264 [20:59] <didrocks> yes, once jaunty released, as GNOME 2.26.1 is mostly a bug fix, there is an exception for it
 265 [21:00] <didrocks> we update it through SRU process
 266 [21:00] <blfgomes> so, that would be a case of cherrypicking
 267 [21:00] <didrocks> blfgomes: the changes between 2.26.0 and 2.26.1 is really tight
 268 [21:00] <didrocks> most of packages have only translation update, for instance
 269 [21:01] <didrocks> this one, bumping dependencies is really exceptional
 270 [21:01] <didrocks> but as it was a real good example to see a lot of things, I choose it as a candidate for this lesson :)
 271 [21:01] <didrocks> dependency changes, patches that doesn't apply \o/
 272 [21:02] <blfgomes> :)
 273 [21:02] <didrocks> well, more questions or everything is clear in everyone's mind? :)
 274 [21:02] <didrocks> (practice and you will learn :))
 275 [21:02] <Pollywog> didrocks: thanks for the presentation
 276 [21:03] <e-jat> :)
 277 [21:03] <e-jat> thanks didrocks
 278 [21:03] <didrocks> again, thanks to all the attendees :)
 279 [21:03] <blfgomes> didrocks: thank you, it was really great!
 280 [21:03] <Rail> didrocks: tnanks!
 281 [21:03] <didrocks> have a nice day/evening/night everyone ;)
 282 [21:03] <e-jat> nite ...
 283 [21:03] <didrocks> next session for those interested will be "Package testing: piuparts and VMs" by dtchen. The 23rd April, 00:00 UTC.


CategoryPackaging

Packaging/Training/Logs/2009-04-16 (last edited 2009-05-02 17:36:26 by 99-21-107-94)