24 August 2014

New website branding - 1st attempt

I think I've got the website header sorted sufficiently well to give it a public airing.

The idea is to keep the original colour sheme and to show the site name in roughly the same style as used on the current site. But now the font's changed and it's rendering text and CSS instead of using an image. It's coded using Bootstrap.

Here's the new header as it will display on larger tablets and desktops:

There's a change in the site navigation: the old site places it down the left hand side of the page while the new site uses a horizontal bar under the branding. I'm using the Bootstrap navbar but I've tried to change the appearance by moving the branding out of the navbar. I've also changed the navbar colour scheme to match the branding. The biggest change is the inclusion of a search box in the navbar.

Here is how the header appears on phones and small tablets:

The navigation moves into the drop down menu on the mobile version and the "strap-line" disappears. I've replaced the Bootstrap "hamburger" menu icon (which I'm not to keen on) with the more obvious "MENU" text. I would prefer to move the menu button up onto the same row as the logo, but haven't worked out how to do that yet!

Just for reference, here's the current website header:

Well, that's the hard part done. All that's left is to design, code and populate the content pages!

Any comments on the new styling will be appreciated.

Long overdue re-design of DelphiDabbler.com

The current version of DelphiDabbler.com has been around for years. It looked quite modern when it was released, but not now. Far from it.

So, the time I'm been putting off for so long has arrived: a re-design is in the works. Not a simple refresh, but a root and branch re-design and re-build.

I've got four design goals:

  1. The new site must be responsive - the current one looks aweful on phones and small tablets.
  2. A want a fresh, clean and uncluttered look and feel - it's currently dated and cluttered.
  3. The content needs to be leaner - there's just too much stuff on the current site so a lot of it's got to go. Also, this is the only way to make the job manageable.
  4. The underlying code needs an overhaul too - the site's JavaScript is pre-historic and the PHP just grew over 12 years from procedural via PHP 4 style classes with a smattering of much nicer PHP 5 style OOP.

Big job for one man then. Especially one who has not kept up to date with modern web programming developments.

I've spent a lot of time over the past weeks reading about responsive design and have researched several techniques. I even tried out one UI framework on the new CodeSnip micro-site with no great success - that's getting changed too!

What I've decided so far is that I'm going to use Bootstrap 3 as the front end framework, because I like the mobile-first responsive design it enforces.

I had some reservations about Bootstrap at first because there are many, many Bootstrap based sites that all look pretty similar. So, I've decided to customise it. And I tried writing a CSS file that modified some of Bootstrap's appearance and ended up with a site that looked like all the others. Because re-skinning Bootstrap via plain CSS is hard.

Plan B was called for. I went "shopping" for Bootstrap templates and couldn't find one I liked at the right price, the right price being £0.00!.

So to plan C, which means customising Bootstrap using Less. Problem is, I've never used Less, so have had to go on a detour to grasp the principles. I was considering hacking the Bootstrap Less files directly until I hit a Bootstrap 3 Less Workflow Tutorial. This was the eureka moment. Now I'm incorporating the Bootstrap Less files in my project and customising them via a set of stand-alone Less files. One day in and it seems to be working.

Now I'm having to learn both Bootstrap and Less as I go along!

I'm pretty sure I'm not going down the web application framework route. I struggle to see how frameworks like AngularJS will help me - DelphiDabbler.com isn't really a web app. So, I think I'll stick with PHP and generate pages on the server.

As to the existing JavaScript: it's horrible and it's all going in the bin. I'm going to be using jQuery in the new site where necessary. That's partly because I've used it before and partly because Bootstrap already requires it.

I've always coded straight to PHP, JS and CSS before. This meant I could write directly to the to a version of the site running in a local Apache server and so see the results of changes immediately. No build process at all. Now I'm using Less that old process won't do because there's a compile step needed before I have usable code. I now need a proper build process. So Node and Gulp have just hit the hard drive. Something else to learn - oh joy!.

I going to maintain the source code in a Git repo. Haven't decided yet whether to keep the code private or whether open source it.

So there we have it. Ambitious and challenging for an old Delphi hacker who has pretty much ignored the world of web development for the last 10 years. Not sure if I'll make it.

I'll keep updating this blog with any progress and will aim to publish early versions somewhere deep down in DelphiDabbler.com in due course.

