Tuesday, November 4, 2008

PHP and outputting floats

I was writing a script in PHP to compare two data sources, and in the report I was outputting using code like this:
echo "A={$vA}, B={$vB}\n";

What was strange is I was getting entries like
A=3.4E+6, B=340000
A=1.4E+6, B=1500000
A=2146666.66667, B=2.3E+6

My first guess was some data was int, so I added asserts for that, but, no, everything is float.

As often happens, the answer was to be found in the user contributed notes in the PHP online manual: http://jp.php.net/manual/en/language.types.float.php#83577

I just have to repeat his final sentence: I have to be honest: this is one of the strangest things I have seen in any language in over 20 years of coding, and it is a colossal pain to work around.

Also in the notes are complaints that output of floating point numbers uses the locale. Using number_format is one solution for that, or using %F in sprintf is also locale-independent apparently. So my code becomes:
echo sprintf("A=%F, B=%F\n",$vA,$vB);

Unfortunately that now gives me entries like:
A=481.000000,B=1150000.000000

I have hit this zero-noise issue using sprintf in C++ too.

So here is my solution (be aware that this adds CPU cycles):

/**
* Format a float, only showing significant decimal places
*
* @param float $v
* @return String
*/
function fmt_float($v){
$s=(string)$v;
if(strpos($s,'E+')===false)return $s;
$s=sprintf("%.9F",$v); //Write with all decimal places
$s=rtrim($s,'0'); //Chop off trailing zeroes
$s=rtrim($s,'.'); //Chop off decimal point if it is left at the end.
return $s;
}
...
echo "A=".fmt_float($vA).", B=".fmt_float($vB)."\n";

I'll throw that into the next fclib release. Can anyone make a better version?

Note: The first two lines mean use PHP's built-in float to string conversion by default and just use our own when it ended up in scientific notation. I found this gave better results (because using %.9F sometimes writes 120.0000000001 instead of simply 120.000000000, whereas the PHP built-in conversion is fine (giving "120") ). However if you also needed a locale-independent solution, then uncomment those first two lines (as PHP's built-in conversion uses locale).


Monday, October 20, 2008

Being emailled followups

