Tuesday, October 31, 2006

Using ASP to put the Current Date on a Page

Ever wanted to put the current date and or time on a page? ASP makes it easy using two built in functions:

Date() (or Now())

Date() returns the current date
Now() returns the current date and time

You can use either one with FormatDateTime().

FormatDateTime allows you to change the way the date/time appears.

FormatDateTime(date(),vbgeneraldate) = 10/31/2006
FormatDateTime(date(),vblongdate) = Tuesday, October 31, 2006
FormatDateTime(date(),vbshortdate) = 10/31/2006
FormatDateTime(now(),vblongtime) = 10:25:49 AM
FormatDateTime(now(),vbshorttime) = 10:25

You can use number values instread of the vb values, per the following chart:
vbGeneralDate0Display a date in format mm/dd/yy. If the date parameter is Now(), it will also return the time, after the date
vbLongDate1Display a date using the long date format: weekday, month day, year
vbShortDate2Display a date using the short date format: like the default (mm/dd/yy)
vbLongTime3Display a time using the time format: hh:mm:ss PM/AM
vbShortTime4Display a time using the 24-hour format: hh:mm

Friday, October 27, 2006

Internet FTP - Web Based FTP Clients

Ever needed to connect to an FTP site and not have access to an FTP client? And can't install a client? Or are you on a computer somewhere that has the FTP port is blocked?

The solution is Web based FTP - FTP over HTTP.

There are a few out there, but the most consistent and useful one I've found is Net2FTP.

At Net2FTP you can enter yout FTP server information and do all your FTP stuff through a web interface. So now you can work on your web sites no matter what computer you're on!

Thursday, October 26, 2006

How to Filter out Bad Bots in ASP with Global.asa

Bad bots? What are those? And why should I keep them out of my web site?

Glad you asked....

Do a search for "bad bot" and you'll find various lists, most written by web site owners who've noticed some strange behavior among the many bots visiting their sites. Although the The definition of a "bad bot" would vary depending on who you ask, there are various behaviors that can be/are considered bad:

not reading robots.txt
disobying robots.txt
requesting too many pages in a short time span
revisiting pages too often
e-mail harvesting
Guestbook spamming
Log Spamming
munging URL's
scraping content
and more....

Trying to use robots.txt for bad bots that either don't read robots.txt or disobey it won't work, so you'll have to use other methods against them. Although some bad bots change both their User Agent and IP address, using one or the other (or both) to ban these bots remains an easily implemented solution. If you want more advanced methods, do a search for "robot trap".

Using Gloabl.asa to Stop Bad Bots

Global.asa is an optional file that can contain declarations of objects, variables, and methods that can be accessed by every page in an ASP application. All valid browser scripts (JavaScript, VBScript, JScript, PerlScript, etc.) can be used within Global.asa.

The Global.asa file can contain only the following
  • Application events
  • Session events
  • <object> declarations
  • TypeLibrary declarations
  • the #include directive
Note: The Global.asa file must be stored in the root directory of the ASP application, and each application can only have one Global.asa file.

This isn't an artivle about Globals.asa, so I'm not going to go into depth here. Suffice to say that in Global.asa there's a section reserved for Session_OnStart. Session_OnStart occurs EVERY time a NEW visitor (including a bot) requests his or her (ot its) first page in the ASP application.

That means you can have a bit of code executed everytime a new visitors arrives on your site, no matter what the entry page.

Here's an example of a global.asa file that will direct bad bots, detected by user name, to a file named "badbot.html". The names here are actual bad bots I've found poking around my various sites. If you do a search for "bad bot lists", you'll find plenty of resources to help you identify bad bots.
<script language="vbscript" runat="server">
sub Session_OnStart
dim vUserAgent, vBad

vUserAgent = Request.ServerVariables("HTTP_USER_AGENT")
vBad = 0

Select Case vUserAgent
Case "larbin_2.6.3 larbin2.6.3@unspecified.mail"
Case "larbin_test nobody@airmail.etn"
Case "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt; DTS agent"
Case "Missigua Locator 1.9"
Case "EmeraldShield.com WebBot"
Case "<unknown user agent>"
Case "Web Downloader/6.5"
Case "Xenu Link Sleuth 1.2f"
Case "Zeus 46694 Webster Pro V2.9 Win32"
Case "LMQueueBot/0.1"
Case "Zeus 28879 Webster Pro V2.9 Win32"
Case "Offline Explorer/2.1"
Case "HTMLParser/1.4"
Case "Zeus 94377 Webster Pro V2.9 Win32"
Case "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; but first you must bring me a shrubbery)"
Case "W3CRobot/5.4.0 libwww/5.4.0"
Case "updated/0.1beta (updated.com; http://www.updated.com; crawler@updated.com)"
Case "mogren_5.4.1 mogrn@mail.ru"
Case "Holmes/1.0"
Case "Ken"
Case "Cuasarbot/0.9b http://www.cuasar.com/spider_beta/"
Case "EmailSiphon"'2/22
Case "Java/1.4.1_04"
Case "OmniExplorer_Bot/1.09 (+http://www.omni-explorer.com) Rentals Crawler"
Case "BigCliqueBOT/1.03-dev (bigclicbot; http://www.bigclique.com; bot@bigclique.com)"
Case "combine/0.0"
Case "Avant Browser (http://www.avantbrowser.com)"
Case "Anonymous/Password"
Case "Mozilla/4.0 pradipjadav@gmail"
Case "aipbot/1.0 (aipbot; http://www.aipbot.com; aipbot@aipbot.com)"
Case "abot/0.1 (abot; http://www.abot.com; abot@abot.com)"'4/8
Case "OmniExplorer_Bot/1.09 (+http://www.omni-explorer.com) Boats Crawler"
Case "AtlocalBot/1.1 +(http://www.atlocal.com/local-web-site-owner.html)"
Case "Java/1.4.2_04"
Case "Web Downloader/6.3"
Case "sbSrer33n qeeyuSrSy hna"
Case "Java/1.4.2_06"
Case "MVAClient"
Case "4"
Case "versus crawler eda.baykan@epfl.ch"
Case "telnet0.1 noone@example.org"
Case "ssquidagent pradipjadav@gmail"
Case "Zeus 83206 Webster Pro V2.9 Win32"
Case "ichiro/1.0 (ichiro@nttr.co.jp) 1 1 0.12%"
Case "larbin_2.6.3 larbin2.6.3@unspecified.mail"
Case "larbin_2.6.3 (larbin2.6.3@unspecified.mail)"
Case "MediaMirror (0.1a)"
Case "Missigua Locator 1.9"
Case "test/0.1"
Case "larbin_2.6.3 (wgao@genieknows.com)"
Case "larbin_2.6.3 wgao@genieknows.com"
Case "Java/1.5.0_02"
Case "noxtrumbot/1.0 (crawler@noxtrum.com)"
Case "versus crawler eda.baykan@epfl.ch"
Case "updated/0.1beta (updated.com; http://www.updated.com; crawler@updated.com)"
Case "0.1 noone@example.org"
Case "Mozilla/4.0 (compatible; BorderManager 3.0)"
Case "Missigua Locator 1.9"
Case "BigCliqueBOT/1.03-dev (bigclicbot; http://www.bigclique.com; bot@bigclique.com)"
Case "POE-Component-Client-HTTP/0.65 (perl; N; POE; en; rv:0.650000)"
Case "RPT-HTTPClient/0.3-3"
Case "SeznamBot/1.0 ( http://fulltext.seznam.cz/)"
Case "Zeus 2339 Webster Pro V2.9 Win32"
Case "telnet0.1 (noone@example.org)"
Case "Wget"
Case "Mozilla/4.0 (compatible; Cerberian Drtrs Version-3.2-Build-0)"
Case "HLoader"
Case "Java/1.4.1_04"
End Select