20 July 2014

New Major Release of CompFileDate (File Date Comparison Utility)

Pulling together the loose ends to release the BDiff / BPatch Utilities yesterday must have triggered a tidying loose ends gene. Because now I've been motivated to put the finishing touches to some code I wrote a few months ago that significantly extends the capabilities of my CompFileDate File Date Comparison Utility. As a result CompFileDate v2.0.0 was released today.

This Windows command line app now lets you specify what operation is used in the comparison of file dates: ">" (i.e. file 1 is later than file 2), "<" (i.e. file 1 is earlier than file 2), "<=", ">=", "=" or "<>". You can also compare files' last modification dates or creation dates. Finally, when comparing the dates of shortcuts there is the option to compare the dates of the shortcuts or the dates of the shortcuts' target files.

Download the executable code from either SourceForge or GitHub.

The source is maintained in the delphidabbler/compfiledate Git repo on GitHub. Contributions welcome.

19 July 2014

New release of the BDiff / BPatch utilities

After a mere five year wait I've finally pulled together the hacking that's been going on sporadically over the intervening period and released an update to the BDiff / BPatch utilities.

It's only a minor update that fixes a couple of minor bugs, but underneath there's been a major refactoring from largely procedural to mainly OOP code: it's all been modernised and Pascal-ified, making it harder to see the code's C origins.

What's more the project has been moved from Subversion to Git, hosted on GitHub as delphidabbler/bdiff, making it easier for anyone who may want to fork it or contribute. Pull requests are welcome.

For me it represents a return to coding after about 3 months lay off. I just got bored and disillusioned with it all! Possibly more on this later.

08 March 2014

Been casting value types to stuff into TStrings.Objects[]?

On numerous occasions I've had the need to store simple, record and interface types in variable or fields of type TObject and had to use some horrible casting to do it. For example, you may resorted to doing stuff like this:

var
  SL: TStringList;
  Value: Integer;
begin
  SL := TStringList.Create;
  Value := 42;
  SL.AddObject('some text', TObject(5));
  ...
end;

Not nice!

Things get worse when the size of the data type is greater than SizeOf(TObject) and this kind of horror is needed:

var
  SL: TStringList;
  R1, R2: TRect;
  PR: PRect;
  Idx: Integer;
  MyRect: TRect;
begin
  ...
  // add some strings and objects
  SL := TStringList.Create;
  R1 := Rect(0, 0, 42, 56);
  GetMem(PR, SizeOf(TRect));
  PR^ := R1;
  SL.AddObject('some text', TObject(PR));
  R2 := Rect(1, 2, 3, 4);
  GetMem(PR, SizeOf(TRect));
  PR^ := R2;
  SL.AddObject('some more text', TObject(PR));
  ...
  // do something with SL e.g.
  MyRect := PRect(SL.Objects[0])^;
  ...
  // free the allocated memory
  for Idx := 0 to Pred(SL.Count) do
  begin
    PR := PRect(SL.Objects[Idx]);
    FreeMem(PR, SizeOf(TRect));
  end;
  SL.Free;
  ...
end;

And I'm not even going into the reference counting hell that is involved when doing all this with interfaces.

It's common to see this kind of stuff going on when someone wants to associate a value with an item in a list box or a list view for example. Now I know we shouldn't be storing data in UI controls, and I do try to avoid it (honest), but who hasn't done it?!

It many cases the problem can be solved by creating a little class that "wraps" the non-object type:

type
  TBox<T> = class(TObject)
  strict private
    var
      fValue: T;
  public
    constructor Create(Value: T);
    property Value: T read fValue;
  end;
 
...
 
constructor TBox<T>.Create(Value: T);
begin
  fValue := Value;
end;

Use TBox<> as follows: here we're wrapping an integer:

var
  IntObj: TBox<Integer>;
begin
  IntObj := TBox<Integer>.Create(42);
  try
    ...
    // use IntObj e.g.
    ShowMessageFmt('Value = %d', [IntObj.Value]);
    ...
  finally
    IntObj.Free;
  end;
end;

Now, the example above using rectangles changes to the somewhat less horrid:

var
  SL: TStringList;
  Idx: Integer;
  MyRect: TRect;
