[Home]

Summary:ASTERISK-03757: [patch] Inband DTMF Signalling Behavior (In 1.0.x and Head)
Reporter:damin (damin)Labels:
Date Opened:2005-03-24 10:45:48.000-0600Date Closed:2005-10-11 23:12:41
Priority:MinorRegression?No
Status:Closed/CompleteComponents:Core/General
Versions:Frequency of
Occurrence
Related
Issues:
Environment:Attachments:( 0) breaks_inband_dtmf.txt
( 1) chan_sip-1.0.5-1.0.6-diff.txt
( 2) dtmf_fix.patch.txt
( 3) sip_debug_broken.txt
( 4) sip_debug_fixed.txt
( 5) what_i_did_to_fix.diff.txt
( 6) Playtones.txt
Description:dmtf=inband behavior has changed somewhere between 1.0.5 and 1.0.7 such that Polycom phones require dtmf=rfc2833 to correctly pass DTMF information. This could potentially affect other UAs.

****** ADDITIONAL INFORMATION ******

This was originally reported in the RC candidate testing (ASTERISK-3658) for 1.0.7, and no real answer was given. We have since narrowed it down to a change that has happened since 1.0.5. I have not had the resources to get in and get the specific information on what version of the chan_sip driver caused the change. It would be helpful if someone could help us narrow down what the changes might be between the versions.
Comments:By: Kevin P. Fleming (kpfleming) 2005-03-24 10:51:21.000-0600

OK, here's a method to deal with this.

Go to http://asterisk.bkbits.net, choose "asterisk-1.0-cvs". Click "Browse the source tree", then "channels" and the "CSets" link next to chan_sip.c.

At that point you will be looking at all changes to chan_sip.c, each changeset listed individually, going backwards in time.

By: damin (damin) 2005-03-24 11:40:09.000-0600

I'll see if I can put some more meat on this and narrow it down later tonight. I have an early morning maintenance window (3:00 AM EST) so I'll not be able to be up too late, but I might be able to track this down during the long downtime as we rsync 1/2 TB. ;)

By: Olle Johansson (oej) 2005-03-24 16:08:05.000-0600

rtp.c has no changes between 1.0.5 and 1.0.7

By: Olle Johansson (oej) 2005-03-24 16:26:46.000-0600

hmmm. This is weird. Can not find any changes in regards to inband between 1.0.5. or 1.0.7. We're closing RTP channels in different places... Need some more info.

By: damin (damin) 2005-03-24 17:53:14.000-0600

Just tested this by forcing my 7960 to inband DTMF. I can report that inband DTMF is broken for 7960 as well.

By: Olle Johansson (oej) 2005-03-24 17:57:02.000-0600

We need someone to test "sip show channel" during a call to see if we have INBAND for that call. If we have, then there's something fishy in RTP and we need to know how far back we have to go to find a working rtp.c - or?

By: damin (damin) 2005-03-24 18:33:11.000-0600

I tested this both with a "sip show peer" and "sip show channel" during a call, per Marks' suggestion on the developer's conference this afternoon. In both cases, DTMFmode was set as inband. I am in the process of reverting chan_sip.c to 1.0.5's to test if the problem is still there (as reported by someone else). If it is, we at least have a timeframe to start checking, and we can incrementally increase revision by revision until we find where it breaks.

By: damin (damin) 2005-03-24 21:03:58.000-0600

Off topic question: Has anyone told Digium that their FTP server has problems w/ hosts behind NAT? I am unable to download anything when connecting to it from behind NAT, but I can connect with everything else.

Now.. I was able to grab copies of 1.0.5 and 1.0.6 and do some further testing. Here is what I found:

Phone        1.0.5   1.0.6   1.0.7
----------------------------------
Polycom      Yes     No      No
Cisco        Yes     No      No
Grandstream  Yes     Yes     Yes

In other words, the Grandstream phone just seems to work no matter what version of Asterisk I use, but the other two fail on everything after 1.0.5. So, consider this confirmation that something is definitely wacky, and that we know where it stopped working. So we can work forward patch by patch from 1.0.5.

My next test is going to be to use 1.0.5 w/ 1.0.7's chan_sip and see if it really IS chan_sip that might be the problem.

By: damin (damin) 2005-03-24 21:24:53.000-0600

