Wednesday 31 December 2008

Happy New Year!

(What more is there to say?!)

I wish you all all the best for 2009 and look forward to 'seeing' you next year!

Until then... enjoy :).

Tuesday 30 December 2008

symfony - upgrade1.2 and Propel 1.3 DSN

Yup, I have been fiddling around with symfony some more!
Since I installed the latest stable build of symfony (1.2.1), I decide to upgrade my projects using:

symfony project:upgrade1.2

The command processed fine but then all hell broke loose so to speak. Basically, the whole project went kaput. So...
I then ran the magic (that is in the non-PHP sense) command:

symfony plugin:publish-assets

Which fixed all my sfGuardPlugin issues!

My next problem was related to propel. I had my databases.yml file configured like so:

all:
propel:
class: sfPropelDatabase
param:
phptype: mysql
database: anxcity
dsn: 'mysql://root@localhost/anxcity'

I kept getting an Access denied error for user 'ODBC' which was strange since my DSN contained the user: root.

So... I tried the long form of the databases.yml declaration like so:

all:
propel:
class: sfPropelDatabase
param:
phptype: mysql
hostspec: localhost
database: anxcity
username: root
port: 3306
encoding: utf8
persistent: true

Then the system complained it wasn't receving the DSN string as planned.
So... I just added it:

dsn: mysql:dbname=anxcity;user=root;host=localhost;port=3306

That seems really trivial BUT ... you do need to use the exact string syntax for it to actually work (which is very different to the DSN string in my original configuration file).
And hey presto!

Thoughts?

Edit:
Ah yes, forgot to say I had to rebuild the model too, using:

symfony propel:build-model

Sunday 28 December 2008

symfony - Ajax is not defined

I have been working on a small Ajax project using symfony - really trying to figure out how to get the nifty ajax functionalities working (using link_to_remote for instance).

I kept getting Ajax is not defined or Draggable is not defined errors and spent a couple of hours searching for the solution. Anyway, I finally came across this command:

symfony plugin:publish-assets


This got it all working for me - it simply copied the 'assets' (js scripts) to my /web folder. Simple :).

More code soon...

Thoughts in the meantime?

Thursday 4 December 2008

Installing symfony - setting up the virtual host 2

Just a quick clarification on my previous post about setting up virtual hosts, which seems to be a little misleading.

You do also need to define your localhost as follows:

<VirtualHost *:80>
ServerName localhost
DocumentRoot "/path/to/www"
DirectoryIndex index.php
</VirtualHost>

(localhost should already be defined in your hosts configuration file).
This way you can still access all your other applications.

Thoughts?

Tuesday 25 November 2008

Installing symfony - setting up the virtual host

Well, here is another thing that I have learned using symfony.

The basic installation tutorial instructs you to set up a virtual host for symfony:

<VirtualHost *:80>
ServerName myapp.example.com
DocumentRoot "/home/steve/myproject/web"
DirectoryIndex index.php
Alias /sf /$sf_symfony_data_dir/web/sf
<Directory "/$sf_symfony_data_dir/web/sf">
AllowOverride All
Allow from All
</Directory>
<Directory "/home/steve/myproject/web">
AllowOverride All
Allow from All
</Directory>
</VirtualHost>


This was all new to me, so I set up "all" the paths correctly, and found that while it did allow me to use my symfony application properly and all the data_dir links where effectively aliased as planned, it also broke my other "localhost" links (e.g. I could no longer access http://localhost/other_app). Ouch.

Now I have figured out why: I hadn't changed the ServerName. So, the issue was solved by simply creating a new ServerName like so:

ServerName symfonyappname.localhost


To get this working the operating system must also be configured accordingly. To do this, simply add an entry to your hosts file, the location of which depends on which OS you are using.

Check out this link to find out where your hosts file is located.

Once the hosts file is properly configured (remember you may need to reboot), simply type:

http://symfonyappname.localhost

and magic happens :).

Thoughts?

Monday 24 November 2008

A visual aid for RAID

Just a quick recap of how the most common RAID can be used for recovery (or not...).



Thoughts?

Thursday 13 November 2008

Netbeans support for Symfony

Now here's a nice and chewy piece of news posted by ppisl from netbeans.org:


The news is that the Symfony support will be part of NetBeans 7.0. We are going to start work on it very soon. I hope that it will be a part of continual build this year and community can comment the support and work with us to finish it in the best possible quality and usability.


This is straight from the Netbeans "issues" site: Issue 145913. You can vote to advocate Netbeans support for symfony from that same page. 468 votes so far...

According to the roadmap Netbeans 7.0 will probably be released around April 2009. It will be exciting to see how this pans out with the release of symfony 1.2 due in December of this year.

Anyone else looking forward to this?

Saturday 1 November 2008

CSS - Choosing colors

A colleague pointed me to this article recently (no offense taken :D). In my view, there are quite a few interesting things there, but still I think using HTML tables for layout is conceptually bad, even wrong, especially today.

Among the good stuff, this interesting link to do with colors and how to choose colors that actually work well together.

They have developed a useful ColorTool applet which you can access via:
PC version
Mac version

You can choose the background color, then select various text colors to go with it (by clicking first on the line of text you would like to change).

Rather clever.

Thoughts?

Saturday 25 October 2008

Plugin installation failed: No valid packages found

Well, I am still exploring symfony and its many interesting options. One of the features that really appeals to me is the ability to secure certain actions (e.g. "create", "save") for a given module (e.g. "user" module, "group" module) using user credentials (e.g. "admin", "guest"). The only catch is that this inbuilt mechanism doesn't provide login per se which means you can set credentials, but have to create the login process yourself. The most obvious way to avoid this is simply to install the sfGuardPlugin plugin for symfony.

I typed the installation command but came across the following:


cmd>> symfony plugin:install sfGuardPlugin

>> plugin installing plugin "sfGuardPlugin"
>> sfPearFrontendPlugin downloading sfGuardPlugin-3.0.0.tgz ...
>> sfPearFrontendPlugin Starting to download sfGuardPlugin-3.0.0.tgz (18,752 bytes)
>> sfPearFrontendPlugin .
>> sfPearFrontendPlugin .
>> sfPearFrontendPlugin .
>> sfPearFrontendPlugin ...done: 18,752 bytes
>> sfPearFrontendPlugin symfony-plugins/sfGuardPlugin requires package
>> sfPearFrontendPlugin "symfony/symfony" (version >= 1.2.0, version <= 1.3.0,
>> sfPearFrontendPlugin excluded versions: 1.3.0), installed version is 1.1.4

Plugin "sfGuardPlugin" installation failed: No valid packages found


The problem here was simply that the latest version of the package was being used. That particular version (3.0.0) is meant for symfony 1.2 which is still being developed. Since I am using the latest stable release of symfony (1.1.4), the trick is simply to specify which release to install. To work this out, simply check out the sfGuardPlugin changelog page to find the correct release version number (2.2.0).


cmd>> symfony plugin:install sfGuardPlugin --release=2.2.0


And hey presto, it worked! Excellent. More on symfony soon...

Thoughts in the meantime?

Saturday 18 October 2008

Adobe Flash 10 released

It looks like it's "sniffer-update" time again... quite a few sites seem to have 'broken' with this new release, at least in Internet Explorer.

Here's a quick way of detecting the Flash version using ActiveXObject:


function testFlashIE() {
var flashMajor=0;
var flashInstalled=false;
try {
flAXO = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
flVersion = flAXO.GetVariable("$version");
flMajor = flVersion.substring(
flVersion.indexOf(" ")+1,
flVersion.indexOf(","));
flashInstalled=true;
flashMajor=flMajor;
}
catch (e) {} // ignore

if (!flashMajor) {
// here comes the usual flash detection loop
// for older versions
// ...
}

return flashInstalled?flashMajor:null;
}


Thoughts?

Tuesday 14 October 2008

PHP Development Frameworks

As mentioned in a couple of previous posts (here and here), I have been looking into symfony as a PHP Framework solution and it's certainly one of the most comprehensive on the market. The following article at PHPit compares ten well-known PHP development frameworks including Zend, cakePHP and symfony.

Although the article is most probably outdated where facts are concerned (with comments dating back to 2006), most of the criteria on which the comparison is built are still very much up-to-date. They cover inbuilt support for: PHP5, Model-View-Controller (MVC), Object Relational Mapping (ORM), Caching, Validation and filtering, Ajax, Authentication, and more.

Still, I feel a development framework shouldn't simply boil down to supporting X or having inbuilt Y, and should in a sense embrace a wider philosophy as a whole.

Thoughts?

Wednesday 24 September 2008

Aptivate Web Design Guidelines for Low Bandwidth

The NGO Aptivate, Cambridge, UK, brought together some useful information about simple bandwidth optimisation techniques/issues.

You can access their Web Design Guidelines for Low Bandwidth at:
http://www.aptivate.org/webguidelines/Home.html


Don't worry about bandwidth!
Soon we will all have infinite bandwidth for no cost.


Heard that before?

