BradTrupp.com - Little slices of my life and my projects BradTrupp.com -- Pages
BradTrupp.com -- Pages -- Page 1 - 2006/01/14 - 2007/05/26

Page 1 - 2006/01/14 - 2007/05/26

<< Older || Newer >>


Montserrat, Spain, 2007 - Page 2 (2007/05/26)

Montserrat, Spain, 2007 - Page 2...

Continue Reading »


Ponta Delgada, Azores 2007 - Page 1 (2007/05/21)

Ponta Delgada is a municipality on Sao Miguel Island in the Azores....

Continue Reading »


Ponta Delgada, Azores 2007 - Page 2 (2007/05/21)

Ponta Delgada, Azores 2007 - Page 2...

Continue Reading »


Ponta Delgada, Azores 2007 - Page 3 (2007/05/21)

Ponta Delgada, Azores 2007 - Page 3...

Continue Reading »


Museum of Glass, Tacoma, 2006 (2007/04/01)

A few random shots from the glass bridge at the Museum of Glass in Tacoma....

Continue Reading »


Use MYSQLDUMP and CRON to backup Databases (MySql) (2006/05/23)

Use MYSQLDUMP and CRON to backup Databases
By Brad Trupp (c) 2007

If you are keeping any web site data in MYSQL databases, are you making regular backups?

"The mysqldump client can be used to dump a database or a collection of databases for backup or for transferring the data to another SQL server (not necessarily a MySQL server). The dump contains SQL statements to create the table and/or populate the table."-- from the MySQL Reference Manual.

Technique 1

I wrote a short PERL script to backup my database and compress the results into a unique name based on current date.

Sample PERL script --

#!/usr/bin/perl

($Second, $Minute, $Hour, $Day, $Month, $Year, $WeekDay, $DayOfYear, $IsDST) = localtime(time) ; 

$Year += 1900 ; $Month += 1;

$dt = sprintf("%04d%02d%02d", $Year, $Month, $Day, ) ;

exec "/usr/local/bin/mysqldump --opt -hHOSTNAME -uUSERID -pPASSWORD DATABASE_NAME |gzip > PATHNAME/$dt.gz";

The $dt variable gets resolved to the current date in YYYYMMDD format.

You will need to customize the exec statements where:

  • Change /usr/local/bin/ to the correct location for mysqldump (or take it out if it is on your path)
  • Substitute the correct names for HOSTNAME, USERID, PASSWORD, and DATABASE_NAME.
  • Put in the correct path name in the PATHNAME variable for the output file location.
  • If gzip is not in your path then put in the proper location too.
So each time you run the perl script, it will backup your database and compress the results into a unique name.

As for running it regularly, just set up a CRON job to run it daily, weekly, or whatever. I'm no CRON expert but I use pair hosting so CRON's can be set up from a control panel without any real knowledge.

Enjoy this gem of wisdom -- it took me far longer than it should of to figure out what goes on the EXEC command.

Technique 2

The wizards at Pair networks sent out this gem of wisdom in one of their monthly newsletters.

To back up a particular database, enter this command (all on one line):

/usr/local/bin/mysqldump -hDBXX.PAIR.COM -uDB_USERNAME -pDB_PASSWORD USERNAME_DATABASENAME > 
usr/home/USERNAME/backup/DATABASENAME.`/bin/date +\%Y\%m\%d`

Here are the replacement values for the above command:

DBXX.PAIR.COM = The hostname of the database server the database resides on
DB_USERNAME = The MySQL username for the database in question
DB_PASSWORD = The MySQL password for the username above
USERNAME_DATABASENAME = The full name of the database
USERNAME = Your pair Networks username

These commands will generate a file in the "backup" directory off of the home directory called DATABASENAME.DATE where DATE is the date the backup was made. Make sure that a "backup" directory exists off of your home directory when creating these cron jobs.

Just set this up to run regularly with cron and you now have regular backups.


Reflections on Company Policies (Business Tips) (2006/05/01)

Start with a cage containing five monkeys.

In the cage, hang a banana on a string and put a set of stairs under it. Before long, a monkey will go to the stairs and start to climb towards the banana. As soon as he touches the stairs, spray all of the monkeys with cold water. After awhile, another monkey makes an attempt with the same result. Pretty soon, when any monkey tries to climb the stairs, the other monkeys will try to prevent it.

Now, turn off the cold water. Remove one monkey from the cage and replace it with a new one. The new monkey sees the banana and wants to climb the stairs. To his horror, all of the other monkeys attack him. After another attempt and attack, he knows that if he tries to climb the stairs, he will be assaulted.