I'm going to go out on a limb and say that chan_sip is the culprit here. I took chan_sip.c and acl.c from 1.0.7 (because the patch from ASTERISK-3029 is required for chan_sip) and Cisco and Polycom's fail. Repeat, the only changes are to use 1.0.7's chan_sip w/ 1.0.5 and inband DTMF is fubarred.

I'm going to see if I can narrow this down any more.

By: Olle Johansson (oej) 2005-03-25 01:58:22.000-0600

Check RTP/SIP debug of the grandstream and make sure it only sends inband and nothing else like RTP and INFO... Just to be sure of what we're looking for.

By: Olle Johansson (oej) 2005-03-25 02:13:47.000-0600

check for changes in ast_dsp_process as well

By: Olle Johansson (oej) 2005-03-25 02:55:21.000-0600

dsp.c hasn't changed at all between these versions...

By: Mark Spencer (markster) 2005-03-26 01:24:07.000-0600

Can you attach a diff between the 1.0.5 and 1.0.7 versions of chan_sip then?

By: damin (damin) 2005-03-26 08:07:54.000-0600

I did one better. 1.0.6 exhibits the behavior, so I attached a diff of .5 to .6 chan_sip. Hopefully this will narrow it down a bit.

If we don't get any breakthrough's on this tonight, I'm going to do a progressive checkout of CVS starting at 1.0.5's release and moving forward week by week to see at what CVS date the behavior starts appearing. If you see something before I start that process, please let me know so I can use that time more effectively on this bug.

edited on: 03-26-05 08:49

By: Mark Spencer (markster) 2005-03-26 10:48:16.000-0600

so, just to confirm, it is only necessary to change this chan_sip.c (and acl.c) to be able to generate the issue, correct?  Assuming that to be the case, I would think the most likely portion of the patch to be the culprit is the moving of the SDP portion, although even after extensive review I don't see where that's tripping it up.  If possible find someone to see if the p->vad structure is NON-NULL when sip_read is called (look for the ast_dsp_process call).  Also, see if setting the option *globally* works versus on a per-peer basis.  Thanks!

By: damin (damin) 2005-03-26 13:59:44.000-0600

To be more specific, I took 1.0.7's chan_sip.c and acl.c and dropped them into 1.0.5. Then I rebuilt and installed the chan_sip.o module. I restarted Asterisk and the behavior was visible.

By: Mark Spencer (markster) 2005-03-27 16:56:01.000-0600

1.0.6 was enough to do it right?

By: damin (damin) 2005-03-28 19:54:07.000-0600

From my initial testing, 1.0.6 exhibits the behavior. I have not had the opportunity, nor free time to devote to going through CVS day by day to find the specific patch. It is not looking like I'm going to have much time this week to devote to it, so if someone else has the time and ability, please don't hesitate to help out. It would be nice to have this confirmed by someone with greater abilities than myself.

By: damin (damin) 2005-04-02 10:16:51.000-0600

Still very pressed for time, and was hoping to be able to replicate this this afternoon, but we are selling our house and have an Open House tommorow, which means I'll be cleaning all damn weekend long.

By: Terry Wilson (twilson) 2005-04-10 16:20:50

I have had problems with dtmf since stable was updated for bug 3660.  Reverting the change fixes everything for me.

By: nick (nick) 2005-04-10 19:08:05

The patch in ASTERISK-3580 was also applied to HEAD... has anyone tested if this problem exists there as well?

Nick

By: damin (damin) 2005-04-11 09:08:40

Alright.. Now we are getting somewhere. I was able to isolate the specific patch that causes the issue. Per Nick's last posting, I am able to confirm that chan_sip from 2/25/05 works fine, while 2/27/05 breaks inband DTMF detection. I can also confirm that http://bugs.digium.com/bug_view_page.php?bug_id=0003660 contains the patch that causes the issue.

The difference is about 11 lines of code. I've attached a diff of the patch for review.

I'm going to re-open 3660 so that the patch can be updated and re-applied to stable before 1.0.8 is dropped.

By: nick (nick) 2005-04-11 18:52:11

Has anyone tested if this problem exists in head?

NB

By: Terry Wilson (twilson) 2005-04-12 11:55:09