begin
  ...
  // add some strings and objects
  SL := TStringList.Create;
  SL.AddObject('some text', TBox<TRect>.Create(Rect(0, 0, 42, 56)));
  SL.AddObject('some more text', TBox<TRect>.Create(Rect(1, 2, 3, 4)));
  ...
  // do something with SL e.g.
  MyRect := (SL.Objects[0] as TBox<TRect>).Value;
  ...
  // free the allocated memory
  for Idx := 0 to Pred(SL.Count) do
    SL.Objects[Idx].Free;
  SL.Free;
  ...
end;

You still have to do a little casting to get the value and you still need to remember to free the objects, but it's a lot clearer what's happening, and you are actually storing data of the correct type in the TStrings.Objects[] property.

For convenience I've created a Gist containing the TBox<> definition.

24 February 2014

When Did The Delphi Language First Support ...?

If you're like me and try to write library code that's compatible with several different versions of Delphi you have probably had cause to ask "When did Delphi first support XXX feature?"

I have. A lot. And then I forget and have to research it all over again. So, I've created a small table of various language and other features of Delphi along with the version where they were introduced.

I've had the page for a while now for my own use, but it occurs to me that others may find it useful. If you're interested, view it here.

Now, I'm not guaranteeing it's 100% accurate, and it's far from complete.

And now the ask. If you know of any other features and the version when the were first introduced please leave a comment and I'll add it to the list.

Also, if I've made a mistake, leave a comment about that too so I can fix it.

19 February 2014

New blog for CodeSnip stuff

Up to now lots of news about my CodeSnip program has been posted on this blog. That's really been off-topic in that I first conceived this blog to be a place to post some occasional musing on programming.

So, Ive now set up the new CodeSnip blog that I'll use for CodeSnip announcements and the like. I'm intending for this blog to become the central hub of all CodeSnip news in future.

Therefore if you've subscribed here mainly for the CodeSnip stuff, it would be best to subscribe to the new blog instead or as well.Sorry if that inconveniences you.

16 February 2014

Workaround for a bug in SourceForge's Blog RSS feed

I've just been setting up a new blog for CodeSnip on SourceForge (of which more later).

On setting up a FeedBurner feed for the blog I've come across a bug in the SourceForge news RSS feed that breaks FeedBurner.

The problem is that FeedBurner (correctly) treats the value of the SF feed's <guid> tags as valid URLs and uses them as destination URLs of some links. Unfortunately the <guid> tags in the SF feed are not valid URLs and this causes FeedBurner to generate bad links.

The RSS specification states that <guid> tags should signal whether or not they contain valid URLs by means of an isPermaLink attribute. The tag's value must be a valid URL if isPermaLink is true but must not to be treated as a URL if the value is false. The attribute's default value, when not present, is true. An here's the problem: SF doesn't provide an isPermaLink attribute and so FeedBurner assumes the value of the <guid> tag is a valid URL when in fact it's not.

This suggests a solution: we need to transform the SF feed, adding an isPermaLink with value false to every <guid> tag in the feed. This will cause FeedBurner to disregard the <guid> tag.

I've written a little PHP script to performs the required transformation. I can't modify the feed at source, so the next best thing is to read it in, modify it and make the modified feed available via a new URL.

Here's the script:

<?php
/*
  Fix for SF RSS feed bug: https://sourceforge.net/p/allura/tickets/6687/
  Reads RSS source code from SourceForge and re-renders it, adding an
  isPermaLink=false attribute to every <guid> tag.
*/

mb_internal_encoding('UTF-8');
mb_http_output('UTF-8');
mb_language('uni');
mb_regex_encoding('UTF-8');
ob_start('mb_output_handler');

class SFBlogFeedConverter {

  private $feedURL;   // URL of SourceForge RSS feed
  private $rssDOM;    // RSS DOM

  public function __construct($feedURL) {
    $this->rssDOM = new DOMDocument();
    $this->feedURL = $feedURL;
  }