In fact it is not true for the majority of the world's population. Many people in remote locations and the developing world do not have fast Internet connections and won't be getting them any time soon.

This is why Aptivate has written a set of Web Design Guidelines for Low Bandwidth, at a time when web site optimisation seems to be going out of fashion.


Very interesting to see the world statistics for bandwidth and Internet access costs. Just goes to show how lucky we are in Western Europe / North America!

Also, here are a couple of the "tips" which particularly caught my attention:

  • drop using HTML tables for layout, switch to CSS: this has been discussed over and over and over, again and again and again, and yet... well, you get my drift =);

  • make your site cacheable: basically, avoid getting too wild with dynamic content;

  • externalise your CSS stylesheets and JS scripts: load it (them) only once for the whole site or sets of pages and let the browser subsequently use the cached version;

  • minimize the use of HTTP requests: there are lots of ways to do this like client-side form validation using Javascript, making sure dynamic pages don't require looping back to the server for pulling in extra files (CSS, images, etc.), and so on and so forth.

  • file and image optimisation: shrink PDF and optimise images for use on the web;

  • provide some sort of support for 'old' browser versions which may have limited support for CSS, Javascript, etc.

  • ...



There is a lot more interesting information on the site covering a variety of topics: high-level design, CSS, caching, compression, multimedia, browser compatibility, search, PDF optimisation, and much more. Well worth the read!

Thoughts?

Wednesday 17 September 2008

PHP 5.2.0 - installing PEAR

I tried to install PEAR a few days ago using my PHP 5.2.0 install by double-clicking the go-pear.bat file in the php5 folder.

It didn't quite go as planned however:

Initialized registry...
PHP Warning: Cannot use a scalar value as an array in phar://go-pear.phar/PEAR/Command.php on line 268
.
.
.
install failed


It seems there is a small bug in the .phar file (in the PEAR folder) which can be fixed by replacing it with the following file:
http://pear.php.net/go-pear.phar

And you can find more information about this issue here:
http://bugs.php.net/bug.php?id=39733

Thoughts?

Monday 15 September 2008

Finding the value in LinkedIn

I have been quite surprised by the number of people who complain about LinkedIn being a) a complete waste of time and/or b) just a plain 'job search' application. Obviously you could make it just that but also alot more, it really depends on how much time and effort you are prepared to invest.

To make an analogy, you wouldn't create a mailbox and then instantly expect to receive 300 interesting emails overnight. In fact, if you get any interesting mail at all it's because you have taken the time to advertise your email address in one form or another.

So why do we expect socializing online to be any different from socializing offline? If you walk into a room full of people, grab a drink and then go and stand alone in a corner, what are your chances of engaging with people? Pretty meak; at least certainly much slimmer than for those who decide to actively engage in conversation.

That's why we 'use' (sorry, bad bad word) our network of friends and relations to get introduced to other people. The same goes for LinkedIn. You need to mimick your real social network, get introduced to others by people you know and trust and move on from there.

The greatest value of the network to me is being given the ability to contact hundreds of experts, people who would previously have remained unreachable, in mere seconds.

A few weeks ago, I was trying to find a comprehensive, cost-effective CRM 'solution'. Now, there are lots of applications out there: sugarCRM, XRMS, Microsoft Dynamics CRM, Zoho and many more.

One way to figure out which is the 'best' solution is to test each application and then try to weigh the pros and cons, and drop cost into the balance somewhere. Now, that can be pretty time-consuming and without being an expert yourself, you can't really guarantee end-result.

Another way to work out the 'ideal' course of action is simply to ask the question on LinkedIn using their Q&A feature. The beauty in this is you reach out to hundreds of experts who might spend let's say 1 to 10 minutes answering your question. Within 24-hours you are actually conversing with more people than you would have been able to get hold of by phone in a day.

And, there is no question that the 10-minutes they spent answering, were much more valuable than my searching for information that isn't in my field of expertise. And, to top it all off, it was great fun corresponding with all the people who replied. Much like in 'offline life' we can engage in a valuable exchange of ideas and knowledge.

So, IMHO, there really is much more to social (or business, as some would have it) networking than at first meets the eye.

What is your take?

Sunday 14 September 2008

symfony sandbox project, tutorial updated

In a previous post, I discussed a couple of issues relating to the symfony project sandbox tutorial.

It looks like the tutorial has since been updated however and I haven't really had the chance to check out the latest version but the parts that were highlighted in my post have definitely disappeared! Good news... :-)

To tell you the truth, I would like to move on to creating a web application from scratch (i.e. without the sandbox) so I will be starting at square one: The Definitive Guide to symfony and hope to be sharing some of this with you in coming weeks.

Thoughts in the meantime?

Wednesday 10 September 2008

Google Chrome EULA update

In an earlier post about the Google Chrome EULA I mentioned how the French version had yet to be amended.

Well, I checked yesterday and all's well that ends well :-).

In French...

11.1 Vous conservez les droits d'auteur et tous les autres droits en votre possession vis-à-vis du Contenu que vous fournissez, publiez ou affichez sur les Services ou par le biais de ces derniers.

... and Dutch

11.1 U behoudt de auteursrechten en enige andere rechten die u al bezit over de inhoud die u op of via de Services inzendt, plaatst of weergeeft.


Thoughts?

Saturday 6 September 2008

PHP Fatal error: func_get_args(): Can't be used as a function parameter

Well, I was a little surprised about this message but then reading the documentation it all made sense.

The only way around this is to place the result of func_get_args() in a variable and then pass that variable to the function you were calling in the first place instead of func_get_args().

WON'T WORK:

my_func(func_get_args());


WILL WORK:

$func_args=func_get_args();
my_func($func_args);


This is because the func_get_args() function must get called in the right context to return the right values as explained in the PHP documentation (PHP.net func_get_args):

Note: Because this function depends on the current scope to determine parameter details, it cannot be used as a function parameter. If this value must be passed, the results should be assigned to a variable, and that variable should be passed.


Interesting.

Thoughts?

Friday 5 September 2008

Google Chrome - user-agent (UA)

For anyone interested in browser detection, here is Google Chrome's "useragent" string:
Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.27 Safari/525.13

You can get it by simply typing "about:" in the omnibox ("address" bar)
or alternatively by adding the following to your <head> section.


<script language="javascript">
function showUA()
{
userAgent = navigator.userAgent;
alert("UserAgent: " + userAgent);
}

window.onload=showUA;
</script>



So something similar to the following could be used to detect which browser you are using:


<html>
<head>
<script language="javascript">
function setBrowser()
{
var browser="unknown";
var userAgent = navigator.userAgent.toLowerCase();
if (userAgent.indexOf("opera") > -1)
browser="Opera";
else if (userAgent.indexOf("konqueror") > -1)
browser="Konqueror";
else if (userAgent.indexOf("firefox") > -1)
browser="Firefox";
else if (userAgent.indexOf("netscape") > -1)
browser="Netscape";
else if (userAgent.indexOf("msie") > -1)
browser="Internet Explorer";
else if (userAgent.indexOf("chrome") > -1)
browser="Chrome";
else if (userAgent.indexOf("safari") > -1)
browser="Safari";

var brDiv=document.getElementById("browser");
brDiv.innerHTML="<b>" + browser + "</b>";
}

window.onload=setBrowser;
</script>
</head>
<body>
You are using:
<div id="browser"></div>
</body>
</html>


If you are using one of those popular browsers its name should show up in the empty "browser" div in the body section. Note that the order of the tests is critical. For instance, both Opera and Netscape useragent strings contain "msie" so it is necessary to test for those browsers before testing for Internet Explorer.

Of course the above script is certainly very basic and we could take things a step further and not only retrieve browser name but also browser version for instance, or test for other things like whether the browser is Java-enabled, which Javascript version is available, which Flash Player version is installed or which operating system is being used.

Let me just share a couple of links which cover this more comprehensive approach to Javascript browser sniffing:
Browser sniffing: takes an in-depth look at how to sniff all major and lots of minor browsers.
JavaScript Browser Sniffer: the "ultimate" mainstream browser detection script.

Have fun!

Thursday 4 September 2008

Google Chrome EULA

As you have probably already heard, there has been huge concern that the Google Chrome EULA was too invasive with regard to intellectual property rights. Google has since changed the English version at: http://www.google.com/chrome/eula.html?hl=en

Google apparently blamed a hasty copy/paste for the mistake but it is a little worrying to think this may have been intentional, and how many people have actually already agreed to the EULA in question.

[EDIT: I take it the change will have retro-active effect.]

Here is the Ars Technica article describing the whole chain of events:
http://arstechnica.com/news.ars/post/20080903-google-on-chrome-eula-controversy-our-bad-well-change-it.html,
and how Google has promised to change its terms and conditions for the new browser.