My problem (though different, results from the same patch) occurs also in head.  One of our SIP providers does not send that he can support oob dtmf but will accept it/use it if they get a response that we support it (messed up, but that is how their equip works).  Since 3660, if we get an INVITE from them, Asterisk generates a 200 OK without the 101 for rfc2833 DTMF in the SDP (even though the sip.conf entry for them has dtmfmode=rfc2833).  We do not register with them, but determine based on the IP.

By: Olle Johansson (oej) 2005-04-12 13:23:46

Terry: SIP DEBUG please...

By: Russell Bryant (russell) 2005-04-12 21:03:41

Can someone pleeeease test this stuff on CVS HEAD?

If nobody wants to, then can someone donate a SIP phone to me?  It kills me to not be able to work on this.

By: Kevin P. Fleming (kpfleming) 2005-04-13 00:45:19

twilson: As mentioned in the other bug, we _cannot_ offer any RTP media in our OK response that was not offered in the peer's INVITE. Setting 'dtmfmode=rfc2833' is not going to affect that, it only controls what we will respond to _if the peer offers_.

Can anyone who can reproduce this problem upload a 'sip debug' trace of the working and non-working cases?

By: Terry Wilson (twilson) 2005-04-13 11:07:14

kpf: I understand that, but here is the problem.  Asterisk isn't doing any kind of DTMF that I can tell in the case where the audio stream is in g729.  Is it not better to send DTMF *some* way in this case?  Maybe a setting in sip.conf that that allows an override like forceg729oobdtmf=yes or (info|rfc2833) or something since asterisk won't do inband g729 dtmf (not that it should)?

Anyway, I did a sip debug (using inband for everything) on a test box for you and what it looks like is happening on mine is that the phone itself is saying that it can support rcf2833 dtmf, so irregardless of the fact that the peer has dtmfmode=inband on it, asterisk doesn't start up the inband dtmf detector.

BTW: this was on CVS-HEAD from a few minutes ago.

Attaching file sip_debug_broken.txt

Also attaching:
what_i_did_to_fix.diff.txt and sip_debug_fixed.txt

The fix is just basically sloppily reverting the patch without checking to see if it breaks anything else.  Just showing that moving the code back to where it was fixes this particular issue.

edited on: 04-13-05 11:08

edited on: 04-13-05 11:20

edited on: 04-13-05 11:22

By: Terry Wilson (twilson) 2005-04-19 11:38:43

Just checking to see if anyone is working on this?  I attached al of the debugging info and more that was requested...

Been looking at it myself and here is what I've got so far.  The Polycom phones for instance will send DTMF based on what the capabilities it gets back from the proxy.  Even though the sip peer is set for dtmfmode=inband, when the call comes in from the polycom it contains that it support oob dtmf.  We respond that we support oob dtmf as well so it sends it.  But, since the peer is marked as dtmfmode=inband, we don't seem to be processing the oob dtmf (I have done a dump and the dtmf is arriving on the asterisk box oob).

check_user_full sets the noncodec capability how it should... process_sdp overwrites it with the incorrect value...

Of course, what we should be doing is responding that we don't support oob dtmf since the peer that is calling has it set to 0--even if the phone is sending that it supports it.  Trying to read through the code and come up with a patch...

edited on: 04-19-05 13:51

edited on: 04-19-05 14:11

By: Terry Wilson (twilson) 2005-04-19 16:08:54

Attached (dtmf_fix.patch.txt) is a simple patch that fixes the inband DTMF problem.  It basically just changes process_sdp to never completely override what was already in p->noncodeccapability.  Whether this is what everyone else will want, I'm not sure.  But, it should allow the patch in 3660 to actually work in the described situations.

It seems that by the time we get to process_sdp we should always have a good value in p->noncodeccapability, so this patch shouldn't cause any problems--of course others should check it out just to be sure.

Patch is against head, but since it is only one line it should be easy to port.  :-)  Disclaimer (although it is a one-liner) on file.

edited on: 04-19-05 16:11

By: Kevin P. Fleming (kpfleming) 2005-04-20 10:22:57

OK, the real root of this problem is that we don't do "allow/disallow" for DTMF modes, we just assume we know what the peer will offer and hope that our end is configured to do the same. The ideal situation would be to enhance the dtmfmode parameter to actually accept a list of formats and only allow those which are specified, but that's a bigger change.