Next, remove another of the original five monkeys and replace it with a new one. The newcomer goes to the stairs and is attacked. The previous newcomer takes part in the punishment with enthusiasm.

Again, replace a third original monkey with a new one. The new one makes it to the stairs and is attacked as well. Two of the four monkeys that beat him have no idea why they were not permitted to climb the stairs, or why they are participating in the beating of the newest monkey.

After replacing the fourth and fifth original monkeys, all the monkeys which have been sprayed with cold water have been replaced. Nevertheless, no monkey ever again approaches the stairs.

Why not? Because that's the way it's always been around here.

And that is how company policy begins...


Understanding Google Adsense (Website Tips) (2006/01/16)

Understanding Google Adsense
By Brad Trupp (c) 2006

Google AdSense is certainly the most popular Pay Per Click or PPC program in our industry today. All you have to do is enroll your site under the Google AdSense program and add some code to your web site to display ads on your web pages. You earn each time a visitor to your site clicks on one of these ads.

Visitors don’t have to buy anything. After all, this is a pay per click program and not a pay per action or CPA program. They just have to click on the ads and nothing more ­ but the advertisers hope visitors do more than just click and look The advertisements on Adsense come from advertisers using Google’s Adwords program.

Ads are definitely not random, but instead are selected to be contextually relevant, meaning, that they are selected based on their relevancy to the subject of your site.

By providing high quality content and careful use of keywords, you provide an excellent base for individuals looking for information about specific products and services, and an excellent vehicle for advertisers targeting those individuals.

There are three determinative factors for the revenue of a site enrolled under the AdSense program.

1. The Cost Per Click or CPC of the ads appearing to your site.

2. The number of page impressions, or simply put, the amount of traffic that passes through your site. If you have a lot of page impressions, you have a better chance of getting a lot of clicks.

3. The Clickthrough Rate or CTR, which is the percentage of viewers who click on your Adsense ads. The higher your CTR, the more you should earn.

Getting more Impressions!

Here are some ways to increase traffic at your web site.

You can create more web pages adding with relevant and focused content.

You can create more internal links to your web pages by cross-linking topics.

List your web site under relevant categories in more directories.

Set up a directory of relevant sites on your website and accept relevant reciprocal links

Write relevant articles. Ensure that your site information in the resource box at the end of each article. Submit to article directories such as http://www.IdeaViewer.com.

Advertise with pay per click search engines.

Getting more Clicks!

Clickthrough rates are the percentage of viewers who click on your Adsense ads. You can increase Clickthroughs by increasing the relevance of Adsense ads on your site, and by tweaking the format and placement of your ads.

You cannot choose which ads Adsense shows on your site, but you can influence the relevance of the ads through your choice of content on each web page and across your web site.

If every page on your site focuses on the site topic, it is more likely that the Adsense ads will too. For example, if the focus of your web site is all about books, and the word “book” appears several times on every page, it is likely that your Adsense ads will relate to books.

The best placement for Google ads varies from page to page, depending on content. Some locations tend to be more successful than others. Wider ad formats tend to outperform their taller counterparts. Google has a "heat map" at http://www.google.com/support/adsense/bin/static.py?page=tips.html that shows how the placement of ads affects the clickthroughs. The colors of the ads also has an effect.

The best way to optimize your web site is to use the Adsense channels feature to track your ad formats and placements. It then becomes all about testing and tracking to see what performs best for you.

What is Effective CPM?

Effective CPM is a measure of your average earnings per thousand impressions. You can increase your Effective CPM by selecting topics that might attract higher bids from advertisers, and building pages and whole websites based on higher paying topics.

Even though Google does not release much information about the value of Adsense bids, you can get a good idea of top paying topics by looking at information tools on Adwords and other pay-per-click search engines. There are also many keyword research tools available, both free and paid, that can help you find high paying topics.

Succeeding with Adsense!

It is a really simple set of rules to help increase your Adsense income.

Build pages and websites with focused content for the best Effective CPM.

Place and format your Adsense ads to maximize clickthroughs.

Promote your sites. Drive targeted traffic to your web pages for maximum impressions.


Handle-Free Checkboxes in a String Grid (Delphi) (2006/01/14)

'Handle-Free' Checkboxes in a String Grid
by Brad Trupp (c) 1997

This was the draft for an article I wrote back in 1997. It was published February of that year as hax # 252 in Visual Developer. Visual Developer was a magazine published by The Coriolis Group until 2001. You can read a little more of its history on Jeff Duntemann's ContraPositive Diary.

Have you ever put together a large form with a few hundred controls and see your old friend the EOutOfResources exception when you ran it? One reason is that your form is using too many windows handles.