A question about Blogspot seems best posted here! I noticed there had been some comments on other entries. Surely I'm not supposed to poll each article to see if there has been a new comment. I'm sure there was a setting to say to email me all follow-ups to all articles, but a recent search turned up nothing.
Anyway, thanks for the replies!! I want to try out the Actionscript suggestions I received and will then update the articles if they work (or even if they don't).

Wednesday, October 15, 2008

Microsoft SQL server and PHP

I'm a big fan of Pear::DB. (And, as an aside, I think the Pear decision to deprecate it was a bit strange.) But it didn't work for me for Microsoft SQL server (aka mssql), for one particular project (I'm fairly sure it has worked on other projects, so I think it was something specific to this environment). What did work was using the COM object.

COM objects from PHP are a bit of a black art, perhaps as most code examples seem to be in Visual Basic, which has a very different syntax. I found the following page useful, as it shows all three ways of running the same query for a mssql database:
http://www.webcheatsheet.com/PHP/connect_mssql_database.php

I think I also used the user comments in the online PHP manual.

One thing the above URL does not show is error reporting. Here is the code I developed, which also takes care of not treating 5701 and 5703 as errors (congrats to Microsoft on another poorly thought out API!):

//$db is the return from the new COM() call.
//...run some Open or Execute command on $db...
$errors=$db->Errors;
if($errors->Count==0)return ""; //It worked
$e='';
foreach($errors as $ix=>$error){
if($error->NativeError==5701 || $error->NativeError==5703)continue; //Information messages, not errors
$e.="Number={$error->Number}, Source={$error->Source}, SQLState={$error->SQLState}, NativeError={$error->NativeError}, Description={$error->Description}\n";
}
return $e;

Sunday, July 20, 2008

Centering multiline text fields in AS3?

This seems to be a regression-without-cure between AS2 and AS3. In AS2 I could write:
txt.wordWrap=true;
txt.align="center";
txt.htmlText="blah, blah, blah";

and each line in that text field would be centered.

In AS3 I am writing:
txt.wordWrap=true;
txt.align=TextFieldAutoSize.CENTER;
txt.htmlText="blah, blah, blah";

but it ends up left-aligned.
The bigger problem is that this is the documented behaviour: if wordWrap is set then align will not center text.

So, how do I center a multi-line text field?!!

(Time passes.)

I cannot believe there is nothing on the web about this. Have all the flash developers in the world stopped centering their text, or am I missing something obvious?

(More time passes.)

OK, after some trial-and-error I have a workaround, which sucks but will get the job done:

CopyA.htmlText='<body><p align="center">blah, blah, blah</p></body>';

Why do I say this sucks? Because I cannot (easily) apply it afterwards: I will need to get the current htmlText contents, detect the body tag and insert after it; and a corresponding closing-P tag at the end.

But in this application the text string comes from a DB and is allowed to contain HTML tags. What if it too already has a P tag? Will I get an extra blank line? Are P tags allowed to be nested?
(Well, I just tried, and it seems fine still, and if the inner P tag has an align that is the one that gets applied. So all good there.)

UPDATE: I discovered I can also write this:
CopyA.htmlText='<p align="center"><body>blah, blah, blah</body></p>';
That is dubious, and I wonder if it is future-proof, or if I am exploiting a bug? But it is obviously far easier, as it saves me having to do any parsing - I can just wrap whatever the existing htmlText is:
copyA.htmlText='<p align="center">'+copyA.htmlText+'</p>';

Tuesday, June 24, 2008

AS3 vertical gradient fills

The examples for gradient fills are either squares, or rectangles with the gradient going from left to right:
http://livedocs.adobe.com/flex/3/langref/flash/display/Graphics.html#beginGradientFill()

So, how do you make a horizontal rectangle, with a vertical linear gradient? Everything I've tried (i.e. rotating it 90 degrees) gives me a solid colour. Here is one failure example (270 degree rotation, then translated back the height).

s.graphics.beginGradientFill(GradientType.LINEAR,
[0x666666,0x666666],[0.9,0.1],[0,255],
new Matrix(0,-1,1,0,height,0));
s.graphics.drawRect(x,y,width,height);


(I'm actually giving up and will instead make this 9 pixel high gradient (a fancy drop shadow effect) by drawing 9 lines! But, please, somebody must have some sample code they can share?)

Boost Spirit, shadowing, and a trailing newline

I've never been a fan of Boost::Spirit. It adds loads of compile time (in fact, some code failed to compile when I only had 512Mb, solely due to spirit), and the source code has shadowed variables (which causes complaints if you switch all warnings on, and therefore causes failure if you compile with -Werror).

I sent a patch in against 1.33 for the shadowed variable problems. So you can imagine my disappointment when I tried to compile against boost 1.34.1 (that comes with Ubuntu 7) and the problems were still there and required me to hack the source code again.
But that was nothing compared to how I felt when my unit tests failed to run. No compile errors, they simply failed to parse. My code was unchanged; only the boost version had changed.

I have finally tracked this down to if there is a trailing carriage-return it won't parse it. I thought the space_p parameter to parse() would take care of that, and perhaps that is the behaviour that changed between 1.33.1 and 1.34.1??

But most frustrating of all is that none of these solutions work:
'\n'
"\n"
ch_p('\n')
*ch_p('\n')
+ch_p('\n')
str_p("\n")
*str_p("\n")
+str_p("\n")

Actually I'm out of ideas!

Here is a code snippet:
GameTree = ch_p('(')[bind(&SGFMoveList::on_game_start, this, _1, fname)]
>> RootNode[bind(&SGFMoveList::on_root_node_end, this, _1,_2)]
>> *Node[bind(&SGFMoveList::on_node_end, this, _1,_2)]
>> *VariationTree
>> !ch_p(';')
>> ch_p(')')[bind(&SGFMoveList::on_game_end, this, _1)]
>> *ch_p('\n');

parse_info<const char*> info=parse(str, *GameTree , space_p);


(I've left a ch_p('\n') in there at the end, just in case it is doing some good.)

So, my solution is to check info.hit instead of info.full! hit is true if the stuff you want matched; full is the same but only gets set if the whole input string got matched. In my case a carriage-return is not getting matched, so hit is true and full is false.

That is a bit crude and may be hiding a genuine problem. So I then have a look at info.stop (which is a pointer to the part of the input string that didn't get matched) to make sure it only contains whitespace.

If anyone knows what is going on please let me know. It amazes me that no-one else has noticed this regression in Spirit, so surely it must be something I'm doing wrong?

P.S. On the next project where I needed a parser I tried Hapy (http://hapy.sourceforge.net/) instead of Spirit. It was much faster and easier to use. Its downsides are practically no-one uses it, so not much documentation, community, etc.
On most projects since then I've used Boost::tokenizer wherever possible, going out of my way to avoid writing a real parser.
The above project, where I'm using Spirit, is complex, needs a real parser, and it works, hence my reluctance to port it to Hapy, or look for something else.

Monday, June 16, 2008

Flex/Flash accessing both network and local files

Flash wants you to be safe, which means a swf you make cannot access the network (not even localhost!) and read local files. This can be a pain when you have a swf file you trust (e.g. when you wrote it yourself)! But the bigger pain is how badly Adobe document the workaround, especially if you are on linux.

First the answer. As root, make /etc/adobe/FlashPlayerTrust/. Then if your trusted swf, and its files are in /home/georgebush/killforoil/ you make a file called:
/etc/adobe/FlashPlayerTrust/killforoil.cfg
and in that cfg file you put this line:
/home/georgebush/killforoil/

George is now able to continue to screw the world without those Adobe do-gooders getting in his way.

Adobe document this (for Windows/Mac) here:
http://livedocs.adobe.com/flex/3/html/help.html?content=05B_Security_01.html

(Why am I saying the document it so badly? Because everywhere else I looked, they say using use-network=true when you make your swf file means it can never access local files.)

Once I knew that FlashPlayerTrust was the key word, I was able to find these linux instructions (which also tell you how to do per-user configurations):
http://www.abdulqabiz.com/blog/archives/flash_and_actionscript/flash_player_trust_f.php

Sunday, June 15, 2008

Gnome file associations, AIR and ZIP

I thought I'd conquered the black-box that is gnome file association configuration (see http://darrendev.blogspot.com/2008/05/gnome-whether-under-redhat-or-ubuntu-is.html)
but I'm stuck again.

Since installing Adobe AIR for linux it has associated itself with zip files. So the icon is now AIR, and the default action is to open AIR (and so when I double-click a zip file it gives me an error saying this isn't an AIR file). The only way I can open zip files is by right-clicking them now.

How do I remove that association and restore archive manager? I don't know. AIR hasn't installed anything in /usr/share/mime. And I cannot see anything in the myriad of configuration directories that live under my home directory. So, where else does gnome get its file association information from?

Please help!

Tuesday, June 3, 2008

Stopping make delete intermediate files

I wanted a makefile to compile mxml (Adobe flex, aka Flash 9) files into swf files and play them automatically. In other words I wanted to just type "make test2" and it would compile test2.mxml into test2.swf, then open test2.swf in the flashplayer.
The hardest part was that, with the automatic rules, make insisted on deleting the "intermediate" file. But in this case the intermediate file was the swf itself. There is a ".PRECIOUS" rule that appears designed for this purpose that made no difference. After much trial, error and banging my head against the keyboard until it bled, it seems setting ".SECONDARY" to blank was the solution. Here is the full makefile (saved in a file called Makefile, in the same directory as my mxml files):

MXMLC=/usr/local/src/flex3sdk/bin/mxmlc

.SECONDARY:

% : %.swf
flashplayer $<

%.swf: %.mxml
$(MXMLC) $<



This makefile is generically useful for when you want to compile and run something; especially when experimenting with lots of small individual files.

Monday, June 2, 2008

Bidirectional unicode codes and Arabic

I have been importing Arabic data into MLSN (http://dcook.org/mlsn/) (incidentally, almost all data currently comes from the AWN project). We have a csv list of synonyms, and each synonym optionally has the Arabic root in square brackets. The whole list is an SQL string, surrounded by single quotes.

When I view in SciTE it looks exactly as I'd expect: the arabic is right-to-left, the square brackets are part of the flow, and then at the apostrophe we're back to left to right. (By the way, vi appearance is the same as SciTE)
But in gedit, firefox and open office writer, when the last synonym has a square bracket it gets jumbled up.

Here is how it looks in scite:


Here is how it looks in gedit:


So, I tried adding the unicode RLE (0x202B) character before the opening square bracket and before the closing square bracket. (Incidentally, in the tab-separated file this fixed the problem in all editors.)
In SciTE no change, which is good.
In gedit et al it now has the square brackets in the flow correctly, but it has been moved to the end of the line and the following SQL clauses are now right-to-left.
Putting a unicode LRE (0x202A) before the following comma did not help! (More precisely it moved the ",'awn');" part back into the left-to-right flow, but still left the Arabic string stranded on the right; but anyway the LRE on the comma causes MySQL problems, see below.)

Is this is a bug in all of gedit, firefox and open office? Could it be a linux or gnome bug and all those applications happen to use it, while SciTE/vi do not? Or am I doing something wrong? Any advice gratefully received!

Here is how it looks in gedit with the explicit RLE codes:



MySQL and Bidirectional Codes

It seems MySQL (after doing "SET NAMES UTF8;" of course), can cope with LRE/LRE inside a quoted string, but they cannot be in the SQL string itself. E.g. on a comma.

Firefox, IE6 and Bidirectional Codes

Without the RLE codes firefox messed up showing the square brackets in both normal display and in an edit form. With the RLE codes, just before each open and each close square bracket, it shows it correctly in normal display, but still gets it wrong in the HTML form input box.
(As an aside, IE6 on Windows XP is the opposite of firefox! The main table is (very) wrong but the edit box is correct!) (And as an aside to my aside, if there is one thing Windows does well it is i18n fonts: the Arabic looks beautiful.)

phpmyadmin has a textarea that shows it correctly (with firefox). They use an explicit dir="ltr" (?!). Using that did not work for me.

So, my solution was when the edit form is being used for Arabic is to dynamically set dir to "rtl", and "ltr" the rest of the time. And (for the IE users) also set dir="rtl" on the Arabic cells, and dir="ltr" on other cells, in the main table. There is no Arabic UI currently, but when there is the dir="rtl" will be set globally via a style sheet (which is why I set the default dir="ltr" explicitly on data cells for non-Arabic languages).

See it in action by doing a search on MLSN. Here is one example: http://two.dcook.org/software/mlsn/main.php?c=06car0
(mouseover the table cells, then clicking the cell will make the edit form active; compare Arabic with the other languages.)

I am open to suggestions for alternative solutions, but I believe this is the "proper" standards, cross-browser solution.

Tuesday, May 27, 2008

Install PHP pecl intl module for ubuntu 7.10 (PHP 5.2.3)

The "intl" extension (which gives you the ICU library, see http://www.icu-project.org and http://pecl.php.net/package/intl) requires PHP 5.2.4 or later.
Ubuntu 7.10 comes with 5.2.3. However the changes required are quite minor.

Note: all the following steps need to be done as root.

First make sure both php5 and php5-dev packages are installed.

Next go to /usr/lib/php5/build/ and replace the acinclude.m4 file with the one here:
http://cvs.php.net/viewvc.cgi/php-src/acinclude.m4?revision=1.387

(This is to get the [PHP_SETUP_ICU] macro, which was added in php 5.2.4)

Next, go to /usr/include/php5/main/ and open php_config.h and at the end add this line:

#define HAVE_PTRDIFF_T 1


Now you should be ready to do the install, which is as simple as:

pecl install intl


It will download a 150K file, and compile and install it.

At the end it says to add a line to php.ini. Assuming you want the intl extension in both the apache module and the cli version of php, then go to /etc/php5/conf.d/ and create a file called intl.ini and in that file put this single line:

extension=intl.so


A quick way to check it all worked is to type:

php -i | grep intl


If it didn't work you will see nothing. If it worked you'll see a line talking about "intl.default_locale".

Sunday, May 18, 2008

Controlling file associations in Gnome

Gnome, whether under redhat or ubuntu, is very hard to configure. Especially controlling the behaviour when you double-click on a file. However I may've got it cracked.

First, the easy way, is right-click a file, choose properties, and there is the open with tab. The setting there affects all files with that extension. (I still think that is one of those things that isn't even obvious once you know about it!)

But sometimes that is not enough. E.g. *.as files were associated with x-applix-spreadsheet, instead of my text editor. And then it then complains I'm trying to open a suspicious file.

Solution: I created this xml file as
/usr/share/mime/packages/actionscript.xml:


<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
<mime-type type="application/x-actionscript">
<comment>Actionscript</comment>
<glob pattern="*.as">
</mime-type>
</mime-info>

Wow, that seemed to do the job!

sprouts on linux

I've been using sprouts for AS3 on linux as a way to get straight into developing without having to learn about the tools or libraries I need. I'm not sure I'll continue using it once I get into more serious work, as it is a bit opaque (i.e. as with just about any framework, it is easy to do things it does by default, and really difficult to do anything else) and is based on ruby which is not one of my favourite languages.

It has also not been very smooth to use and install, which is what the rest of this article is about.

I'm following the instructions on:
http://www.projectsprouts.org/getting_started.html

on ubuntu. I had ruby installed, and just installed the gem package
(i.e., sudo gem --help then worked). (I also needed to install the rake package.)

But the following line fails:

sudo gem install sprout
Bulk updating Gem source index for: http://gems.rubyforge.org
ERROR: While executing gem ... (Gem::GemNotFoundException)
Could not find sprout (> 0) in any repository

Ah, simply trying it again works. Note that it will ask about all the "required" dependencies. If they are truly "required" then no choice but to say "Y"?

$ sudo gem install sprout
Bulk updating Gem source index for: http://gems.rubyforge.org
Select which gem to install for your platform (i486-linux)
1. sprout 0.7.171 (mswin32)
2. sprout 0.7.171 (darwin)
3. sprout 0.7.171 (x86-linux)
4. sprout 0.7.171 (ruby)
5. Skip this gem
6. Cancel installation
> > 3
Install required dependency rubyzip? [Yn]
Install required dependency archive-tar-minitar? [Yn]
Install required dependency rails? [Yn]
Install required dependency rake? [Yn]
Install required dependency activesupport? [Yn]
Install required dependency activerecord? [Yn]
Install required dependency actionpack? [Yn]
Install required dependency actionmailer? [Yn]
Install required dependency activeresource? [Yn]
Install required dependency net-sftp? [Yn]
Install required dependency net-ssh? [Yn]
Install required dependency needle? [Yn]
Install required dependency open4? [Yn]



Next, this line fails:
sprout -n as3 SomeProject

Run "gem contents sprout" to see it has been installed in:
/var/lib/gems/1.8/gems/sprout-0.7.171-x86-linux/bin

It is not executable so:
cd /var/lib/gems/1.8/gems/sprout-0.7.171-x86-linux/bin/
sudo chmod +x sprout

You can temporarily add it to the path with:
export PATH=$PATH:/var/lib/gems/1.8/gems/sprout-0.7.171-x86-linux/bin

This now works:
sprout -n as3 test1


But:
cd test1
rake

fails with the line: "no such file to load -- sprout".


This seems to do the trick:
rake -I /var/lib/gems/1.8/gems/sprout-0.7.171-x86-linux/lib/


Q. Where do I set that so it is a global setting??


Another problem: when I double click a swf file it tries to open it in
movie player. I try to connect to flashplayer, but that name does not
exist in /usr/bin.
Q. Where has the standalone flash player been installed??

Monday, May 12, 2008

fl.motion.easing open source

I've been trying out TweenLite (http://blog.greensock.com/tweenliteas3/), but it relies on the fl.motion.easing package, which is only available to paying Adobe customers.

However the actual code is by Robert Penner under a BSD-license: http://www.robertpenner.com/easing/

Based on the suggestion here (http://www.actionscripts.org/forums/showthread.php3?t=144172) ) I've taken the AS2 code and made an AS3 version, under the same BSD license. I cannot believe that no-one else has done this before, but if they have I certainly couldn't track it down.

TODO: put the zip file up here.