This patch does appear to have the desired effect, in that it will force us to only offer what has been specified in the peer entry, even if the SIP peer offers to use a different mode. In that situation, if you have 'dtmfmode=inband' and you allow both ulaw and G.729 for that peer, when the peer wants to use G.729 and RFC2833, and we reject the request for RFC2833, the call may very well fail... but that's not a bad result, given that inband DTMF doesn't work in complex codecs anyway.

Anyone else want to chime in on this patch before I commit it?

By: damin (damin) 2005-04-20 12:28:40

I would agree that it is better to fail a call for incompatible Codec / DTMF signalling rather than to complete it. From a user's perspective, implementing a new system and having it partially work is a lot more annoying than having a system that forces you to design it right to work in the first place. Would it be possible to implement some idiot proofing logic at registration that would print out a console message when someone chose incompatible codec and DTMF settings? I'd imagine that given the flexibility of everything else in Asterisk, it is likely possible that one can create all sorts of totally broken and non-working configurations. I will apply this patch to my development boxes tonight and test the behavior to ensure that it works as advertised.

By: Kevin P. Fleming (kpfleming) 2005-04-20 12:41:50

No, at registration time we have no idea what DTMF mode the peer wants to use, and there's no guarantee that it won't change on a call-by-call basis anyway.

By: damin (damin) 2005-04-20 13:01:09

Maybe not at registration, but what about when the configuration is read from the .conf files?

By: Terry Wilson (twilson) 2005-04-20 15:19:32

It would be nice if we could also implement something that is basically a fallback like the g729forcedtmf=(info|rfc2833) as kind of a catchall for the failure case. If it happens to be set then in process_sdp if you can determine what the codec is going to be, then you go ahead and allow the override since you are doing g729 and the peer is labled as inband.  The allow/disallow seems to be the best way to fix it, but since people are having problems now, this might be a nice fallback until something better is implemented (fixed is always better than broken).

By: damin (damin) 2005-04-20 21:30:09

Uhh Ohh.. Doesn't compile cleanly on cvs-stable:

gcc -pipe  -Wall -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -g  -Iinclude -I../include -D_REENTRANT -D_GNU_SOURCE  -O6 -march=pentium3   -DZAPTEL_OPTIMIZATIONS  -DASTERISK_VERSION=\"CVS-v1-0-04/20/05-22:27:56\" -DINSTALL_PREFIX=\"\" -DASTETCDIR=\"/etc/asterisk\" -DASTLIBDIR=\"/usr/lib/asterisk\" -DASTVARLIBDIR=\"/var/lib/asterisk\" -DASTVARRUNDIR=\"/var/run\" -DASTSPOOLDIR=\"/var/spool/asterisk\" -DASTLOGDIR=\"/var/log/asterisk\" -DASTCONFPATH=\"/etc/asterisk/asterisk.conf\" -DASTMODDIR=\"/usr/lib/asterisk/modules\" -DASTAGIDIR=\"/var/lib/asterisk/agi-bin\"     -DBUSYDETECT_MARTIN      -Wno-missing-prototypes -Wno-missing-declarations   -DZAPATA_PRI   -DIAX_TRUNKING   -DCRYPTO -fPIC    -c -o chan_sip.o chan_sip.c
chan_sip.c: In function `set_destination':
chan_sip.c:3000: `peernoncodeccapability' undeclared (first use in this function)
chan_sip.c:3000: (Each undeclared identifier is reported only once
chan_sip.c:3000: for each function it appears in.)
make[1]: *** [chan_sip.o] Error 1
make[1]: Leaving directory `/usr/src/asterisk/channels'
make: *** [subdirs] Error 1

By: Kevin P. Fleming (kpfleming) 2005-04-20 23:38:20

The things people are asking for here are opening Pandora's box... you basically want to allow/disallow combinations of codecs, which is far more complex than chan_sip can currently do (and certainly won't go into stable in any case).

I think the best we can do here is to support some sort of allow/disallow behavior for DTMF modes; if you allow RFC2833 and the peer chooses to use it with ulaw, so be it, you won't be able to stop it.

By: Michael Jerris (mikej) 2005-04-21 14:49:08

Notes from devcall from kpflemming, bkw, and me, Proposed solution:

Cover 3 cases.  

If dtmfmode=info, then if peer offers rfc2833, log warning and send info.  Still connect call.

If dtmfmode=rfc2833, If peer does not offer 2833, log warrning, send rfc2833, still connect call.

If dtmfmode=inband, if the peer offers 2833, accept it, send rfc22833, if they don't offer 2833, and codec != alaw, ulaw, or g726, then issue warning that inband dtmf will not work on complex codec (codecname).  Connet call.  Still send inband.  If not offered 2833, and codec is dtmf capable, turn on dsp and send inband.

Additionally, confirm that we will properly process rfc2833 frames no matter what mode we think we are in.

Need comments on this implementation.  This should add more compatability then we have now, allowing some badly configured calls to connect, offering warnings when necessary when dtmf will not work on the call.

By: damin (damin) 2005-05-01 12:44:11

I think the three cases defined above are fine, and I agree that it will allow some badly configured endpoints to complete calls, trying to guess the best method to use for the call. However, I wonder if this is trying to hard? By that I mean that we should probably be a lot more rigid about completing calls for misconfigured endpoints. Imagine the new user setting stuff up incorrectly, and having it still work. Then, down the line, something minor changes and because of the complex if/then/else logic implemented we stop completing the calls. I think it is better to force end-users to configure their equipment properly then to let them use broken options.

This is my two cents, and really is a much deeper question regarding the phillosophical vision for Asterisk and how it should be designed. In deference to that vision being clear, I'd vote for the implementation of a patch that handles the conditions that were defined above.

By: damin (damin) 2005-05-01 12:48:07

Additionally, I'd like to get this wrapped up and implemented in stable fairly quickly. There are several people out there waiting for this to be corrected before upgrading from 1.0.5, and it is an issue that I think is fairly important.

By: Michael Jerris (mikej) 2005-06-08 07:17:30

Do we have any volunteers or a bounty for this one?

By: damin (damin) 2005-06-08 15:12:52

This was discussed a bit w/ Russell, Mark and KP Flemming on the 6/2/05 Developers conference. As I understoof it (please correct me if I'm wrong) Rusell + Mark and the folks at Digium were going to Lab this up and try to knock it out. I haven't heard as to what the status is of that. Perhaps we can get a comment from Rusell on this?

By: Olle Johansson (oej) 2005-06-09 01:38:30

A side note: If we have qualify=yes on a peer and send options, some peers will properly return an SDP that we can parse and use for changing the peer configuration in regards to DTMF.

Another side note: We need to check how Asterisk responds to OPTIONs... :-)

By: Russell Bryant (russell) 2005-06-14 16:05:24

On the dev call, damin claimed that beyond the issues described here about the interaction of different dtmf modes, inband dtmf is totally broken in 1.0.

I have this labbed up at my desk right now.  I am able to pass inband dtmf from my Cisco 7960 without any problems.  I'm going to need some help recreating this if it is still a problem ...

By: Enzo Michelangeli (enzo michelangeli) 2005-06-21 07:26:09

One thing I've noticed is that SendDTMF() does not work if dtmfmode=inband, and the same is true for PlayTones(), which uses the same primitive: see e.g. my (unanswered) post at http://forums.digium.com/viewtopic.php?t=313 .

I also made an attempt at locating the origin of the problem running Asterisk under gdb, but I suspended it waiting to see if others had noticed the same problem. I'm attaching the notes I had taken at that time, but I'm not sure they make sense as I'm far from a clear understanding of the program's logic. I'm attaching them anyway (in the file "Playtones.txt") in case someone may find them useful.

Enzo

By: Olle Johansson (oej) 2005-07-20 12:48:30

Where are we with this issue report?

By: damin (damin) 2005-08-12 19:48:03

I'm going to lab this up at home based on my previous notes here tonight and see what I can figure out. I've got some new perspectives and tools to use from ClueCon that might help the process out. Also, Joseph <syscon@interbaun.com> posted something to -dev tonight complaining about the same problem. I'm going to test this w/ the current stable CVS tonight and my Cisco 7960 w/ 7.4 firmware.

By: Joseph_s (joseph_s) 2005-08-12 20:36:40

dtmfmode=inband was working OK till (and including) ver. 1.0.5; since ver.1.0.6 it stopped working.  Now, I'm on ver. 1.0.8 and it still hasn't been fixed.

There is no point entering ver.2.0 if standard features aren't beeing fixed.

I have standard analog phones connected to Sipura SPA-3000 units (two of them), I have a SIP phone and "dtmfmode=inband" is not working with any of them.

When I dial my mailbox and type password it is not beeing recognized.
When somebody dial IN from PSTN line the internal extensions are not recognized.

dtmfmode=rfc2833  works OK

#Joseph

By: Michael Jerris (mikej) 2005-09-02 20:15:41

damin, do you have any update on your testing and labbing this up?  Also, are you able to lab this up with both current CVS v1-0 and CVS HEAD branches so we can conclusively verify if this is still in both or just in v1-0.  Thanks.

By: Michael Jerris (mikej) 2005-09-09 20:03:14

One more update request.  Calling anyone to perform this testing please.

By: John Lange (johnlange) 2005-09-10 00:29:32

I'm going to add this note here even though I have not finished thorough testing of all scenarios. If someone would like me to test something specific please let me know.

Situation:

PSTN = Cisco SIP Gateway connected to a PRI/T1 interface. Configured to talk to asterisk doing ulaw and inband only.

PAP2 Device = Linksys PAP2 adapter

Asterisk = Asterisk 1.0.9 configured to do canreinvite=no in all cases (so it stays in the media stream at all times).

Grandstream GXP-2000

So the following scenarios are :

PAP2 <---> Asterisk <---> PSTN (via Cisco)

or

PAP2 <---> Asterisk <---> PAP2

or

PAP2 <---> Asterisk <---> Grandstream


Scenario Results:

1) PAP2 device set to inband, asterisk dtmfmode=inband:
- PSTN works
- Voicemail works
- Asterisk IVR works

2) PAP2 device set to auto, asterisk dtmfmode=inband:
- PSTN broken
- Voicemail broken
- Asterisk IVR broken

3) PAP2 device set to auto, asterisk dtmfmode=rfc2833:
- PSTN works (but flaky. Tones are often choppy or clipped. Many customer complaints)
- Voicemail works
- Asterisk IVR works

4) PAP2 device set to inband, asterisk dtmfmode=rfc2833:
- PSTN works
- Voicemail broken
- Asterisk IVR broken

5) PAP2 device inband asterisk dtmfmode=rfc2833:
- Grandstream dtmfmode=rfc2833: broken (can't hear DTMF sounds, just clicks)
- Voicemail broken
- Asterisk IVR broken

6) Grandstream inband, asterisk dtmfmode=rfc2833:
- PAP2: works (can hear DTMF sounds)
- Voicemail broken
- Asterisk IVR broken

Post a note here or contact me directly john.lange at open-it.ca if you want more testing or have a question.

By: Michael Jerris (mikej) 2005-09-10 01:46:00

so if I am reading the notes properly, a correctly configured system works properly?

By: Olle Johansson (oej) 2005-09-10 06:56:15

Can you capture the INVITEs and 200 OK SDP's in the different cases so we can see what's going on in the auto mode, what is being sent. I guess RTP debug needs to be turned on.

By: Kevin P. Fleming (kpfleming) 2005-09-14 21:13:47

There is also now a 'dtmfmode=auto' in CVS HEAD that may very well help this situation. See http://www.voip-info.org/tiki-index.php?page=Asterisk%20sip%20dtmfmode

By: Michael Jerris (mikej) 2005-09-24 19:01:58

suspending this bug due to no response.  If anyone is able to produce the requested information please re-open this bug.

By: damin (damin) 2005-10-11 20:22:29

Astricon Update: Russell and I labbed this up in the Code Zone w/ a Grandstream and SJPhone. The results are that 1.0-cvs (as of today) works fine w/ both sides configured correctly for Inband DTMF. I.E. the SIP devices are configured for inband AND the peer statement is forced to inband.

johnlange posted that inband DTMF on the Device and rfc2833 on the peer statement is broken. I just confirmed w/ Olle, and chan_sip should listen for all types of DTMF, and only disable Inband in one particular situation. So, ostensibly, MY bug is ready to be closed, but johnlange MAY have found a different bug relating to the behavior of misconfigured devices.

My feelings are that if this is indeed the case, and john can reproduce it, he should go ahead and open a New Bug for the 1.0 tree entitled "chan_sip DTMF auto-detection problem" and detail his testing results there.

By: damin (damin) 2005-10-11 20:23:25

Tested at Astricon 2005 Code Zone.