This HAX example shows how to imbed checkboxs in any cell in a TStringGrid and use exactly zero additional windows handles. Start by dropping a stringgrid on your form and setting your maximum columns and rows. Next, add an array of boolean with the same dimensions as the stringgrid to hold the value of the checkboxes. Our FormCreate method fills the stringgrid with some initial text values and sets all the checkboxes to true. This is so the checkboxes will display initially as checked.

The grids DrawCell method is called each time a cell needs to be drawn. It clears out the cell region, calculates where the checkbox goes, calls our DrawCheckBox routine to print the check box, and finally prints the cell’s text. Since DrawCheckBox routine is passed the sender TStringGrid, and uses the senders canvas property, it can be called from any TStringGrid. The Rectangle method draws the empty checkbox. The “X” inside is done by drawing lines from top left to bottom right and bottom left to top right corners.

We detect if our checkbox was clicked by saving the mouse X and Y co-ordinates on the grid’s MouseDown event and comparing then against the mouse co-ordinates on the MouseUp event. If the two sets are in the same grid cell and are in the check box area then it’s a hit. If so, we store the new status of the checkbox in our boolean array and redraw the checkbox to the correct state.

A few ways you can extend this sample are to allow for multiple check boxes or use bitmaps to show checked and unchecked.

Listing 1: PGRID.PAS
unit Pgrid;

interface

uses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  Forms, Dialogs, Grids;

type
  TForm1 = class(TForm)
    StringGrid1: TStringGrid;
    procedure FormCreate(Sender: TObject);
    procedure StringGrid1DrawCell(Sender: TObject; Col, Row: Longint;
      Rect: TRect; State: TGridDrawState);
    procedure StringGrid1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure StringGrid1MouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
  private
    cb: array[0..9,0..9] of boolean;
    DownMouseX, DownMouseY : integer;
    procedure DrawCheckBox( Sender: TObject; Rect: TRect; myState: boolean);
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
var
   iCol, iRow: integer;
begin
     for iCol:= 0 to 9 do for iRow:= 0 to 9 do begin
         cb[iCol,iRow]:=true;
         StringGrid1.cells[iCol,iRow]:=char( ord('A')+iCol+iRow);
         end;
end;

procedure TForm1.StringGrid1DrawCell(Sender: TObject; Col, Row: Longint;
  Rect: TRect; State: TGridDrawState);
var
   myOffset: longint;
   R: TRect;
   s: string;
begin
     if ( Col = 0 ) or ( Row = 0 ) then exit;
     myOffset := Rect.Bottom - Rect.Top - 2;
     (Sender as TStringGrid).Canvas.FillRect(Rect);
     R := Classes.Rect( Rect.Left, Rect.Top, Rect.Left+myoffset-1, Rect.Bottom );
     DrawCheckBox( sender, R, cb[Col,Row]);
     R := Classes.Rect( Rect.Left+myoffset+2, Rect.Top, Rect.Right, Rect.Bottom );
     (Sender as TStringGrid).Canvas.TextRect(  R, R.Left + 2,R.Top+2,
             (Sender as TStringGrid).Cells[ Col, Row] );
end;

procedure TForm1.StringGrid1MouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
     DownMouseX:=X; DownMouseY:=Y;
end;

procedure TForm1.StringGrid1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  R, ARect : TRect;
  itemHeight : integer;
  Col1, Row1, Col2, Row2: longint;
begin
  with (Sender as TStringGrid) do begin
      MouseToCell(DownMouseX, DownMouseY, Col1, Row1);
          MouseToCell(X, Y, Col2, Row2);

          if ( Col1 > 0 ) and (Col1 = Col2) and
                 ( Row1 > 0 ) and (Row1 = Row2) then
          begin
                ARect :=cellrect( col, row);
        itemHeight := ARect.Bottom - ARect.Top - 2;
                { Are the mouse down and mouse up positions in the same box? }
                if ( ARect.Left < X ) and ( X < ARect.Left+2+itemHeight-1 ) and
                   ( ARect.Top < Y ) and  ( Y < ARect.Bottom )and
                   ( ARect.Left < X) and  ( X < ARect.Left+itemHeight-1 ) and
                   ( ARect.Top < Y ) and  ( Y < ARect.Bottom ) then begin
                         cb[Col,Row] := not cb[Col,Row];
             R := Rect( ARect.Left, ARect.Top, ARect.Left+itemHeight-1, ARect.Bottom );
             DrawCheckBox( sender, R, cb[Col,Row]);
                   end;
      end;
  end;
end;

procedure TForm1.DrawCheckBox( Sender: TObject; Rect: TRect; myState: boolean);
var
  itemheight, itemIndent : integer;