The French version (http://www.google.com/chrome/eula.html?hl=fr) doesn't seem to have been amended at the time of writing:

En fournissant, publiant ou affichant le contenu, vous accordez à Google une licence permanente, irrévocable, mondiale, gratuite et non exclusive permettant de reproduire, adapter, modifier, traduire, publier, présenter en public et distribuer tout Contenu que vous avez fourni, publié ou affiché sur les Services ou par le biais de ces derniers.


Something to keep an eye on...

Thoughts?

[Update: Check out the follow-up post regarding the Google Chrome EULA]

Wednesday 3 September 2008

Experimenting with Google Chrome

(Thank God for work and the XP box there!)

I have downloaded, installed and survived the Google Chrome experience.

As far as I can tell it really lives up to expectations: on first impression its user interface is very nice and crisp, the browser is fast and renders nicely.

It's definitely usable "as-is" and despite being beta could probably replace any browser for day-to-day browsing except perhaps in some rather specific cases which some have been reporting.

Feature-wise, you can seamlessly extract a tab to a new window or reassemble tabs located in separate windows into a single window.

The developer tools are another cool feature. It would be really nice if you could snap them into your current tab though (or have the "snap-in" appear in every tab once you open it). For the moment, the tools open in an new window which stays on top of everything you are doing in the browser and I found it was a major distraction (compared to using Firebug in Firefox for instance).

Last but not least, the "omnibox" in every tab is a really nice feature which I shall probably learn to miss in other browsers.

Well, that's it for now. As you can tell I didn't really have the chance to take it for an in-depth test run and look at security features for instance.

It will be interesting to see whether Google's new approach actually causes any disruption on the browser market.

What do you think?

Tuesday 2 September 2008

Aaaaaaaaaargh

Just one simple question... (*sobs despairingly*)

When (if ever) will Google Chrome become available to Win2k users?

Google Chrome

So Google has been at it again with this new very engaging project: Google Chrome, an open source web-browser with lots of impressive ideas with regard to stability, speed, security, standards and much, much more.

I have heard the site to keep an eye on today for a fresh copy is:
http://www.google.com/chrome

If you are interested, there is an nifty explanatory comic book by Scott McCloud at:
http://blogoscoped.com/google-chrome/

In it, the Google Chrome project is detailed from several angles, plus you get to 'meet' lots of people who are working on the project. Their take was basically to create a browser which would be more in line with today's web applications (coming at it from a very different angle than when browsers were used to process plain web pages, with little or no: DOM manipulation, AJAX scripts, etc.).

  1. Stability, testing and multi-process architecture:
    Using processes instead of threads to improve stability and prevent memory bloat as well as building on other Google tools to improve test efficiency.

  2. Speed: Webkit and V8:
    Increasing speed and efficiency by using Webkit and a high-performance javascript virtual machine called V8.

  3. Search and user experience:
    Changing the tab controls and their uses; introducing the omnibox, elegant inline completion and improved popup handling; improving user experience with a compelling "new tab" page which holds the most visited pages and search sites.

  4. Security, sandboxing and safe browsing:
    Preventing attacks by sandboxing (jailing) each separate process and helping users to avoid phishing scams using up-to-date blacklists of harmful sites.

  5. Gears, standards and open source:
    Using gears to improve developer experience, complying with standards (and perhaps setting new ones?), and of course sharing.



All of this really sounds very impressive, it seems Google is simply always that one step ahead of everyone else!

More news about whether this was all too good to be true, once I actually get to try it out, which I hope will be very soon :-)

Thoughts for now?

Friday 22 August 2008

Batch programming tip #17: Moving/Copying hidden/system folders and files

A recent question about renaming a folder (on computing.net) brought to my attention the fact that move (which I usually use to rename folders) and also rename won't work on hidden/system files.

To avoid this 'issue' you must change the folder's system attributes.
First we define our original and destination folders.

set oldp=[define original folder here]
set newp=[define destination folder here]

Then we set the h (hidden) and s (system) attributes off (-h -s), move the folder, and switch the attributes back on again (+h +s).

attrib -h -s %oldp%
move %oldp% %newp%
attrib +h +s %newp%

You can also change all the file attributes within the folder, by using the /S modifier. And all (sub-)directories by using /D.

For instance:

attrib -h -s %oldp% /S /D


Will switch off the hidden and system attributes for (sub)folders and files in the %oldp% folder.

The same sort of thing happens with xcopy.
If you want to use xcopy on hidden/system files you must add the correct modifiers like so:

set oldp=[define original path here]
set newp=[define destination here]
xcopy %oldp% %newp% /H /S

Or only "visible" files will get copied.

I would love any additional input you may have about this.

Thoughts?

Thursday 21 August 2008

Symfony sandbox project

I recently heard of the Symfony project. It's an appealing free open-source PHP5 development framework licensed under the MIT license and I decided to give it a go.

For starters I downloaded the sandbox version from:
http://www.symfony-project.org/installation/1_1

I had an easy-PHP installation already up and running on my Windows 2000 system. So simply dropped the sandbox project under my www folder and followed the instructions on the Symfony website using mySQL as database manager:
http://www.symfony-project.org/tutorial/1_1/my-first-project

It was all pretty straight-forward except for a few "catches" detailed below.

#1 - the project uses php.exe on the command line to generate configuration files, PHP classes, etc. You really need to make sure to copy the php.ini file to the folder where the php.exe is located in order for the configuration to be taken into account. You can check which modules are available (and in effect, whether your latest php.ini is getting loaded properly) by typing
php -m
on the command line.

#2 - I also activated the xsl extension. This gets rid of some error messages that occur during database configuration and creation. I am not sure whether this makes an actual difference on the end result but was trying to clear any errors as I ran into them.

#3 - When I tried to access http://localhost/sf_sandbox/web/frontend_dev.php/comment or http://localhost/sf_sandbox/web/frontend_dev.php/post as specified in the tutorial, the pages wouldn't launch properly, I was getting database error messages.
To avoid this, I had to manually configure the www\sf_sandbox\config\database.yml configuration file:

all:
propel:
class: sfPropelDatabase
param:
phptype: mysql
database: symfony_project
dsn: 'mysql://root@localhost/symfony_project'

I changed all three parameters: phptype, database (use the database name you chose), and dsn (note that root is using an empty password to connect here).
For changes to take effect, make sure to clear the cache using:
php symfony cache:clear

#4 - In the middle of the tutorial, it tells you to start using your new website.
However, when you try to add a comment you get the following error:
Class "Post" must implement a "__toString" method to be rendered in a "sfWidgetFormPropelSelect" widget
To fix this, open the
sf_sandbox\lib\model\Post.php
and add a __toString method as follows:


class Post extends BasePost
{
function __toString()
{
return $this->getTitle();
}
}


To be 100% accurate, also change the sf_sandbox\apps\frontend\modules\comment\templates\editSuccess.php file so that the Post id label becomes Post title or simply Post since the post title is what we're actually seeing now we have added the __toString method in the Post class.

#5 - I couldn't get the following to work:

Next, open the modules/comment/templates/editSuccess.php and replace the following lines:

<tr>
<th>Post:
<td><?php echo object_select_tag($comment, 'getPostId', array (
'related_class' => 'Post',
)) ?></td>
</tr>


The original code is slightly different in the sandbox version and the replacement code wouldn't work. One way to avoid this issue is to set the default post id in your comment actions class.
Simply open your sf_sandbox\apps\frontend\modules\comment\actions\actions.class.php and add the following in the "executeCreate()" method:

$post=PostPeer::retrieveByPk(
$this->getRequestParameter('post_id'));
if ($post)
{
$this->form->setDefault('post_id',
$this->getRequestParameter('post_id'));
}

This simply pre-selects the post title in the form when you access the 'new comment' page from a given post's page by setting the default value of the drop-down choice list.

#6 - in the same file (sf_sandbox\apps\frontend\modules\comment\actions\actions.class.php). Instead of using the code from the tutorial, simply replace the redirect line with:
$this->redirect('post/show?id='.
$request->getParameter('comment[post_id]'));

This will redirect to the correct post rather than to the comment page.

Well, that's it for now. I haven't finished the tutorial yet. I have only made it to just before the Form Validation chapter. So still lots of fun to be had - stay tuned!

Thoughts in the meantime?

[EDIT: it looks like the Symfony Sandbox Project tutorial has been updated so some - if not all - of the above information may no longer be applicable.]

Wednesday 20 August 2008

Me.dium - Power to the People

In a comment left on a previous post about Cuil not quite living up to previous expectations, Chris pointed me to the Me.dium search engine (built on Yahoo Search BOSS). This alpha-release search engine offers two search types: you can opt for traditional results but also decide to 'get social' and view the 'hottest' results according to what other people are viewing.


Me.dium.com has taken a different tack. We have a full web index, but we change the results based on the surfing activity of our user base (now over 2,000,000).


The searching activity data is gathered using the Me.dium search toolbar. Obviously, you don't have to install it yourself unless you actually want to become part of the crowd - but with this new "Power to the People" philosophy, it's being part of the crowd that empowers you as an individual surfer. Based on the tutorial, it seemed a little too invasive (teenager-ish?) for me: you can see which of your friends are online, what they are currently viewing, chat with them, etc. and, even if the feature can be disabled, I am not sure I want to share that amount of intimacy with my friends when at work or at home. But it's probably just one of those things I will change my mind about as more and more people choose to use it.