If vBad=1 then
End If
end sub
To use this, simply create a file named global.asa, paste in the above script, and save it in the root of your web site. Any bot with a user name matching any of the above will be sent to the non-existance web site "http://www.no-where-at-all-in-the-universe.com". You can use the same bad bots I'm using or build your own list.

Wednesday, October 25, 2006

The Importance of Fast Loading Web Pages

Usability studies have shown that visitors are willing to wait for about 10 seconds for a page to load before moving on. If your web page takes too long to load, you may consider redesigning it. Making the page load faster will increase the number of visitors that hang around and explore your site.

Despite the ready availability of broadband, high-speed connections still only make up about 60% of Internet connections. Not everyone has a cable modem, a T1, or DSL connection. The truth is that there are still a large number of surfers with modems of 56k.

Here are a few things you can do to make your pages load faster:

Consider taking out any embedded multimedia (background song, videos etc.) unless absolutely necessary. Yes, they might create a great effect, but if your visitors get impatient and leave, then the whole purpose is lost. Beside, most people don't want to be serenaded by the Andy Griffith theme while surfing your site.

Optimize images. You can do this with most image editing software. You can also save loading time by re-using images between pages (these will be on the browser's cache and will load much faster).

Preload images. If you have a few large images throughout your site, you can put it on the home page at the bottom of the page by simply adjusting the width and height to 1. This will make is seem to be no larger than a dot, even though the entire image will be loaded and saved to the disk cache.

Use height and width tags on your images. This way the browser will know were everything is before the images are loaded. The users can start to read what is on your site before all images are loaded.

If you are using tables, don't make very large ones, instead construct several smaller ones (you can always link them up if you want). This will help quite a bit. Also, don't put tables inside other tables if you can help it, because the browser will take longer to work out the spacing.

Remove "white space" (the spaces between your coding).

Last but not least, make sure your front page is as short as possible. A longer page will take a long time to load, even if it's all text. You can always use a link with extra info on another page. If you have too much content on a page, consider splitting it into two or more pages.

A fast-loading site will keep visitors waiting, and the last thing is you web visitors bailing out before the page loads becuase it's taking too long.

Monday, October 23, 2006

Geek Babe Monday - Jolene Blalock

Although Jolene proved to be a born surfer while growing up in California, she decided to pursue an acting career. Born and raised in California, Jolene's father would take her and her brothers to the water to surf, in what became a regular family sport.

She made her debut in 1998, in a bit part in the comedy Veronica's Closet, and The Love Boat: The Next Wave a year later.

Jolene got her big break when she was cast as Medea in the NBC miniseries, Jason and the Argonauts in 2000, co-starring Jason London and Natasha Henstridge.

2000 was a big year for the natural blonde turned brunette, who appeared in an episode of G vs E, a couple of episodes of D.C., and a guest spot on C.S.I.. She also appeared in the military drama JAG.
Jolene Blalock - Subcommander T'polJolene Blalock
Jolene hit the big time when she was cast as Subcommander T'Pol in the installment of the Star Trek franchise, Enterprise. With the success that Jeri Ryan brought to the show as Seven of Nine, Jolene is sure to make every man a Trekker. The part forced her to wear pointy devil ears, a wig and a catsuit (yes!), and incidentally, she was going to turn down the role at first.

All I have to say is "beam me up!"

Thursday, October 19, 2006

Changing the Way Links Look

Although CSS is pretty well know, I still often get or see questions about how to change the way links look and act. Using CSS, it's easy to change link appearance and behavior.

Here are the four CSS aspects of a link that you can affect:
A:link - base appearance of the link
A:visited - the way the link looks after it has been clicked on
A:hover - the way the link looks when the user hovers the mouse pointer over it
A:active - the way active links look; a link becomes active once you click on it

Example: remove underline and make links red on mouseover:

<STYLE TYPE="text/css">
a {text-decoration: none;}
a:hover {color:red;}
Note that by assigning value to the base 'a' tag, you change the appearance of ALL links. What if you only want to change some? Enter the subclass::

<STYLE TYPE="text/css">
a.LinkStyleOne:link {text-decoration: none;}
a.LinkStyleOne:hover {color:red;}
You would then contstruct the link like:
<a href="http://www.SomePlace.com/" class="LinkStyleOne">Link Text</a>

Using CSS you can change all sort of aspects of link appearance, highlight color, underline style, background color, size and much more.

Wednesday, October 18, 2006

How to Hide Email Addresses from Spammers

Are you tired of spam? I know I am.

Hard-core spammers use what are termed 'bot' to crawl the web and harvest email address. These bots search through page source code looking for email addresses. Because of the fixed format of an email address, they are pretty easy for to automatically extract from page code.

Here's a handy way to hide email address from most bots using JavaScript. Being client side executed, JavaScripts aren't run until the page is assembled by the client. Although most automated bots can see the JavaScript at the code level, they aren't able to execute it.

What this littel code does is seperate your email into variables, which JavaScript then assembles. Bot aren't able to assemble the parts, thus don't see the email address.
<script language=javascript>
var linktext = "Email the Webmaster";
var part1 = "webmaster";
var part2 = "MySite.com";

document.write("<a href=" + "mail" + "to:" + part1 + "@" + par2 + ">" +
linktext + "</a>")

Replace 'Email the Webmaster' with whatever link text you want, 'webmaster' with the front part of your email address, and 'MySite.com' woth the rest of your email address. Notice that I also break up the 'mailto' portion as well.

Simply place this little script wherever you want. Users (with JavaScript enabled) will be able to see it, but the bots won't!

Tuesday, October 17, 2006

Write to a File in ASP

Here's a simple script that will create (or open) a file and write to it:
<% const ForAppending=8 const TristateFalse=0  dim oFile, oFSO, strFileName  'Create a filesystem object    Set oFSO = CreateObject("Scripting.FileSystemObject")  'The path and strFileName to write to strFileName="c:\inetpub\wwwroot\MyWebSite\files\testfile.txt"  'Open the file or create a new if it does not already exist Set oFile = oFSO.OpenTextFile(strFileName, ForAppending, true, TristateFalse)  'Write to the file oFile.Writeline "This is a test!"  'Close the file oFile.Close  'Free the objects set oFile=nothing set oFSO=nothing %>
If the file doesn't exist, it will be created and the line written to it. If the file already exists, it will be opened and the new line added at the bottom of all the existing lines.

If you are executing this script from a web page, then you need to make sure the the IUser account has been granted write permissions to whatever directory the file is in. In the example, you would need to make sure IUser has write permissions to the 'files' folder.

Monday, October 16, 2006

Geek Babe Monday - Alexa Davalos

Alexa Davalos starred opposite Vin Diesel in The Chronicles of Riddick adn was the character Gwen Raiden in the TV Series Angel. Born in 1982 in Paris, France, Davalos relocated to Los Angeles from New York. She made her first screen appearance in John Frankenheimer's Riviera when she was 3. Her love of performing took root when her family relocated to New York City and Davalos became involved with ballet. Following her mother (Elyssa Davalos, a notable television and theater actress) and grandfather (Richard Davalos, legendary for his performance as James Dean's brother in East of Eden) from set to set allowed Davalos a unique insight into the world of acting.
Alexa Davalos from Chroinicles of RiddickAlexa Davalos
Throughout her childhood, her mother continued training with Stella Adler. Davalos sat in on some of those classes and remembers the experience as having a profound impact on her desire to act. In her early teen years, she spent most of her time on location or in the theater with her mother, doing anything to be involved. It was also around this time that she made her first commercial with Patty Hansen. She has worked as a model with such prominent photographers as Peter Lindbergh and her father, Jeff Dunas.