begin
with (Sender as TStringGrid) do begin
     itemHeight := Rect.Bottom - Rect.Top - 2;
     Canvas.Font.Color := Font.Color;
     Canvas.Pen.Color := Font.Color;
     Canvas.Rectangle(
        Rect.Left + 1, Rect.Top + 1,
        Rect.Left + 1 + ItemHeight, Rect.Top + ItemHeight + 1);
     { draw X in box }
     if myState then begin
        Canvas.MoveTo( Rect.Left + 1, Rect.Top + 1);
        Canvas.LineTo( Rect.Left + 1 + ItemHeight, Rect.Top + ItemHeight + 1);
        Canvas.MoveTo( Rect.Left + ItemHeight, Rect.Top + 1);
        Canvas.LineTo( Rect.Left , Rect.Top + ItemHeight + 1);
        end;
     end;
end;

end.


Explorer-Style Fly-By Buttons (Delphi) (2006/01/14)

Delphi - Explorer-Style Fly-By Buttons
By Brad Trupp (c) 1997

This was the draft for another article published June 1997 in Visual Developer magazine as hax # 257.

Have you seen those fly-by buttons in products like Microsoft's Internet Explorer where they do not become active until the mouse cursor passes over them? Using Delphi’s TSpeedButton as a base, we can simply and quickly construct a work-alike button.

There are two tricks that really pull our explorer style buttons together quickly. The first one is found by looking down the object hierarchy of TSpeedButton, beyond its base of TGraphicControl, and down into TControl where you find two useful events. One tells you when the mouse passes onto your control, and the other when it leaves. These are CM_MOUSEENTER and CM_MOUSELEAVE.

The second trick is that the paint method for TSpeedButton already displays nicely grayed out text and graphics when the button is disabled. By capturing the CM_MOUSEENTER and CM_MOUSELEAVE events, you can bring the button to life, enabling it as the mouse passes over, and disabling it as the mouse leaves. We gray out the button initially in the Create method by setting Enable to False. As an added bonus, we use the Create method to make the button a little larger since speed buttons are so tiny by default.

If you have the VCL source code, you could just copy out the Paint method and modify it to your whims. Instead we will let the button draw out normally and paint our changes over top. Our Paint method flattens out the button by drawing new lines over the TSpeedButton’s existing 3D lines. The line color is set to the same color, clBtnFace, as the speed button background. When the button is enabled, our Paint method draws a focus box around the button, showing it as active. The focus box is inset by 1 pixel around the button since you normally overlap speed buttons slightly.

One small 'unfeature' caused by taking over the normal Enable property is that there is no way to completely disable buttons anymore. This is remedied by adding a new property called Disable. Three extra lines of code, and all it does is prevent the button from being enabled as the mouse passes over. Way too simple?

Listing 1: PGRID.PAS

unit Xplorbtn;

interface

uses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  Forms, Dialogs, Buttons;

type
  TExplorerButton = class(TSpeedButton)
  private
    FDisabled: boolean;
    procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;
    procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
  protected
    procedure Paint; override;
  public
    constructor Create(AOwner: TComponent); override;
  published
    property Disable: boolean read FDisabled write FDisabled default FALSE;
  end;

procedure Register;

implementation

constructor TExplorerButton.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  SetBounds(0, 0, 33, 33);
  enabled:=false;
end;

procedure TExplorerButton.CMMouseEnter(var Message: TMessage);
begin
  inherited;
  if not FDisabled then enabled:=true;
end;

procedure TExplorerButton.CMMouseLeave(var Message: TMessage);
begin
  inherited;
  enabled:=false;
end;

procedure TExplorerButton.Paint;
begin
     inherited paint;
     with Canvas do begin
     { Paint over the 3D rectangle }
     Font.Color := clBtnFace;
     Pen.Color := clBtnFace;
     Pen.width:=3;
     MoveTo( 0, 0); LineTo( 0, Height-2); LineTo( Width-2, Height-2); LineTo( Width-2, 0); LineTo( 0, 0);
     { Draw a box around active selection. Indent by 1 pixel since speedbuttons tend to be overlapped in design. }
     if enabled or ( csDesigning in ComponentState ) then begin
       Font.Color := clWindowText;
       Pen.Color := clWindowText;
       Pen.width:=1;
       MoveTo( 1, 1); LineTo( 1, Height-2); LineTo( Width-2, Height-2); LineTo( Width-2, 1); LineTo( 1, 1);
       end
     end;
end;

procedure Register;
begin
  RegisterComponents('Samples', [TExplorerButton]);
end;

end.

<< Older || Newer >>


 

All Tags
Business Tips
Code
Life Skills
Music
My 15 minutes
Old Articles
Photos