We all know Web 2.0 really is all about 'social': social networking, social bookmarking, social learning, you name it, it has social in front of it. Well, this new engine brings 'social' to the search industry.

When you use social search, you get extra information for every link in your result set:
- crowd rank: not sure how this works, perhaps there is a rank button on the toolbar, a bit like the Google page rank (?);
- velocity: whether site traffic from the crowd is stable, increasing or decreasing;
- recent activity: how 'hot' the site is (luke-warm, warm, hot);
- visitors present: whether anyone from the crowd is currently visiting;
- average visit duration: "short", "medium" or "long" (?);
- navigate from and to: how most of the crowd moves to or from the link.

So you actually get quite a lot of additional information about each search result.

It will be interesting to see in what way the search results are influenced by the crowd, I guess it could (hypothetically) lead to all sorts of biases, but also to a good way of measuring what most people are interested in or in fact (want to) believe.

I couldn't help but wonder whether the propagandists could get hold of this, but I get the feeling that's a typical Web-2.0 non-argument. A bit like the kind of argument you may have against corporate wikis/forums/blogs. The top 'guys' always have the gut feeling the system will be used and abused whereas in actual fact, the vast majority of people are pretty level-headed and once they get the hang of the system actually use it in constructive ways. It seems to me that the more people use this system, the better the results will be and the lesser the impact of small groups of people who may want to sway the search results one way or another.

And there is always the Yahoo-based standard search to fall back on if you are not getting what you want.

There were a couple of minor things I noted when using the search engine.
There was one feature I really missed: the word suggestions. For instance, I wasn't quite sure how to spell Musharraf so guessed at Musharaf, I was expecting the search engine to automatically suggest the correct spelling - it's a bad habit, but a great feature that most Google users have probably grown used to.

Another thing I found as an avid Googler who doesn't ever press the "I'm feeling lucky" button (shameful I know...), was that using the "I feel social" button really didn't come naturally. I think the location of the button and the use of the word 'feel' set the alarm bells a-ringing in a "don't-click-me" kind of way.

One last thing I felt was missing was the ability to sort the search results by crowd rank, recent activity, average visit duration, etc. as this could certainly increase search relevancy. But I guess there is only so much you can expect from an alpha release especially with this level of stability! :-)

So, Me.dium definitely looks promising, and it's really top-notch: if there were any glitches, I certainly didn't notice them. AND it's bringing something really new to the search market so it's worth staying tuned to see how this project will evolve and whether it can get hold of any significant share of the search market.

Thoughts?

Tuesday 19 August 2008

Netbeans 6.5b released

The Netbeans 6.5b was released last week and can be downloaded here. The full installer weighs in at around 200Mb.

To my knowledge this is the first "release" to include the PHP module. The previous version, dubbed "Early Access For PHP" required a separate download and wasn't integrated into the usual Netbeans IDE which included the usual Java, Ruby, etc.

It's great to be able to seamlessly integrate PHP projects in this latest release!

Thoughts?

Monday 18 August 2008

KeyCzar quickfix fixed

Some of you might recall my using a batch 'quickfix' in a previous post about Google KeyCzar: creating the RSA public and private keys using batch, to work around a small issue whereby filenames ended up being concatenated to the folder name (e.g. rsakeysmeta instead of rsakeys\meta).

A few hours after posting, I eureka-d that adding \ to the folder variables would probably fix it much more neatly - and now I have found the time to verify this, it does :-).

I fixed the previous post accordingly and here is the uninterrupted simplified version of the batch for anyone interested:

@echo off
setlocal enabledelayedexpansion

:init
set java=java
if exist "C:\Program Files\Java\jre1.6.0_05\bin\java.exe" set java="C:\Program Files\Java\jre1.6.0_05\bin\java.exe"
if exist "C:\Program Files\Java\jre1.6.0_07\bin\java.exe" set java="C:\Program Files\Java\jre1.6.0_07\bin\java.exe"
if not exist %java% goto java_nf

set parent=..
set keyczar=keyczar05b.jar
set gson=gson-1.1.1.jar
set log4j=log4j-1.2.15.jar

if not exist %parent%\%keyczar% goto keyczar_jar_nf
if not exist %parent%\%gson% goto gson_jar_nf
if not exist %parent%\%log4j% goto log4j_jar_nf

goto create_keys

:create_keys
set location=rsakeys\
set public=publickeys\

if not exist %location%%public% mkdir %location%%public%

echo Creating key set
%java% -classpath %parent%/%keyczar%;%parent%/%gson%;%parent%/%log4j% org.keyczar.KeyczarTool create --location=%location% --purpose=crypt --asymmetric=rsa
echo Creating private decryption key
%java% -classpath %parent%/%keyczar%;%parent%/%gson%;%parent%/%log4j% org.keyczar.KeyczarTool addkey --location=%location% --status=primary
echo Creating public encryption (primary) key
%java% -classpath %parent%/%keyczar%;%parent%/%gson%;%parent%/%log4j% org.keyczar.KeyczarTool pubkey --location=%location% --status=active --destination=%location%%public%
goto eof

:java_nf
echo Cannot find java
goto eof

:keyczar_jar_nf
echo Cannot find keyczar jar
goto eof

:gson_jar_nf
echo Cannot find gson jar
goto eof

:log4j_jar_nf
echo Cannot find log4j jar
goto eof

:eof
echo Press any key to quit
pause > NUL
goto blackhole

:blackhole

Well, that's it. Much neater and quite as functional!

Please refer to the previous post for more information on what is actually happening here.

You can also read the second part of the post which covers how to use the KeyCzar library in Java for asymmetric RSA encryption/decryption (using the keys we just created with the above batch file).

Thoughts?

Sunday 17 August 2008

Cuil, not that cool

So perhaps Cuil isn't as cool as they had made out when it was launched.

I was really enthusiastic about the Cuil search engine when it was first publicized but have returned to my 100% Google searching as it comes up with the results I am expecting, and thus increases my productivity. The Cuil features like drill-down and its well thought-out philosophy are great but get completely overshadowed by the engine's poor search results.

So how do I measure how good the results are? Well, really the way I do this is by comparing the results from Cuil to those that Google would give me. Which is probably very bad practice, but I guess that just highlights the fact Google really has become the de facto "best" search engine for most people. How many times have you heard "Google it", and how many times have you heard "Yahoo it"? See, that's what I thought.

It does leave me wondering whether in some cases it's the search engine giving poor results or me using poor search words. Perhaps the way I pick search words has changed to accomodate the way Google references its pages and that's what makes it easier for me to use Google than Cuil, for instance.

Still, Cuil does on occasion undoubtedly return disastrous results.
For instance, if I search for the following three words:
e-learning technologies karrer
I expect the first link to be the eLearning Technology blog by Tony Karrer.
Well although Cuil actually will provide a link to the blog (and not the main page at that!), it does so with the wrong picture and in fact places the correct picture under someone else's name! Ouch.

So it seems Google really does just go that extra mile... :-)

Thoughts?

Saturday 16 August 2008

Batch programming tip #16 (part 2): getting property values from an ini file

This is just a slight variation on the previous post on working with *.ini files.
Here we only retrieve property values but not sections or property names.

@echo off
setlocal enabledelayedexpansion

:init_vars
set ini_file=my.ini
goto show_values

:show_values
for /F "tokens=1,2 delims==" %%L in (%ini_file%) do (
if not [%%M]==[] (
echo Value: %%M
)
)
goto eof

:eof
echo Press any key to quit
pause > NUL


Simple :-).

Thoughts?

Friday 15 August 2008

Splashtop

A colleague recently pointed me to the Splashtop website: http://www.splashtop.com/ and then days later a discussion with friends brought it back to mind.

So what is Splashtop? It's a small Linux distribution which launches in a matter of seconds at bootup allowing you to almost instantly access the internet using a fully-fledged browser. The website offers some nice demos which give you the "feel" for the way it works and naturally, its impressive startup speed.

The following movie shows the basic Splashtop environment. Note that later versions have already been improved on with new functionalities!



It looks like it might be time to give up on that two-minute bootup wait before you look up your favourite recipe, check your email or look up a new road itinerary.

Splashtop is currently bundled with ASUS motherboards and notebooks.

Thoughts?

Google Keyczar - now available for Java 1.5

This is a quick update regarding a sidenote in yesterday's post:
... if you get a message like "incorrect class version, 50 should be 49" or something along those lines, it means you are not running the correct version of java (i.e. the KeyCzar classes were compiled with a later version).


Steve Weis, who originally developed keyCzar, very kindly confirmed this information this morning.

The class version error is indeed due to the fact that we're using Java 1.6. Unfortunately, that's not supported by some (all?) Mac users, so we're going to post a Java 1.5 Jar soon.