ASP Database Connection Strings: Access and SQL Server

SQL Server 2000 ODBC connection using Named Pipes:
Driver={SQL Server};
SQL Server 2000 and 2005 ODBC connection via IP address (IP Address,Port - default port is 1433):
Data Source=,1433;
Network Library=DBMSSOCN;
Initial Catalog=DatabaseName;
User ID=Username;
SQL Server OLE DB:
Data Source=ServerName;
Initial Catalog=DatabaseName;
User Id=UserName;
SQL Server 2000 OLE DB via IP address (IP Address,Port - default port is 1433):
Data Source=,1433;
Network Library=DBMSSOCN;
Initial Catalog=DatabaseName;
User ID=UserName;
SQL Server 2005 ODBC connection using Named Pipes (You might need to download the SQL Server 2005 Native Client; the download contains both the ODBC and OLE DB providers):
Driver={SQL Native Client};
SQL Server 2005 Express ODBC connection to a database file (mdf):
Driver={SQL Native Client};
SQL Server 2005 Express ODBC connection when the file resides in the data directory:
Driver={SQL Native Client};
Access ODBC:
Driver={Microsoft Access Driver (*.mdb)};
Access OLE DB:
Data Source=\path\Database.mdb;
User Id=admin;

Friday, October 13, 2006

Sending Email in ASP Using CDONTS

I've already writen an article about sending email in Windows 2003 using CDO; no I'll present a method for sending email using ASP from Windows 2000.

In OS years, Windows 2000 is pretty ancient. Never-the-less, there are still plenty of web site hosted on Windows 2000 servers. On such a system, if you want to send mail from a web site, you need to use the CDONTS object as opposed to the CDO.

Here's the quick and easy for sending a text message
Dim MailBody
Dim objMail

MailBody = ""
MailBody = "This is an email from CDONTS." & vbCrLf
MailBody = MailBody & "It is easy to send mail using CDONTS" & vbCrLf
MailBody = MailBody & "Give it a try!"

Set objMail = CreateObject("CDONTS.NewMail")
objMail.From= "somebody@somewhere.com"
objMail.To= "somebodyElse@somewhereElse.com"
objMail.Subject="Text Email from CDONTS"
objMail.Body= MailBody
set objMail=nothing
vbCrLf means Carriage return Line feed; this is to mark the end of a line and star a new one. The vb in fron mean - you guessed it - VBScipt. Ther are a bunch of other vb character codes available as well.