  public function RenderRSS() {
    if ( !@$this->rssDOM->Load($this->feedURL)) {
      $code = 500;
      $desc = 'Internal Server Error';
      header("HTTP/1.0 $code $desc");
      header("Status: $code $desc");
      header('Content-Type: text/html; charset=utf-8');
      echo "<!DOCTYPE html>\n"
        . "<html>\n"
        . "<head>\n"
        . "<meta charset=\"utf-8\">\n"
        . "<title>$code $desc</title>\n"
        . "</head>\n"
        . "<body>\n"
        . "<h1>$code $desc</h1>\n"
        . "<p>Can''t open CodeSnip blog feed on SourceForge</p>\n"
        . "</body>\n"
        . "</html>\n";
      return;
    }

    $guidNodes = $this->rssDOM->getElementsByTagName('guid');
    foreach ($guidNodes as $guidNode) {
      $guidNode->setAttribute('isPermaLink', 'false');
    }
    header('Content-Type: application/xml; charset=utf-8');
    $xml = $this->rssDOM->saveXML();
    header('Content-Length: ' . strlen($xml));
    echo $xml;
  }
}

$blogXML = new SFBlogFeedConverter(
  // Replace [PROJECT] below with the required project name
  'http://sourceforge.net/p/[PROJECT]/blog/feed'
);
$blogXML->RenderRSS();
?>

Get the code from GitHub

First off we just make sure we use UTF-8 encoding.

The main code is wrapped up in the SFBlogFeedConverter class. There's a constructor that takes the URL of the feed we're converting as a parameter and stores it. It also creates a DOM object to use later.

The meat of the code is in the RenderRSS method. We try to load the RSS from the URL passed to the constructor. If that fails we create an error 500 response and exit. If the DOM loads OK we get all the <guid> nodes and give each one an isPermaLink attribute with the value False. Finally we write the required headers followed by the converted XML.

The last bit of code just creates a SFBlogFeedConverter instance with the required feed URL and then calls RenderRSS to perform the conversion.

To use the script, upload it to a web server and make it accessible via a URL. Then point FeedBurner (etc.) at the new URL and all should be fine.

I've modified FeedBurner in this way for the CodeSnip blog feed and now everything works fine.

You can see the different between the two feeds. Point your browser at http://sourceforge.net/p/codesnip/blog/feed to see the original version and at http://codesnip.delphidabbler.com/feeds/blog-feed to see the transformed version. (Depending on your browser, you may need to view the source code to see the difference).

If you're experiencing the same problem please feel free to use the script until such time as SF fix the bug.

01 February 2014

Considering changing license of Code Snippets Database snippets

I'm considering changing, or more accurately clarifying, the license that applies to the snippets in the Code Snippets database.

At present the code is covered by this rather vague statement that is written to the top of any unit generated by CodeSnip or the online database reader app:

{
 * This unit may be freely distributed and used on the condition that this
 * comment is not removed from the unit.
 *
 * ...
 * 
 * The source code contained in this unit is made available on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. The code is used
 * entirely at your own risk.
 *
 * ...
}

While a slightly different statement appears in any exported snippet: here's an example:

{
 * This code snippet was generated by DelphiDabbler CodeSnip Release 4.8.5 on
 * Sat, 01 Feb 2014 14:02:09 GMT. It is made available on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. The code is used
 * entirely at your own risk.
}

And the CodeSnip about box just says:

The source code in the database may be used freely, but is made available on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. The code is used entirely at your own risk.

At first sight dedicating the code to the public domain seemed a good choice but, from what I've read, there are risks with this. What is more, public domain is not a license and isn't approved by the Open Software Initiative.

OK, not public domain then, so which license to use? I want to satisfy the following criteria as far as possible:

  1. The open source nature of the code should be protected - no-one should be able to make it closed source.
  2. The code should be compatible with as many open source projects that use other licenses as possible.
  3. The license should be as permissive as possible without contravening points 1 and 2.
  4. There should be a disclaimer of warranty (as publisher I want some protection!)
  5. We shouldn't add to the problem license proliferation, so no custom or obscure licenses.
  6. Minimum onus should be placed on the user for making source code available or for giving credit - these are only little snippets of code after all.

Because of item 2 above, I've rejected any of the GPL/LGPL, strong copyleft, licenses because they're viral and mean the code can't be used with many other popular open source licenses. Conversely, item 2 also requires that the code must be able to be used in GPL/LGPL projects.

Having reviewed several popular licenses I think that the MIT License (a.k.a the X11 license) meets my criteria the best: it's very permissive, compatible with the GPL etc., disclaims warranty and is not too onerous to comply with.

I'm proposing to make the copyright statement read "© Peter Johnson (www.delphidabbler.com) and contributors".