Well, for anyone interested the 1.5 Jar is already available at the KeyCzar website: http://www.keyczar.org/.

Have fun!

Thursday 14 August 2008

Google Keyczar - a Java encryption/decryption example

Google Keyczar is a new Google toolkit for data encryption. We saw in a previous post how to create the private and public key files for RSA encryption.

Let's now see how to use them by integrating the Keyczar library in a Java project.
It's actually extremely simple.

First, let's see the code from Bob's perspective. Bob encrypts the data using a public key which Alice has given him (and maybe other people). To do this we will use a class called BobsApp which will specifically handle encryption using the public key folder (you'll want to check its location: it should be rsakeys\publickeys\ and the rsakeys folder should be located at the same level as the BobsApp class file).


package keyczartest;

import org.keyczar.Encrypter;
import org.keyczar.exceptions.KeyczarException;

public class BobsApp
{
private Encrypter encrypter; // used to crypt

public BobsApp() throws KeyczarException
{
String publickey=this.getClass().getResource("rsakeys/publickeys").
getFile();
this.encrypter=new Encrypter(publickey);
}

public String process(String data) throws KeyczarException
{
if (data==null) return null;
return this.encrypter.encrypt(data);
}
}


Now, let's do the same thing from Alice's perspective. She will receive Bob's (and maybe other people's) encrypted messages, but she alone can decrypt them using her private key. (You'll want to check the private key folder location: it should be rsakeys and the rsakeys folder should be located at the same level as the BobsApp and AlicesApp class files).

This is the Java utility class which specifically handles decryption:

package keyczartest;

import org.keyczar.Crypter;
import org.keyczar.exceptions.KeyczarException;

public class AlicesApp
{

private Crypter crypter; // used to decrypt

public AlicesApp() throws KeyczarException
{
String privatekey=this.getClass().getResource("rsakeys").
getFile();
this.crypter=new Crypter(privatekey);
}

public String process(String data) throws KeyczarException
{
if (data==null) return null;
return this.crypter.decrypt(data);
}
}


Now, let's create our main method which we can use to run the project:

import keyczartest.AlicesApp;
import keyczartest.BobsApp;

public class Keyczarette
{
public static void main(String[] args)
{
try
{
String secretText="For Alice's eyes only. Signed: Bob";
String bobsMessage=new BobsApp().process(secretText);
System.out.println("Bob sends: " + bobsMessage);
AlicesApp app=new AlicesApp();
String alicesMessage=new AlicesApp().process(bobsMessage);
System.out.println("What Alice reads: " + alicesMessage);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}


Just one last note, if you get a message like "incorrect class version, 50 should be 49" or something along those lines, it means you are not running the correct version of java (i.e. the KeyCzar classes were compiled with a later version).

Straight to the point! =D

Could it get any simpler than that?

Wednesday 13 August 2008

Google Keyczar - creating the RSA public and private keys using batch

Google Keyczar made headline news on geek planet recently and I couldn't help but give it a go. It's a cryptographic toolkit for Python and Java and here is a quick look at how you can get it to work for Java on Windows.

You can use it to encrypt/decrypt using public/private keys or to sign content. What really interested me was to use the RSA asymmetric method as it has always really appealed to me. Just to recap' on how this works, the idea is that Alice uses two keys: a public key (which anyone and everyone can know) and a private key that only she knows. Anyone can send her an encrypted message using the public key. To decrypt the message you need the private key, so only Alice can read the message. Excellent.

For starters, here's a link to where you can get the keyczar jar library: http://www.keyczar.org/.

You will also need two dependencies:
- the gson jar from Google code:
http://code.google.com/p/google-gson/
- the apache log4j jar:
http://logging.apache.org/log4j/1.2/download.html

Also note: I think JRE 1.6 or more is required to run the jar properly.

There are several steps to getting this up and running:
1. We need to create the public and private key files. The keyczar toolkit provides command line utilities to do this.
2. We need to create the Java code which will encrypt Bob's message to Alice (using the public key), and decrypt Bob's message when it reaches Alice (using the private key) so that Alice, and only Alice, can read it.

This first post will cover how to create the public and private key files using the batch file shown below.

I will add a couple of notes as we go along to explain the various parts of the batch file.


@echo off
setlocal enabledelayedexpansion


We need to set up Java properly, so point this to a JRE on your machine.

:init
set java=java
if exist "C:\Program Files\Java\jre1.6.0_05\bin\java.exe" set java="C:\Program Files\Java\jre1.6.0_05\bin\java.exe"
if exist "C:\Program Files\Java\jre1.6.0_07\bin\java.exe" set java="C:\Program Files\Java\jre1.6.0_07\bin\java.exe"
if not exist %java% goto java_nf


Here we are defining the directory structure to be able to find the jar files which will be passed to the Java command. In my case the batch file is located in a script directory. The 3 jars (keyczar, gson and log4j) are all located on the same level as the script directory i.e. a level above the .bat file. This is why I set the parent variable to ..


set parent=..


Obviously check the exact jar names...


set keyczar=keyczar05b.jar
set gson=gson-1.1.1.jar
set log4j=log4j-1.2.15.jar

if not exist %parent%\%keyczar% goto keyczar_jar_nf
if not exist %parent%\%gson% goto gson_jar_nf
if not exist %parent%\%log4j% goto log4j_jar_nf

goto create_keys


Now we'll be calling the commands to create the keys.


:create_keys
set location=rsakeys\
set public=publickeys\

if not exist %location%%public% mkdir %location%%public%


You will want to make sure each of the following three %java% commands are actually on one line and not cut up as they are here.

Right, first command, create the key set. Note that we'll be using asymmetric RSA.

echo Creating key set
%java% -classpath %parent%/%keyczar%;%parent%/%gson%;%parent%/%log4j% org.keyczar.KeyczarTool create --location=%location% --purpose=crypt --asymmetric=rsa


Second java command: create a key. This will be the secret key. Its status must be set to primary because that means it can be used for decrypting.

echo Creating private decryption key
%java% -classpath %parent%/%keyczar%;%parent%/%gson%;%parent%/%log4j% org.keyczar.KeyczarTool addkey --location=%location% --status=primary


Finally, we create the public key and use a "public" destination for it.

echo Creating public encryption key
%java% -classpath %parent%/%keyczar%;%parent%/%gson%;%parent%/%log4j% org.keyczar.KeyczarTool pubkey --location=%location% --status=active --destination=%location%%public%
goto eof

:java_nf
echo Cannot find java
goto eof

:keyczar_jar_nf
echo Cannot find keyczar jar
goto eof

:gson_jar_nf
echo Cannot find gson jar
goto eof

:log4j_jar_nf
echo Cannot find log4j jar
goto eof

:eof
echo Press any key to quit
pause > NUL
goto blackhole

:blackhole


That's it. Once you run this, you should get the following results:

rsakeys\
publickeys\
1
meta
1
meta

Basically two files for each key: a meta file which describes the key and another file which contains the key itself.

If you're interested there is some excellent documentation on the keyczar wiki at:
http://code.google.com/p/keyczar/w/list

It gives real insight into the key metadata, the various possible values and what they actually mean.

Thoughts for now?

[EDIT: For the second part of this post follow the link: Google KeyCzar Java encryption/decryption]

Tuesday 12 August 2008

Kolb's learning styles

An interesting article about Kolb's theory on experiential learning and learning styles model:
http://www.businessballs.com/kolblearningstyles.htm

What better way to learn than through concrete experience?

Monday 11 August 2008

Batch programming tip #16: Reading a property from an INI file

You are going to start thinking batch an I are having a love-hate relationship but there was an interesting question on computing.net recently. Someone asked how to get a property from an INI file and/or print things to an ini file or text file.

This was my effort at it.

File: - my.ini -

[provider]
name=ETH
organization=Stardust

[file]
server=192.168.254.42 ; use IP address
port=8080
file=wonderful.txt


The aim of the following batch is to retrieve the server IP address.
To do this we read all the lines of the ini file (that is each first "token" of every line, but because the property=value entities don't contain any default delimiters the first token will actually be the property=value pair on each line).

Then we try matching the beginning of the line with our property name.
If it matches, bingo, get the remaining string value and output it to ini/txt.

File: - ini_bat.bat -

@echo off
setlocal enabledelayedexpansion

:init_vars
:: this is our ini file path
set ini_file=my.ini
:: this is the key for which we want to retrieve a value
set key=server
:: this is the length of our key word (e.g. 'server')
set keylen=6
:: this is the index at which the equal sign should be
set /a eqsign=%keylen%+1
:: tmp dir name (should be empty)
set tmp_dir=tmp000
:: make temp dir
if not exist %tmp_dir% mkdir %tmp_dir%
goto get_key

:get_key
set tmp_file=%tmp_dir%\tmp.txt
:: this read the first token of every line, shouldn't be spaces in the ini file properties
for /F %%L in (%ini_file%) do (
set line=%%L
set linestart=!line:~0,%keylen%!

if !linestart!==%key% (
set value=!line:~%eqsign%!
goto output_value
)
)

:: this will erase existing %tmp_dir%\new.ini and %tmp_dir%\new.txt files

:output_value
echo Outputting value to ini file
echo server=%value% > %tmp_dir%\new.ini
echo Outputting value to text file
echo The value is: %value% > %tmp_dir%\new.txt
goto eof

:eof
echo Press any key to quit
pause > NUL
goto blackhole

:blackhole


And there you have it!

Some obvious improvements could be:
- setting the key dynamically (this also means computing the key length on the fly).
- including adequate behaviour if the property definitions include spaces
(e.g. server = 192.0.2.42)

Thoughts?

Tuesday 5 August 2008

Birthday Week

Well, this is really a one off, because for once (!) I shall be talking about my private life. Expect crazyness. Not.

This week is my birthday week and I am lucky to have lots of things going on this year so please forgive my short absence from the blogosphere... and, fear not, I'll be back soon with new riveting posts :D.

Among things I would like to explore:
- software licenses
- impersonal e-learning
- PowerPoint presentations
- Splashtop
- Google Translation
- geeky programming stuff

And lots of other things too.

'See' you soon I hope ;-),

Elinor

Saturday 2 August 2008

Object-oriented form rendering using PHP, part 3

Back to a couple of posts that date back to ages ago:
Object-oriented form rendering using PHP, part 1
Object-oriented form rendering using PHP, part 2

Basically, I had said at the time I would be redesigning lots of the code. Which is now done! Just one update compared to what was previously said, the client-side rules are added to the onsubmit event of the form.

And this is the result from the server perspective (login form):

$login_form=new HTML_Form('login',$_SERVER['PHP_SELF'], 'POST', 'login');

// identifier
$f_identifier=new Text('identifier', 'identifier', '', 15, 15);
$f_identifier->setLabel(Toolkit::get_lang('identifier'));
$f_identifier->addOnSubmitRule('trim');
$f_identifier->addOnSubmitRule('required', 'This field is required');
$login_form->add($f_identifier);

// password
$f_password=new Password('password', 'password', '', 15, 15);
$f_password->setLabel(Toolkit::get_lang('password'));
$f_password->addOnSubmitRule('required', 'This field is required');
$login_form->add($f_password);

// secure form
$login_form->secure();

// submit button
$submit=new Submit();
$login_form->add($submit);

// display form
$login_form->display();

if ($login_form->validate())
{
// handle POST information, etc.
}


First I create an HTML_Form object to which I can add form elements like Text or Password objects. I can add rules to my form elements using the addOnSubmitRule method.

This is the resulting form:

<form action="/stardust/zencity/main/home.php" method="POST" id="login" name="login" onSubmit="reset_errors(); var ret=true;ret&=trim('identifier');ret&=required('identifier','This field is required');ret&=required('password','This field is required');if (!ret) return false;">

<label for="identifier">identifier* : </label>
<input id="identifier" name="identifier" type="text" size="15" maxlength="15"/>
<span id='error_identifier' name='error_identifier'></span><br/>

<label for="password">password* : </label>
<input id="password" name="password" type="password" size="15" maxlength="15"/>
<span id='error_password' name='error_password'></span><br/>

<input id="seckey" name="seckey" type="hidden" value="BcfaGvQEpqvJujGv90nz6P10zEBqgOBUp9X3J0aXrebdf9tUoD1DA1hv28e5tlkv"/><br/>

<input type="submit" value="ok"/><br/>

</form>


The validate() method then checks the form (e.g. makes sure it has been submitted with the correct security key).
Some of the goodies are:
- the required fields' labels are automatically appended with * sign;
- the calls to JS code are automatically generated and most of the checking happens on the client-side, to help avoid server overload for simple rules (like trim, minimum length requirements, email validity, etc.);
- error zones are automatically created, these are used by the Javascript code to show error messages when the client-side rules are not met (e.g. required field empty);
- you can seamlessly add to the code behind all this: new rules, new types of elements (for instance, I have designed a small captcha - which still needs tuning mind you - which I can create with: new Captcha('captcha', 'captcha'), and then add to form using the usual add() method; simple as that).

Well, hopefully more on this project soon to explain what's actually happening behind the scenes.

Thursday 31 July 2008

Using help to help yourself (part 2): publishing batch help information in HTML format

Well, it took quite a bit of head-scratching but here it is: a batch script that outputs information about commands in HTML format.

This is the code (NOTE: works with french accented words)

[commands_site.bat]

@echo off

:init
setlocal enabledelayedexpansion
set out_dir=site
set page_sub=pages
set page_dir=%out_dir%\%page_sub%
if not exist %page_dir% mkdir %page_dir%
goto create_site

:create_site
set ifile=%out_dir%\index.html
> %ifile% echo ^<html^>^<head^>^<title^>Commands index^</title^>^</head^>
>> %ifile% echo ^<body^>
for /F "tokens=1" %%C in ('help') do (
call :set_is_command %%C
if "!is_command!"=="1" (
echo Handling: %%C
set cfile=%page_dir%\%%C.html
>> %ifile% echo ^<a href="%page_sub%\%%C.html"^>%%C^</a^>^<br/^>
:: set cfile=CON
> !cfile! echo ^<html^>^<head^>^<title^>%%C^</title^>^</head^>
>> !cfile! echo ^<body^>^<h2^>%%C^</h2^>^<pre^>
for /F "delims=" %%T in ('help %%C') do (
set str=%%T
set str=!str:…=^&agrave;!
set str=!str:‚=^&eacute;!
set str=!str:Š=^&egrave;!
set str=!str:ˆ=^&ecirc;!
set str=!str:‰=^&euml;!
set str=!str:Œ=^&icirc;!
set str=!str:‹=^&iuml;!
set str=!str:“=^&ocirc;!
set str=!str:—=^&ugrave;!
set str=!str:–=^&ucirc;!
set str=!str:‡=^&ccedil;!
set str=!str:ÿ=^&nbsp;!
>> !cfile! echo !str!
)
>> !cfile! echo ^<br/^>^<br/^>
>> !cfile! echo ^<a href="../index.html"^>Back to index/Retour ^&agrave; l'index^</a^>
>> !cfile! echo ^</pre^>^</body^>^</html^>
)
)
>> %ifile% echo ^</body^>
>> %ifile% echo ^</html^>

goto end

:set_is_command
set name=%~1
set is_command=1
if not "%name%"=="" (
set num=1
for /F "usebackq tokens=1 delims=ABCDEFGHIJKLMNOPQRSTUVWXYZ" %%W IN ('%name%') do (
set num=0
)
set is_command=!num!
)
goto blackhole

:end
echo Press any key to quit...
pause > NUL

:blackhole

So, how does it work?

One
We enable delayedexpansion. This allows us to dynamically set variables in FOR loops.

Two
We prepare the output directories (mkdir). The root of the "site" is the site directory (this is where the site index will get stored). In this directory, a subdirectory is created which will hold all the pages (one for each command): the pages subdirectory.

Three
A loop (for /F "tokens=1" %%C in ('help')...) is used to loop through all the lines output by the help command. Each command is output starting with the command name and one or more lines of short explanations like the following example shows:

VERIFY Indique à Windows 2000 s'il doit ou non vérifier que les fichiers
sont écrits correctement sur un disque donné.

Notice the accented characters shown in the explanation (é, à).

Four
Obviously we only want to retrieve the command names (e.g. VERIFY) and nothing else. To do this we must check the first token of every line. In our case the first token will be VERIFY for the first line, and "sont" for the second line. Only the first of these two tokens is an actual command name. Fortunately, it has only uppercase letters.
The set_is_command subroutine makes sure the is_command variable is set to 1 if the token is a command (i.e. all uppercase letters) or 0 if the token isn't (one or more lowercase letters e.g. "sont").

Five
The script will output: one file for each command (containing its detailed help information) and an index file which will reference all these command pages.
For every command name, we:
- create a link in the index file
- create a file containing the detailed information (the result of help %commandname%)

Six
Notice there is a strange section with a few lines like:
set str=!str:Œ=^&icirc;!

At first, when I tried to output the result of 'help %commandname%' to an HTML file, the accented characters got replaced by different characters. For instance: "é" was shown as ",", "è" was shown as "Š", and so on and so forth. After some Googling and much head-scratching, I came up with this.
The idea is to replace the "bad" character with a character which will give me the desired result. Because I am working with HTML a good way to do this is to replace these accented characters with the corresponding HTML entities. Thus, é becomes &eacute;, à becomes &agrave;, etc.
I used a simple replacement syntax set str=!str:S=R! where S represents what you're searching for and R represents the desired replacement. Neat little trick.

There is a catch however. To work properly with accented characters, you need to open the batch file using EDIT (cmd > EDIT). If you open the above code using EDIT you will find that "…" becomes "à", "‚" becomes "é", "Š" becomes "è", etc. Once you have finished entering the accented characters, you can then revert to notepad for instance but the characters will look "strange" (i.e. as in the example above).
I guess you could do exactly the same with text, by typing the accented characters in notepad (for instance), then opening the file in EDIT. The notepad characters will look weird in EDIT but you can then type in EDIT the original characters to be replaced with the "weird" notepad characters using the S=R syntax. I haven't tried this but I expect it works.

Well, I think that's it. I hope someone will find this useful!

Thoughts?

Wednesday 30 July 2008

Batch programming: using help to help yourself

Nothing I know of can quite beat the Linux/Unix "man" pages but here's a quickie on how to use the help command from the Windows command prompt.

Step 1: start the prompt (Start -> Run -> (type) cmd -> Enter)

Step 2: type help

cmd> help

This displays a list of available batch commands.

Step 3: get help on command of your choice (e.g. "FOR")

cmd> help for


Reading all of this in black and grey is pretty tedious, so I have started on a script that will output all these command in HTML format. Run it once and it will create a folder containing:
- an link index to all the commands
- one page per command with the relevant details

I currently have two major problems with this:
1. Trailing "spaces": I can't seem to remove trailing spaces successfully (not even sure they really are spaces)
[EDIT: PROBLEM 1 SOLVED, shall post code tomorrow]
2. Accented characters: I am using French, and accented characters are output as anything but what they should be. For instance "é" is output ",", etc. and I have yet to find a full-DOS solution to this problem.
[EDIT: PROBLEM 2 SOLVED, shall post code tomorrow]

Any suggestions more than welcome regarding these two issues =)

Tuesday 29 July 2008

Batch programming tip#15: Getting file information

This example speaks for itself I think. You can obviously also use it in FOR loops or subroutines. It show how to retrieve lots of useful information about files (in this exemple the first argument).

[info.bat]

@echo off

:init_vars
if [%1]==[] goto what_file
if not exist %1 goto what_file
goto show_info

:show_info
echo.
echo General information
echo -------------------
echo Fully qualified name (%%~f1): %~f1
echo Drive letter (%%~d1): %~d1
echo Path (%%~p1): %~p1
echo File name (%%~n1): %~n1
echo File extension (%%~x1): %~x1
echo Date time (%%~t1): %~t1
echo Size (%%~z1): %~z1
echo File attributes (%%~a1): %~a1
goto show_combinations

:show_combinations
echo.
echo Some possible combinations
echo --------------------------
echo Drive and path (%%~dp1): %~dp1
echo Filename and extension (%%~nx1): %~nx1
echo Path using short names (%%~fs1) : %~fs1
echo.
goto eof

:what_file
echo Please provide valid file.
goto eof

:eof
echo Press any key to quit
pause > NUL


Simply call it using something like:

[info_call.bat]

@echo off
call info test_file_info.longext


These allow you to get: file size, date time, etc. Really useful stuff =D.

Have fun!

Monday 28 July 2008

Cuil - Search Engine

It seems to have been a long long while since any new search engine has actually surfaced on the web and made Google look anything different to Goliath (OK, I know that's a bad example because Goliath lost and Google just keeps winning :-)).

But look out for this new rising star: http://www.cuil.com/

Co-founded by ex-Google employees, Cuil has already crawled more pages than the Search Engine Giant itself! With a name from the Gaelic word for Knowledge, it looks like you may not be able to ignore this site for too long!

Among some of its really neat features are:
- two or three-column presentation of search results
- context-driven results with a drilldown feature which allows you to easily get to other pages in the same context by using an "Explore by category" link box located at the right-hand side of the screen (for instance, try typing "e-learning technologies")
- search tabs: in some cases search tabs will appear at the top(-ish) of the page with "sub-searches" (for instance, try searching for "insects" and you will get tabs relating to "Flying insects", "Beneficial insects", "Harmful insects" and many more)

Add to that an excellent FAQ, clear an meaningful explanations, cool web design, plus lots of things I probably missed, and you must be on to a winner!

This afternoon (by GMT+1 standards), they were already adding capacity, with their search page sporting the message:

We’ll be back soon...
Due to overwhelming interest, our Cuil servers are running a bit hot right now. The search engine is momentarily unavailable as we add more capacity.
Thanks for your patience.

It's a hit! =D

What do you think? Can Cuil unsettle Google on the search engine market?

Sunday 27 July 2008

Batch programming tip#14: The difference between :: and REM

Both REM and :: are commonly used to "comment out" a line in batch files, so what's the difference between them?

REM is the true "Remark" command. In other words it is treated as such and interpreted.

::, on the other hand, is an invalid label (a label starts with a colon) and is therefore simply skipped.

What this means is using REM is slower than using :: because :: means the line is skipped and the next is interpreted whereas with REM the line isn't skipped in the first place.

Thoughts?

Friday 25 July 2008

Batch programming tip#13: Using setlocal enabledelayedexpansion

Delayed expansion is pretty tricky to explain. It basically means you are making sure that your variable is evaluated as many times as necessary and not just once (as would normally be the case).

The typical use for this is when using a "for" command. Without delayed expansion, variables do not appear to get set correctly. Why? Because they are evaluated once for the for command (rather than each time you loop) which results in apparently strange behaviour.

Example:

@echo off

:action
set num=0
for /l %%N IN (1,1,9) do (
echo %num%
set /a num=%num%+1
)
goto show_result

:show_result
echo Num is actually now worth: %num%
goto eof

:eof
echo Press any key to quit...
pause > NUL
goto blackhole

:blackhole

The for /l %%N IN (1,1,9) do command basically creates a loop from 1 to 9 with a step of 1 (so nine passes).
Anyhow, anyone would go crazy trying to debug this thing: it outputs nine zeros and a total worth of 1!

Enter delayed expansion however and things get back to normal:

@echo off

:init_sys
setlocal enabledelayedexpansion

:action
set num=0
for /l %%N IN (1,1,9) do (
echo !num!
set /a num=!num!+1

)
goto show_result

:show_result
echo Num is actually now worth: %num%
goto eof

:eof
echo Press any key to quit...
pause > NUL
goto blackhole

:blackhole

Notice we use the exclamation mark instead of % to reference variables within the for loop. This makes sure the variable is reassessed every time we use it.

I have written a short example below with a loop inside a loop. It loops through a sentence and shows every word separately using a call to an appropriate subroutine.


@echo off

:init_sys
setlocal enabledelayedexpansion

:init_vars
set text=The quick brown fox jumps over the lazy dog

:action
echo Displaying text using %%: %text%
echo Displaying text using ^^!: !text!

for /l %%N IN (1,1,9) do (
call :get_substr %%N "%text%"
echo Token: !strtok!
)
goto eof

:get_substr
set token=%~1
set string=%~2

for /F "usebackq tokens=%token% delims= " %%w in ('!string!') do (
set strtok=%%w
)
goto blackhole

:eof
echo Press any key to quit...
pause > NUL
goto blackhole

:blackhole

Note that if you don't use the delayed expansion properly (e.g. in the second for loop: '!string!') all hell will break loose... I know because I tried :D

The second use of delayed expansion is to nest variables like so:

@echo off

:init_sys
setlocal enabledelayedexpansion

:init_vars
set text=The quick brown fox jumps over the lazy dog

:action
for /l %%N IN (1,1,9) do (
call :getchars %%N
)
goto eof

:getchars
set num=%~1
echo !text:~0,%num%!
goto blackhole

:eof
echo Press any key to quit...
pause > NUL
goto blackhole

:blackhole

What this script does is successively retrieves N (N being 1 to 9) number of characters from our sentence "The quick brown fox jumps over the lazy dog".
To do this we nest the %num% variable in our "substring" notation:
!text:~0,%num%!

Cool.

Thoughts?

Sunday 20 July 2008

Batch programming tip#12: Creating a timestamp

Now we can substring, creating a timestamp is really easy.

This is one simple way of doing this using the %date% and %time% system variables to create timestamped files.


@echo off

:create_file
call :get_timestamp
type NUL > %timestamp%.file
goto eof

:get_timestamp
set d_stamp=%date:~11%%date:~8,2%%date:~5,2%
set t_stamp=%time:~0,2%%time:~3,2%%time:~6,2%%time:~9%
set timestamp=%d_stamp%%t_stamp%
goto blackhole

:eof
echo Press any key to quit...
pause > NUL
goto blackhole

:blackhole

(We reverse year, month and day so that the files are naturally sorted in the 'right' order.)

The create_file section retrieves the timestamp (e.g. 2008071719410698) created by the get_timestamp subroutine and uses it to create an empty file. Obviously this can have multiple uses like timestamping log information for instance.

(Note: day and month probably appear in a different order according to sytem locale.)

Thoughts?

Saturday 19 July 2008

Batch programming tip#11: Using The Substring Equivalent

As you know, most (all?) programming languages provide a substring() method of some sort which allows you to retrieve part of a string variable.

To do this in batch you can use the following syntax:
%var:~start% or
%var:~start,length%
where start is the index of the first character to retrieve (the first character in a string is indexed 0) and length is the length of the substring to retrieve. If no length is given the whole remaining string is shown.

In this example, we use a system variable %date% which holds the current system date and then echo the current system month and year.

@echo off

:get_year
echo System date: %date%
echo System month: %date:~8,2%
echo System year: %date:~11%
goto eof

:eof
echo Press any key to quit...
pause > NUL
goto blackhole

:blackhole


You can also use this method 'backwards'. Assume we didn't know the length of the %date% variable string, and wanted to retrieve the four last characters which represent the year.
We could then use the following syntax: %date:~-4% with a minus preceding the 4. This moves us back 4 characters from the end of the string, then (because no length has been specified) returns all the remainder until the end of the string. This is equivalent to: %date:~-4,4%

The drawback here is you cannot dynamically set the 'start' and 'length'. For this we need to use delayed expansion, which I'll get back to in a later post!

Until then, thoughts?

Friday 18 July 2008

Batch Programming Tip#10: Making and calling a subroutine (part 2)

Let's see how can pass arguments to our get_date subroutine to change date format. For instance, we will be able to choose whether the day or month comes first in our output string and which separator (if any) we wish to use.
Beware that date /T is probably locale dependent. On my system the date is output in the following format 'day. dd/mm/yyyy' e.g. mon. 14/07/2008


@echo off

:show_date
call :get_date / 0 1
echo Date: %_date%
goto eof

:get_date
set delim=%~1
set order=%~2
set show_day=%~3

echo delim=%delim% and order=%order% and show_day=%show_day%

for /F "tokens=1,2,3,4 delims=/ " %%d in ('date /T') do (
set day=%%d
set dd=%%e
set mm=%%f
set yyyy=%%g
)

set _date=%dd%%delim%%mm%%delim%%yyyy%
if "%order%"=="1" set _date=%mm%%delim%%dd%%delim%%yyyy%
if "%show_day%"=="1" set _date=%day% %_date%
goto blackhole

:eof
echo Press any key to quit...
pause > NUL
goto blackhole

:blackhole


The get_date subroutine has changed considerably.

First, we get three possible arguments: delimiter, order (either day/month or month/day) and show_day (whether or not to show the day: 'mon.' for instance). You retrieve the arguments in the same way as you would for batch command-line arguments (using %~1, etc.).

These arguments are appended to the call to the subroutine: call :get_date / 0 1.

Second, we split the date string into four parts day (mon.), dd (14), mm (07), yyyy (2008).

Finally, we build the %_date% variable while taking into account the various arguments. If %order% is set to 1 we reverse dd and mm order. If show_day is set to 1, we prefix the date with the day.

That's it.

Thoughts?

Thursday 17 July 2008

Batch Programming Tip#10: Making and calling a subroutine (part 1)

It looks like quite a few people are wondering how to write a subroutine, and how to pass it arguments. So let's write a small subroutine. You can't actually 'return' a value from the subroutine in the usual sense of the term. You can however set one or more variables within the subroutine which can then be used by the caller.

Let's imagine we need to write a subroutine that will retrieve the current date for us.

Let's start our batch by writing the following subroutine which will compute the date and store it in the %_date% variable.

@echo off

:get_date
for /F "tokens=2 delims= " %%d in ('date /T') do (
set _date=%%d
)
goto blackhole

:blackhole

What happens here is a slightly more complex for /F construct than we saw previously.
date /T outputs the current date, for instance as follows: mon. 14/07/2008
The for construct then effectively splits the string using the space character as the delimiter (this will leave us with 2 tokens: 'mon.' and '14/07/2008' but without the quotes). It then takes the second token (tokens=2) which is stored in %%d. Neat!

Obviously, if you run this script 'as-is', you won't actually 'see' anything happen, although the script will have computed the 'date' and stored it in the %_date% variable.

I do have an inkling that date format varies according to system locale. For instance you may find that on some systems you will output day/month/year and on others month/day/year according to your country/language settings.

Right, now let's add in some script to call the subroutine.


@echo off

:show_date
call :get_date
echo Date: %_date%
goto eof

:get_date
for /F "tokens=2 delims= " %%d in ('date /T') do (
set _date=%%d
)
goto blackhole

:eof
echo Press any key to quit...
pause > NUL
goto blackhole

:blackhole

Calling the subroutine is done in much the same way as calling an external batch but with an extra colon: call :get_date. This sets the %_date% variable which can then be shown from within the calling routine.

Note the importance of the 'goto blackhole' instruction at the end of the subroutine, this is what makes you 'return' to the calling code. You can alternatively use goto:EOF or goto :EOF. (Note that this is NOT the same as goto eof without the colon, which leads to the "Press any key" section of this script.)

One way to improve our subroutine would be to add arguments to allow for various date formats.

Thoughts?

Wednesday 16 July 2008

Batch programming tip#09: Using FOR /D

This is a basic variation of the for loop. Add the /D modifier to loop through directories.

The following script shows all the subdirectories of the current directory (the directory the batch is running from).

@echo off

:action
for /D %%l in (*) do (
echo Directory: %%l
)
goto eof

:eof
echo Press any key to close window...
pause > nul
goto blackhole

:blackhole


Let's simply list all directories and all files in those directories:

@echo off

:action
for /D %%l in (*) do (
echo Directory: %%l
cd %~dp0\%%l
for %%f in (*.*) do (
echo File: %%f
)

)
goto eof

:eof
echo Press any key to close window...
pause > nul
goto blackhole

:blackhole

Well, that's it for now.

Thoughts?

Tuesday 15 July 2008

Batch programming tip#08 (part 3): Reading from a file - Looping

This post will bring an end (I think) to this thread about file reading using batch.

To use the loop command on a file we simply add /F in our FOR loop construct like so:

@echo off

:init_vars
if exist file1.txt goto action
echo Oops. file1.txt doesn't exist. Please create it or change file name.
goto eof

:action
for /F %%l in (file1.txt) do (
echo Content: %%l
)
goto eof

:eof
echo Press any key to close window...
pause > nul
goto blackhole

:blackhole

This will probably work with most configuration files you might use. There is one additional parameter that's really useful though, especially if your lines contain spaces. The FOR loop will by default only return the first token up to a delimiter character. The default delimiter characters are space and tab. This means the script above will only return the first word of any line containing spaces.

To avoid this (usually unwanted) behaviour, use the delims parameter and set it to empty as in the following code:

@echo off

:init_vars
if exist file1.txt goto action
echo Oops. file1.txt doesn't exist. Please create it or change file name.
goto eof

:action
for /F "delims=" %%l in (file1.txt) do (
echo Content: %%l
)
goto eof

:eof
echo Press any key to close window...
pause > nul
goto blackhole

:blackhole


Notice how we have added to our for construct:
for /F "delims=" %%l in (file1.txt) do

You can set "delims=" to whatever you want in effect, you could for instance use comma instead: "delims=,".

Well, I think that's it, you can of course take file reading much further if you want. In that case, you might want to check Rob van der Woude's comprehensive page about NT FOR syntax. Enjoy!

More shortly about how to loop through directories.

Thoughts in the meantime?

Monday 14 July 2008

Batch programming tip#08 (part 2): Reading from a file - Looping

So, let's see how we can loop through information.
The following script is the same as the previous but I have added a loop construct which will loop through our file_content variable (the first line of the file).

@echo off

:init_vars
if exist file1.txt goto action
echo Oops. file1.txt doesn't exist. Please create it or change file name.
goto eof

:action
set /P file_content=<file1.txt
for %%l in (%file_content%) do (
echo Content: %%l
)
goto eof

:eof
echo Press any key to close window...
pause > nul
goto blackhole

:blackhole

The loop construct is simple: for %%varname in (%var%) do ( ..[action]..)
The parentheses around the %var% are not in there just for form, you really need to remember them or your batch will crash.

To test it try using a file that contains a first line with spaces in it (e.g. The quick brown fox jumps over the lazy dog) and you will see that each word of the first line of the file will appear on a line of its own.

Excellent, the next step will be to loop through all the lines in a file.

Thoughts in the meantime?

Sunday 13 July 2008

Batch programming tip#08: Reading from a file

Reading from file can sometimes be really useful. For example, you could imagine one process was to output lots of file names to a given file (let's call it file1.txt) and then that our batch would jump in there and retrieve those file names and print up whatever is in them (obviously in a real-world case scenario, you would want to handle the files and do something with them, e.g. archive them to a different location or whatever).

To read content from a file, we set a variable using /P and the < sign after the usual = sign.

The following code does this.

@echo off

:init_vars
set /P file_content=<file1.txt
goto action

:action
echo File content: %file_content%
goto eof

:eof
echo Press any key to close window...
pause > nul
goto blackhole

:blackhole

Note that if file1.txt doesn't exist an error message will show and the variable %file_content% will be empty.

Hey presto, we got something out of the file. This is great... except: we are only getting hold of the first line.

In the two following posts, I will explain the loop construct and how to use it to read all the lines from the file.

Thoughts in the meantime?
Online Marketing
Add blog to our blog directory blog search directory Blog Directory Blogarama - The Blog Directory