You can also send an strHTML formatted email with CDONTS:
Dim objMail
Dim strHTML

Set objMail = CreateObject("CDONTS.NewMail")
strHTML = ""
strHTML = strHTML & "<HTML>"
strHTML = strHTML & "<head>"
strHTML = strHTML & "<title>Sending CDONTS HTML Email</title>"
strHTML = strHTML & "</head>"
strHTML = strHTML & "<body bgcolor=""FFFFFF"">"
strHTML = strHTML & "<p><font size =""3"" face=""Arial""><strong>"
strHTML = strHTML & "It's also easy to send an HTML formatted email.</strong><br>"
strHTML = strHTML & "You can use HTML tags right in your string.</p>"
strHTML = strHTML & "<p align = ""center"">Beautiful HTML emails are only a momnet away!</p>"
strHTML = strHTML & "</body>"
strHTML = strHTML & "</HTML>"

objMail.From= "somebody@somewhere.com"
objMail.To= "somebodyElse@somewhereElse.com"
objMail.Subject="HTML FOrmatted Email from CDONTS"

set objMail=nothing
There are a few things worth talking about here: Notice the double quotes inside the strHTML assignments. When assign attributes to tags, you have to use either:

Double Quotes: <font size=""3"">
Single Quotes: <font size='3'>
No Quotes: <font size=3>

If you use a single quote, the script will think that's where the string assignment ends and your script will break.

If you want to include an image, you can point to any image by fully qualifying the src tag: <img src=""http://www.ImageServer.com/MyImage.jpg"">

If you send an HTML formatted mail to a mail reader that doesn't support HTML (most do), it will come out with the tags included.

With CDONTS, you can also send attachments and Carbon Copies. To send an attachment, use the AttachFile method. This method has three parameters:

1. Source, type String or Istream object. This parameter is required, and must contain the full path and file name of the attachment. Only C/C++ and Java programs can use an Istream object.

2. FileName (optional). This provides a file name to appear in the attachment's placeholder in the message. If not specified, the file name from the Source parameter is used.

3. EncodingMethod (optional). Indicates the encoding of the attachment. There are two possible values: 0, meaning the attachment is in UUEncode format; and 1, indicating the attachment is in Base64 format. (Base64 is the encoding scheme defined by MIME; UUEncode is an older format that you should use if you suspect your recipient(s) may not have a MIME-compliant system.) The default value of this parameter depends upon the MailFormat property. If the MailFormat property is set to 1, the default value of EncodingMethod is 0. If the MailFormat property is set to 0, the default value of EncodingMethod is 1.

Example of a completed AttachFile with all parameters:
objMail.AttachFile Server.MapPath("/DirectoryOnYourSite/TheFileToAttach.txt"),"FileYouAskedFor.txt",1

Here's the whole she-bang. IN this example, I want the file to be sent with the same name it has on my server, and since I'm setting MailFormat to 0, I dont' need to set the EncodingMethod parameter:
Dim MailBody
Dim objMail

Set objMail = CreateObject("CDONTS.NewMail")
objMail.From= "somebody@somewhere.com"
objMail.To= "somebodyElse@somewhereElse.com"
objMail.Subject="CDONTS Email with CC and Attachment"

objMail.AttachFile Server.MapPath("/DirectoryOnYourSite/TheFileToAttach.txt")

MailBody = "CDONTS Mail with file attached" & vbCrLf
MailBody = MailBody & "The file must reside on your web server" & vbCrLf
MailBody = MailBody & "The File must be less than 2 megs in size" & vbCrLf
MailBody = MailBody & "If you need to send larger files, check with your hosting company" & vbCrLf

objMail.Body= MailBody
set objMail=nothing
More stuff to jam into your brain:

BodyFormat sets the text format of the mail object. It has two possible values: 0, which indicates that the body of the message includes Hypertext Markup Language (HTML); or 1, which indicates that the body of the message is plain text. The default value is 1, so this property does not need to be set for plain text messages.

MailFormat sets the encoding for the mail object. It has two possible values: 0, which indicates that the object is to be in MIME (Multipurpose Internet Mail Extension) format; or 1, which indicates that the object is to be in uninterrupted plain text. This property is optional, and its default value is 1. This property determines the default value for the EncodingMethod parameter in the AttachFile method (to be discussed later). When sending an attachment, set the MailFormat property to 0.

Importance (optional) sets the importance associated with the mail object. The possible values are: 0, indicating low importance; 1, indicating normal importance (default); and 2, indicating high importance. Format: objMail.Importance=2

The most common use of sending mail from a web page is having someone fill out a contact or some other form. In that case, you would wnat o have them enter their email address and message, which you could then grab from the form submission and assign in your Mail object.

Now go forth and spam not!

Thursday, October 12, 2006

Using LCase and UCase in ASP

These are pretty simple functions; nevertheless, in my traffic logs I see visitors showing up after conducting searches on how to change case in ASP... so here you go!

UCase changes everything to upper case:
will return
LCase() changes everything to lower case
will return
Here's a way to capitalize ONLY the first letter:
If you are converting to sentence case, you might want to put it in all lower case first, and then capitalize the first letter. Keep in mind that this doesn't account for proper names and other words that are normally capitalized: they will remain in lower case (supposing that's how they started out).

If you're not familiar with the Left() function I use above, here's another handy-dandy RetroWebDev post on string manipulation using Left, Right and Mid.

Wednesday, October 11, 2006

Using the Mod function in ASP to Create Dynamically Sized Tables

There's a relatively obscure function in ASP called Mod, which is short for "modular division" or "modulo" in Latin. The "modulus", or remainder, is what's left over when one number is divided by a number.