Note that this proposal applies only to code currently in the database, all my future contributions, and that submitted using the CodeSnip Code Submission Wizard. In future I am planning to let contributors specify their own license.

Any comments welcome. In the absence of comments I'm proposing to roll this out in March 2014.

28 November 2013

CodeSnip v3 Support Ending Soon

Given the small number of users of CodeSnip 3 out there, and the even smaller number of bug reports for it, I've decided to end support for this version at the end of 2013.

So, from January 2014, no more bugs will be fixed and no new features will be added. That means that any new Delphi compilers released after the end of this year will not be added to CodeSnip 3.

If you want to keep up to date please update to CodeSnip 4 now.

Sorry if that causes inconvenience, but this is a one-man developmet team and I need to spend my time developing v5!

13 October 2013

Old Code Snippets Database Online App Retired

After many year's service I've finally retired the old Code Snippets Database online viewer. It's been replaced by the new JavaScript driven version - "Take 2" - available at http://snippets.delphidabbler.com/.

The old app hadn't been able to display the newer snippets in the database for some time. However the killer blow was that some recent changes to the back-end database broke the app's ability to generate Pascal units.

Any bookmarks you have to the defunct application will now automatically redirect to "Take 2", so you won't be left staring at a 404 page.

Some links to the old application requested it to display a set of snippets that were named in the URL query string. So as not to break these links this type of URL will redirect to a special snippet listing script that will display the required snippets.

"Take 2" is an Ajax application the does much of its processing in the browser, so it should be quicker to use once all the data has loaded. It's also got a much cleaner and more modern user interface.

Although "Take 2" is still in beta it now has many features of the old app and adds some new ones. The only major feature still to implement is text searching, and that's on the to-do list.

Aplogies if the change is inconvenient. Please do give the new version a try - it may do what you want. Do ask if there are any features you would like to be added.

And, if you're a Windows user, don't forget that there's the CodeSnip code bank application that can load and display the snippets from the database.

16 September 2013

CodeSnip 5 - Proposed Feature Removal

I'm getting on with developing CodeSnip v5 and have been thinking of ditching some features that have struck me as particularly useless. These are all features I haven't used personally since CodeSnip v1.

They are:

  1. The Save Snippet option from the File menu.
  2. The related Copy Snippet option from the View menu.

Before I delete the features I'm looking for some feedback as to whether anyone uses them and can't live without them. If you want to keep them in v5 please get in touch. If I don't hear any howls of protest, the features are going to go!

Let me know what you think either by commenting or sending me a message via my website's contact page.

What follows is a little overview of what the features do.

All these options do is to generate something like the following and either put it on the clipboard or write it to file:

{
 * This code snippet was generated by DelphiDabbler CodeSnip Release 4.8.0 on
 * Mon, 16 Sep 2013 16:53:57 GMT. It is made available on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. The code is used
 * entirely at your own risk.
}

{
  Required unit(s):
    SysUtils
}

function DateQuarterEnd(const D: TDateTime): TDateTime;
  {Gets the date of the last day of the quarter containing a given date.}
var
  Year, Month, Day, Quarter: Word;
begin
  SysUtils.DecodeDate(D, Year, Month, Day);
  Quarter := 4 - ((12 - Month) div 3);
  // get 1st day of following quarter
  Month := 0;
  SysUtils.IncAMonth(Year, Month, Day, Quarter * 3 + 1);
  // required date is day before 1st day of following quarter
  Result := SysUtils.EncodeDate(Year, Month, 1) - 1.0;
end;

There's also the Edit | Copy Source Code option that just put the actual snippet source on the clipboard:

function DateQuarterEnd(const D: TDateTime): TDateTime;
var
  Year, Month, Day, Quarter: Word;
begin
  SysUtils.DecodeDate(D, Year, Month, Day);
  Quarter := 4 - ((12 - Month) div 3);
  // get 1st day of following quarter
  Month := 0;
  SysUtils.IncAMonth(Year, Month, Day, Quarter * 3 + 1);
  // required date is day before 1st day of following quarter
  Result := SysUtils.EncodeDate(Year, Month, 1) - 1.0;
end;

So, all the first option adds is to list the dependencies in comments (which you can get in more details from the program's View | Dependencies menu option) and some disclaimer.

Over to you.