If you not as old as I am (or if you have kids right now) you might remember doing division with a remainder. So 13/6 = 2 R1, where R is the remainder (what's left over after you divide 12 by 6). Well that's what Mod is.

Syntax of the Mod function:
Number 1 mod Number 2
Here's a little loop to show you how the Mod function works to return the remainder:
For i = 1 to 10
Response.write(i & " mod 5 = " & i mod 5 & "<br>")
The results of this will look like:
1 mod 5 = 1
2 mod 5 = 2
3 mod 5 = 3
4 mod 5 = 4
5 mod 5 = 0
6 mod 5 = 1
7 mod 5 = 2
8 mod 5 = 3
9 mod 5 = 4
10 mod 5 = 0
Let's break down some of them:
1 mod 5 = 1 / 5 = 0 with a remainder of 1
2 mod 5 = 1 / 5 = 0 with a remainder of 2
6 mod 5 = 1 / 5 = 1 with a remainder of 1

In the commercial world, many advanced encryption techniques, including the world-standard RSA Encryption Algorithm, use the mod function as part of their internal functioning.

But what use is Mod to you?

The RetroWebDev post <a href=”http://retrowebdev.blogspot.com/2006/08/alternating-row-colors.html”>Alternating Row Colors</a> is a solution that makes use of Mod.

With a more advanced script, you can use Mod to create dynamically sized tables.

Say you want a table with 3 cells in each row, and there are 9 items to be displayed. Three rows of three and you're done. But suppose there are 10 items. To keep the table well-formed, you need to create three rows of three, then an additional row with one cell containing the 10th item, then two empty cells and a close row tag. Now what if you want to give the user the option of showing 3, 4, or 5 items per row? Mod to the rescue.

Here's a function that will produce a well-formed table based on your input of intCells and intItems. Simply pass in the values you want for number of cells per row and the total number of items:
Function MakeTable(intCells, intItems)

strHTML = "<table cellpadding=2 cellspacing=0>"

'Loop through the items
For i=1 to intItems
' start of new row?
If i mod intCells=1 Then strHTML = strHTML & "<tr>"

' Add a cell
strHTML = strHTML & "<td>" & i & "</td>"

' end of row?
If i mod intCells=0 Then strHTML = strHTML & "</tr>"

'if end of row, fill remainder with empty cells
If intItems mod intCells > 0 Then
' loop to complete table
For j=1 to intCells-(intItems mod intCells)
' add empty cell
strHTML = strHTML & "<td> </td>"

' close row if last cell
If j=intCells-(intItems mod intCells) Then strHTML = strHTML & "</tr>"
End if

' close table
strHTML = strHTML & "</table>"

' assign strHTML to the function
MakeTable = strHTML
End Function
Calling the function:
Call MakeTable(3,9)
creates a table with 3 cells per row and 9 total items.
Call MakeTable(5,21)
creates a table with 5 cells per row and 21 total items (4 rows of 5 and 1 row of 1 with 4 empties).

While you might not be in the cryptography business, if you create shopping carts, online stores, photo albums, calendars, etc., anything that might need the flexibility of tables with variable numbers of items and/or items per row, Mod is a great tool to be familiar with.

Tuesday, October 10, 2006

Server.Transfer versus Response.Redirect in ASP

When sending a user to another page, most programmers in ASP use Response.Redirect. Response.Redirect sends a message to the browser, telling it to go to another page:
Server.Transfer is similar in that it sends a user to another page, but it has some distinct advantages and disadvantages.

First, the big drawback of Server.Transfer is that it can only send users to a page running on that server. You can't use Server.Transfer to send a user to an external site. Only Response.Redirect can do that.

Transferring to another page using Server.Transfer conservers server resources. The transfer takes place on the server instead of forcing the browser to redirect to a new page. This means fewer HTTP requests coming through and can make your applications run more efficiently.

Server.Transfer maintains the the original URL in the browser.

Server.Transfer has a second parameter — "preserveForm". If you set this to True, using a statement such as Server.Transfer("WebForm2.aspx", True), the existing query string and any form variables will still be available to the page you are transferring to. This technique is great for wizard-style input forms split over multiple pages.

Don't confuse Server.Transfer with Server.Execute, which executes the page and returns the results.

When the Server.Transfer method is called, execution of the first page is terminated and execution of the second page begins. If the first page has started writing to the response buffer, the second page appends to the buffer instead of replacing it. If buffering is on, then HTTP headers can be modified by the ASP file that it is transferred to. If buffering is off, the HTTP headers are not modifiable by the ASP file that it is transferred to, unless no content has been sent by ASP yet. Additionally, multiple transfers can be called in succession, thereby chaining pages together.

The only data transferred to a second ASP page are the ASP built-in objects and the ASP Error object values from the first request. Any variables declared by the first ASP page are not available in the second ASP page.

Server.Transfer has several advantages over Response.Redirect:
  • Because it saves a round trip between the server and the browser it's faster and reduces the load on the Web server.
  • The Response querystring and form collections are preserved during the transfer. As a result, you don't need to worry about reposting form and querystring data to the new page.
However, Server.Transfer does have a few disadvantages:
  • You can only use Server.Transfer to redirect to a page on the same Web server.
  • You can't pass a querystring to the new page. (However, remember that the querystring passed to the page executing the transfer will automatically be passed along to the new page.) If you try to pass a querystring to the new page, you will trigger an ASP error.
  • The browser is never notified of the new page, which can cause problems with relative links in some cases.
Caution! The last point is more important than you think! I've found that this last point can be a show-stopper for using Server.Transfer. If you use Server.Transfer to transfer execution to page in a different folder, all of your relative links will break. This includes any relative links to images, anchor tags, or style sheets on the page.

Monday, October 09, 2006

Geek Babe Monday - Xenia Seeberg

Smart and hot!

Xenia Seeberg (born Anke Wesenberg on April 4, 1972 in Geldern , Germany) is a German film and television actress. She is perhaps best known for her role as Xev Bellringer in the science fiction television series LEXX.
Xenia Seeberg from LexxXenia Seeberg
Seeberg is 5ft 8in tall and speaks German, English, and French; and has degrees in Latin and philosophy. She attended theater school of Lee Strasberg in New York.

Improving ASP Performance Tip #1

Assign opbject variables to local variables.

Reading from the object variable is slower than reading from the local variable. So if you're going to be using the object variable frequently, store it in a local variable and access it that way.

If Object.Value = 0 then
Do something
elseif Object.Value > 0 then
Do something
elseif Object.Value
Dim vObject

vObject = Object.Value

if vObject = 0 then
Do something
elseif vObject > 0 then
Do something
elseif vObject <> etc...

Friday, October 06, 2006

Geek's Approach to working out Q&A

My post A Geek's Approach to Working Out generated some questions:

Q: Forty-one! That's pretty old....
A: You'll be there soon enough, if you're lucky.

Q: I don't believe you can total more than 1,000 lbs doing this workout
A: Meet in my local gym. For every pound over 1,000 I do, you pay me $5, for every pound under, I'll pay you $20.

Q: 15 reps sounds like too many. I always heard you need to do heavy weights and low reps to get bigger
A: You can certainly get bigger doing heavy weights and low reps, but no matter what weight or reps you're doing, you won't get bigger if you don't increase your tonnage (and as a result the amount of work your muscles are doing). You can't keep doing the same weight and same number of reps every workout if you want to get bigger and stronger.

And I offer this: find someone who can squat 150 pounds 15 times and find someone who can squat 250 pounds 15 times and see whose legs are bigger.

The whole key to getting bigger and stronger through resistance training is progression. To get bigger and/or stronger, you either need to:
  • keep adding weight
  • keep adding reps
  • reduce workout time
    With the goal being to increase your tonnage (the amount of weight you move). If you can both increase your tonnage and increase intensity (pounds moved per second) so much the better.

    Q: How can you get a good workout in only 20 minutes?
    A: How quickly you move the tonnage is the measure of intensity. You can increase your intensity without increasing weight or reps by doing your workout faster. Ultimately, you'll need to experiment to find the best combination of reps, weight, and intensity (pounds per second) for yourself.

    One of the best things you can do if you're serious about making gains is to keep a log. A log will let you see your progress as well as keep you on track. You can get a little notebook or do what I do and use a workout spreadsheet.
  • Passing Values out of a Subroutine in ASP

    It's a known fact that most programmers (and most people in general) are lazy. In ASP, declaring variables is optional, so most programmers don't. I've gotten away from that and tend to do Option Explicit at the top of my page and then declare all my variables
    Option Explicit

    Dim Var1, Var2, Var3
    I've found it makes it easier for me to debug my code.

    If you do declare your variables, do it first thing at the top of the page for your global variables. If you use function or subroutine variables, you can declare those inside the subroutine of function in which you use them.

    The main advantage of declaring variables is that it makes it easier to debug your code, because if you misspell a variable it will show up as undeclared. Declaring your variables has an added effect, usually unknown to beginning programmers.

    Say you have a subroutine the figures out the values of something:
    Sub DoSomething
    x = 1
    y = 2
    z = x + y
    End Sub
    Now you would think the value of z would be accessible to the rest of the page, but it won't unless you've declared it as a global variable outside the subroutine. So if you try this:
    Call DoSomething
    You won't see anything, because the value of z won't come out of the subroutine. You have to do it like this:
    Dim z

    Call DoSomething
    In this example, since z has been declared as a global variable, it will persist out of the function and be accessible to the rest of you code.

    I remember practically pulling my hair out the first time I used a subroutine to concatenate a string and then couldn't get the string to print!

    There is another way to accomplish this without using a script level Dim statement; you can declare the subroutine as Public.
    Public Sub DoSomething
    x = 1
    y = 2
    z = x + y
    End Sub
    So here are the rules summed up:
    • Variables in Private subroutines and functions are available only to that function or subroutine
    • Variables in Public subroutines and functions are available to the entire script
    • Variables declared at the script level are available to the entire script
    • Variables declared at the subroutein or function level are available only within that subroutine or function

    Thursday, October 05, 2006

    A Geek's Approach to Working Out

    Not being your typical geek (at least in my commitment to fitness and avoidance of Mountain Dew), I've been working out for more than 20 years. I'm no no power lifter, but even now, at the age of 41 and a bodyweight around 195 (6 feet tall), I can still exceed a 1,000 pound total on the three big lifts: squat, bench press, and dead lift.

    Over the years, my training has changed as I've learned new things and grown older. I take a much more cerebral approach to training now than I did when I was in my 20s and early 30s, where my main lifting philosophy was high weight, low reps, every set to failure and never go down. This type of max effort training eventually takes its toll, especially on joints like the elbows and shoulders and the lower back as well.

    As my strength gains trickled to a halt in my late 30s, I began exploring alternate ways of training and have come up with a good system that seems to work, in that I've made some very good progress using it over the last 8 months. It's more of a high intensity training approach, as opposed to the volume training I used to do (and the one most weight lifters still do).

    If you're a regular weight lifter, you probably do multiple exercises per body part, multiple sets per exercise, and reps in the range of 4 - 10. Typical weekly schedules for someone doing such a workout might be 4, 5 or 6 days a week, along the lines of:

    4 day
    Mon, Thurs:Chest, shoulders, triceps
    Tues, Fri:Legs, back, biceps

    5 day
    Mon, Thurs:Chest, triceps
    Wed:legs, shoulders
    Tues, Fri:back, biceps

    6 Day
    Mon, Thurs:Chest, triceps
    Tues, Fri:back, biceps
    Wed, Sat:legs, shoulders

    These volume workouts usually include doing 3-5 different exercises for each bodypart, 3-5 sets per exercise, and 4-10 reps per set, usually with the weight increasing each set. There's nothing wrong with such a workout - I did a workout much like this for almost two decades. Everyone can make good gains lifting this way, though you might often find yourself hitting a plateau now and then and needing to do something to break through. Varying the exercises you do each time, along with the amount of weight and the numbers of reps, is a good way to keep this routine from going stale.

    Since this type of routine didn't seem to be working for me that well, I decided to try something new. After much online research and experimentation, I came up with a routine that has resulted in good gains in size and strength over the last 8 months (bodyweight from 188 to 195 and all poudages heavier). It's based on several high intensity workout (HIT) methods, which you can read more about online if you've any desire to research it.

    To determine the intesity of my training (how much work I am doing), I calculate a pounds per second. Lets look at that in a volume workout. I'm going to use a few assumptions for the ease of calculation; YMMV:

    Time to complete 1 rep: 5 seconds
    Time between sets: 120 seconds
    Time between exercises: 180 seconds

    Here's some of the formulas I'm using:
    RepTime = Number of Reps * Number of Seconds to perform each Rep
    Set Rest Time = (Number of Sets - Number of Exercises) * Seconds of Rest Between Sets
    Exercise Rest Time = (Number of Exercises -1) * Seconds of Rest Between Exercises

    Tonnage is calculated on a per set basis:
    Tonnage = Reps x Weight

    I use Pounds per Second as representing 'intensity' of the workout:
    Pounds per Second = Total Tonnage/Total Time

    Now let's take a typical volume chest workout. Substitute your poundages for the ones below if you want to see how your workout breaks down. The time under each exercise include rest time between sets ((Number of Sets - 1)*120):

  • Bench Press: 135x10, 155x8, 185x6, 205x5
  • Time: 500 seconds; tonnage: 4520 pounds

  • Incline Press: 135x8, 135x8, 155x6, 175x4
  • Time: 490 seconds; tonnage: 3790 pounds

  • Decline Dumbell Press: 70x8, 70x6, 70x5
  • Time: 335 seconds; tonnage: 1330 pounds

  • Dumbell Flys: 45x8, 45x8, 45x6
  • Time: 350 seconds; tonnage: 990 pounds

  • Rest between exercises: 540 seconds
  • Total time: 1675 seconds
  • Total Tonnage: 10630 pounds
  • Pounds per second = Total Tonnage / Total Time = 6.35

    After chest, if you were doing the 4 day routine, you'd still have shoulders and triceps to do.

    I've included a spreadsheet breakdown of a full body workout done over two days. Change the weight used to see how your workout stacks up. Here's the final rollup for the Monday and Tuesday workouts of the 4 day a week routine listed above:
  • Total time: 13620 (3 hours 45 minutes)
  • Total tonnage: 53640
  • Pounds per second: 3.94

    With my new workout, I elminated almost all the isolation exercises and have gone to doing the full body three times a week (Mon, Wed, Fri). Each exercise is done for 1 set of 15 reps, with only 2 minutes of rest between exercises (keeping the assumed 5 seconds per rep). Here it is with the poundages I used on October 2, 2006:

    Mon, Wed, Fri
  • Squat: 205x15 - 75 seconds, 3075 pounds
  • Leg Curl: 130x15 - 75 seconds, 1950 pounds
  • Dumbell Press: 80x13 - 65 seconds, 1040 pounds
  • Lat Pulls: 160x15 - 75 seconds, 2400 pounds
  • Military Press: 105x15 - 75 seconds, 1575 pounds
  • Triceps Extensions: 100x15 - 75 seconds, 1500 pounds
  • Dumbell Curl: 40x12 - 60 seconds, 480 pounds

  • Total time: 1100 seconds (18mins 20secs)
  • Total tonnage: 12020
  • Pounds per second: 10.93

    Comparing the pounds per second here with that of the volume workout, we see that this routine moves almost 3x as much weight per second. Time taken to complete a full body workout has gone from 4 hours to just under 20 minutes (not including warmup and stretching). If you think this workout is for sissies, I challenge you to give it a try. Make sure you bring a barf bag the first few times!

    I realize a lot of traditional lifters will look at this and scoff, thinking that there's not enough work being done. Although overall exercises, sets, and tonnage is lower, there is actually more work being done per second of this workout - almost 4 times as much work.

    By cutting out isolation exercises and focusing on compound, multiple joint movements, we can get a full body, high intensity workout done in 20 minutes. I know a lot of you lifters enjoy those small isolation movements, but they really aren't necessary to a workout program with the goal of increasing OVERALL strength and fitness. If you're a bodybuilder, you might need to do isolation movements to bring out details, but for someone who simply wants to get stronger, bigger, and look better, basic, core strength movements are best. If you really want to put a little emphasis on a muscle group, add it in at the end as I've done with biceps and triceps.

    • Don't be a wuss! Go all the way doen on squats. Don't listen to whiners who say you'll injure your knees; that's BS. Knees are made to bend - deep squats wil make them stronger, not weaker.
    • Vary the exercises. For legs you might do squats on Monday, Leg Press on Wednesday, and Deadlifts on Friday. For chest you might do Flat Bench, Incline Bench, Dumbell press. For back maybe Close Grip pulls, Wide Grip Pulls, Seated rows.
    • Warm up! I do 20 minutes slow jog on a treadmill (5 miles per hour) at the start of every workout
    • Stretch! After the treadmill, I do 10 minutes stretching
    • Keep up the pace - don't slack between sets
    • You can do less reps with more weight if you want, but your goal should be to do no less than 10.
    • I do cardio 3x a week on my off days, jogging about 2.5 miles on Tues, Thurs and Sat or Sun
    Here's a spreadsheet of my current Geek Workout.

    Explanation of exercises you might not have done and how I do others:
    1. Power clean is gripping the bar slightly wider than shoulder width with your arms hanging in front. With knees slightly bent and keeping your elbows high, pull the bar up the front of your body and then rotate your arms underneath once the bar gets to your upper chest. From that position, press the bar straight up overhead. Then lower the bar to the upper chest, rotate the arms over the top of the bar, and lower it to the starting position. Focus on keeping the movements crisp and smooth. Use just enough leg to assist in getting the bar overhead.

    2. I do dumbbell curls seated and alternating arms, starting with my left (weaker) arm

    3. Narrow lat pulls are either gripping the bar underhanded with your hands close together, or using a v-bar. Hands should be no more than 6 inches apart.

    4. I do shrugs gripping the bar behind the bar, not in front. Easier on my lower back.

    Keep in mind you don't get that workout body through workouts alone. Watch your diet - you don't have to be a food Nazi, but you should do your best to limit fat and sugar. Get rid of soft drinks and fast food. Snack on trail mix or almonds or mixed nuts/dried fruit. Limit red meat, eat more chicken, preferable white meat chicken. Tuna is good, but don't eat too much because of mercury content. Replace white rice with brown, white bread with whole wheat. Eat more fruits and veggies. Make sure you get enough protein. If you're going for size gains, don't overdo tha cardio and make sure you're getting sufficient calories.

    It all might seeem overwhelming at first, but if you can get it going and stick with it for a few weeks, it will become habit and you'll soon be reaping the benefits.
  • Wednesday, October 04, 2006

    JavaScript Back Button or Link

    How do I make a back button or link?

    This is a pretty common (and basic) question with an easy solution. Note that it requires you visitor have JavaScript enabled, but that covers about 96% or more of web surfers.

    Link methods:
    <a href="javascript:history.go(-1);">back</a>
    <a href="#" onClick="javascript:history.go(-1);">back</a>
    <a href="javascript:;" onClick="javascript:history.go(-1)">back</a>
    Button method:
    <input type="button" value="Go Back" onClick="javascript:history.go(-1);">
    <img src="GoBackImage.jpg" onClick="javascript:history.go(-1);">
    You can change how many pages you sent the use back by changing the value in the parentheses; (-2) will send them back 2 pages.

    Tuesday, October 03, 2006

    Using the VBScript Replace() Function in ASP

    Ever wanted to search a string to find a word or phrase and replace it with a different word or phrase? ASP in VBScript provides an extremely useful and easy to use function - Replace() - that can be used replace all occurrences of a particular substring with a replacement substring.

    Here's the format:
    Replace(String, Find, ReplaceWith[, start[, count[, compare]]])
    String is the original string

    Find is the substring you are searching for

    ReplaceWith is what you want to replace the substring with.

    Find and replaceWith are the only required parameters.

    There are some optional parameters as well:
    start is the position in the original string where you want to start your seach from (default is 1)

    count is the number of occurances you want to replace (default is -1, which means all occurances)

    compare determines the mode to use when doing the comparison. vbBinaryCompare is case sensitive, vbTextCompare is not. By default, it is set to vbBinaryCompare

    The compare variable is worth looking at more in-depth. Example:
    Replace("quick brown fox", "Fox", "Dog")
    If you execute this, the result with be "quick brown fox". The replace won't happen because by using the default, vbBinaryCompare, "Fox" does not equal "fox": the case of the 'f' is different.

    If you want the replace to be case insensitive, you have to execute it as:
    Replace("quick brown fox", "Fox", "Dog", vbTextCompare)
    In this example, the result will be "quick brown Dog". It will ignore case when searching for "fox" and will replace it with the substring you specified, in this case "Dog" with a capital "D".

    Another way to do this is to use LCase() to make the string all lower case:
    Replace(LCase("quick brown FOX"), "fox", "DOG")
    The result here would be "quick brown DOG".

    Replace() is very useful for manipulating strings, but if you don't know how to set your case sensitivity, it can be frustrating!

    Monday, October 02, 2006

    Geek Babe Monday - Claudia Black

    Claudia Black portrayed Aeryn Sun on the SciFi series FarScape. She also showed up in Stargate SG-1 starting in 2006 as Vala Mal Doran
    Claudia Black FarScapeClaudia Black SG-1
    Claudia Black
    Claudia Black was born on October 11, 1972 (because she is very secretive about her personal life, her actual year of birth is still not officially certain), in Sydney, Australia. She has lived most of her adult life abroad, opting to reside in New Zealand and London, England, for extended periods of time.

    As an accomplished stage actress, Claudia has starred in many roles with various stage productions, as well as with the Belvoir Street Theatre, a renowned Australian acting troupe. In 1990, Claudia's turn as Portia in Shakespeare's The Merchant of Venice earned her a nomination in the Globe Shakespeare Competition; she made it to the finals.

    The bulk of her early onscreen career took place in Australian television productions. Early appearances include bit parts in G.P. (1993), Police Rescue (1993) and the miniseries Seven Deadly Sins (1993). She achieved notoriety in Australia by the mid-1990s, thanks to roles in A Country Practice (1994) and City Life (1996).

    Using Request.ServerVariables in ASP

    When a visitor requests a web page on your site, IIS gathers information from both the client computer and the server. This information is stored in a collection known as the Request.ServerVariables collection. ASP code has access to the collection, the information of which can be handy.

    With the ServerVariables, you can get the visitor's browser information, the referring URL, the visitor's IP address, the URL being fetched, and a bunch of other information.

    Here's a list of some of the more commonly used ones:

    • HTTP_USER_AGENT - the browser the visitor is using
    • LOGON_USER The Windows NT account that the user is logged into.
    • PATH_INFO Extra path information as given by the client. You can access scripts by using their virtual path and the PATH_INFO server variable. If this information comes from a URL it is decoded by the server before it is passed to the CGI script.
    • QUERY_STRING Query information stored in the string following the question mark (?) in the HTTP request.
    • REMOTE_ADDR - The IP address of the remote host making the request.
    • REMOTE_HOST - The name of the host making the request. If the server does not have this information, it will set REMOTE_ADDR and leave this empty.
    • SCRIPT_NAME - A virtual path to the script being executed. This is used for self-referencing URLs.
    • SERVER_NAME - The server's host name, DNS alias, or IP address as it would appear in self-referencing URLs.
    • URL - Gives the base portion of the URL.
    Here's a script you can run on an active server page to see the entire Request.Servervariables collection:
    For Each name In Request.ServerVariables 
    response.write(name&": ")
    On a presonal note, here's some of the things I've done using Request.Servervariable info:

  • Filter content by User Agent or IP
  • Ban based on IP
  • Ban bad bots based on User Agent
  • Build URL's based on Script or Server Name
  • Track access by IP

    Here's a cool app built around Request.Servervariables: a dynamic content tree to help your users navigate around your site.