Any one who has used a spreadsheet (usually Microsoft Excel) is familiar with the idea of Macros. These are simple scripts that can automate basic tasks to free up more time in your day for Facebook. And, most people who use Google Spreadsheets haven’t gotten round to figuring out the Google Apps equivalent of Macros, Apps Script. Apps Script is based on Javascript, so if you have had any experience with Javascript then you will be fine. However, if you have not (as I have not) then you are lucky as I have done the hard yards for you. However, if my wisdom is not enough then there is extensive help and examples on line.

What we’re going to do with this very simple tutorial is to walk through some basic data manipulation and send some TXT messages from your spreadsheet.
The full script code and a copy of the spreadsheet are at the end of this article so if you are not a geek or, you have a life or are just lazy then hit the page down button til you get to the bottom or click here to preview the spreadsheet and use the template. Finally you will be able to send a SMS message to the numbers listed in your spreadsheet. If you don’t feel like working this through, the complete version is contained in this spreadsheet and accompanying code.

First up you’ll want to create a spreadsheet. Head on over to your Google Drive and create one.

Click the red CREATE button and choose Spreadsheet from the list of offerings. Once you have created your Spreadsheet, name it and then open the Script Editor.

Welcome to the Script Editor

The Script Editor is in the Tools menu

Script Editor is sparse yet powerful, quiet yet wise, confusing yet enigmatic. Basically, it will probably drive you crazy if you let it but once you crack the code it will be your BFF.

Once into the Script Editor we can start to create. With every Script you need a way for the user to interact with it, this is called the User Interface (UI). For this example we’re going to add a “Bulletin.net” Menu to the Spreadsheet and a Menu Item called “Send SMS” that will run our Script. To do this we need to write our first piece of Apps Script, a Function called onOpen.

[cc lang="javascript" escaped="true" width="580px" line_numbers="on"]

function onOpen() {

var sheet = SpreadsheetApp.getActiveSpreadsheet();
var entries = [{
name : "Send SMS",
functionName : "sendSMS"
}];
sheet.addMenu(“Bulletin.net”, entries);
};

[/cc]

There are a couple of Functions in Apps Script that need a specific name and onOpen is one of them; it is executed every time the Spreadsheet is opened. So if you change the name of our function from onOpen to something else, your menu won’t appear in the Spreadsheet. You can change what’s in quotation marks to change the name of the Menu (Line 9), Menu Item (Line 5) and the name of the Function executed (Line 6).

In Javascript square brackets ‘[]‘ are used to define Arrays (collections of ‘things’) and curly brackets ‘{}’ to denote Objects (‘things’ that can do ‘stuff’). The menu is therefore an Array of Objects and each Object has two Fields, name and functionName. Fields and Objects are separated by commas. Go ahead and Save your file by clicking the disc icon, then refresh your Spreadsheet. You should see your new menu added to the right of the standard menu.

Be patient because it can take a few seconds for the menu to appear.

Clicking it will have no effect because we haven’t added the sendSMS function yet. This one is a bit more complicated!

The sendSMS function

[cc lang="javascript" lines="-1" escaped="true" width="580px" line_numbers="on"]

function sendSMS() {

/**
* The FIRST PAGE of the current spreadsheet is examined for any non empty cells
* and a range is defined.
*/
var ss = SpreadsheetApp.getActiveSpreadsheet();
var dataSheet = ss.getSheets()[0];
var dataRange = dataSheet.getRange(2, 1, dataSheet.getMaxRows() – 1, 4);

/**
* The SECOND page has the settings defined
*/
var templateSheet = ss.getSheets()[1];
/**
* B1 has the message content or template
* B2 is intentionally blank
* B3 has the user ID
* B4 has the user password
*/
var msgTemplate = templateSheet.getRange(“B1″).getValue();
var serviceId = templateSheet.getRange(“B3″).getValue();
var servicePassword = templateSheet.getRange(“B4″).getValue();

// Create one JavaScript object per row of data.
objects = getRowsData(dataSheet, dataRange);

// add a results column to the source data
var resColumn = dataRange.getEndColumn() – dataRange.getColumn() + 1;
dataSheet.getRange(1,resColumn,1,1).setValue(“SMS Send Result”);

// For every row object, create a personalized message from a template and send
// it to the appropriate person.
for (var i = 0; i < objects.length; ++i) {
// Get a row object
var rowData = objects[i];

// Generate a personalized message.
// Given a template string, replace markers (for instance ${“First Name”}) with
// the corresponding value in a row object (for instance rowData.firstName).
var msgText = fillInTemplateFromObject(msgTemplate, rowData);

//Browser.msgBox(GmailApp.getAliases());
var aliases = GmailApp.getAliases();
// Build the RESTful HTTP request
var url = “https://www.bulletinmessenger.net/api/3/sms/out?”
+ “userId=” + serviceId
+ “&password=” + servicePassword
// recipient number must be in INTERNATIONAl format
+ “&to=” + rowData.number
+ “&body=” + msgText;
// Call the web service
var response = UrlFetchApp.fetch(url);

// Get the response code (200=good)
var ResponseCode = response.getResponseCode();
// write the HTTP result to the result column in the source data sheet
if (ResponseCode == 200 ) {
ResponseCode = “OK”;
}

dataSheet.getRange(i+2,resColumn,1,1).setValue(ResponseCode);

}
}

[/cc]

Let’s break it down to understand how it works.

[cc lang="javascript" escaped="true" width="580px" line_numbers="on"]

var ss = SpreadsheetApp.getActiveSpreadsheet();
var dataSheet = ss.getSheets()[0];
var dataRange = dataSheet.getRange(2, 1, dataSheet.getMaxRows() – 1, 4);

[/cc]

The first few lines grab the first Worksheet and a Range Object.  A Spreadsheet usually contains several Worksheets and in this example we have three, one for the recipient data, one for the message settings/config and the third has instructions.
For the layman, a Worksheet is the bit of the Spreadsheet with the grid of Rows and Columns, it’s where you put data.  One of the important things to remember about ranges and objects etc is that they are counted from zero (aka zero indexed) so that the first worksheet has an index of 0 (eg ss.getSheets()[0]), the second worksheet has an index of 1 (eg ss.getSheets()[1]) etc

The Range Object specifies areas of a Worksheet and lets you read/write the data contained within it. In our case we’re using a special Function in the Worksheet Object called dataSheet.getRange that returns the Range Object encompassing only the area of the first worksheet that contains data.

[cc lang="javascript" escaped="true" width="580px" line_numbers="on"]

var templateSheet = ss.getSheets()[1];
/**
* B1 has the message content or template
* B2 is intentionally blank
* B3 has the user ID
* B4 has the user password
*/
var msgTemplate = templateSheet.getRange(“B1″).getValue();
var serviceId = templateSheet.getRange(“B3″).getValue();
var servicePassword = templateSheet.getRange(“B4″).getValue();

[/cc]

This section extracts the message settings that you need to send the message via Bulletin Messenger.

The first line defines the worksheet that the settings are on.  The second line gets the value of the cell B1.  You can reference a range (getrange()) using the well known and easy to use “A1″ notation that us humans are used to, or alternatively (as above) you can define the range by location in the worksheet.  This second method is complicated so I recommend using the “A1″ notation.  In this case the message template (msgTemplate) is stored in cell B1 of the second worksheet.  Likewise your Messenger username (serviceId) and password (servicePassword) are stored in cells B3 and B4 respectively.

[cc lang="javascript" escaped="true" width="580px" line_numbers="on"]

// Create one JavaScript object per row of data.
objects = getRowsData(dataSheet, dataRange);

[/cc]

This part is deceptively simple.  the recipient data is basically stored as an array object which is easy for the script to use.

[cc lang="javascript" escaped="true" width="580px" line_numbers="on"]

// add a results column to the source data
var resColumn = dataRange.getEndColumn() – dataRange.getColumn() + 1;
dataSheet.getRange(1,resColumn,1,1).setValue(“SMS Send Result”);

[/cc]

I thought it would be nice to log the send result along side each recipient in the resColumn of the data worksheet.  The first of these two lines gets the width of the data so I do not overlap any of the data.  The second line puts a header in that column using the awkward getRange() by location function.

Now, are you ready for the heavy lifting part of the script?

[cc lang="javascript" escaped="true" width="580px" line_numbers="on"]

// For every row object, create a personalized message from a template and send
// it to the appropriate person.
for (var i = 0; i < objects.length; ++i) {

[/cc]

Doesn’t seem like much but this line is what makes scripting so powerful.  With this single line the script will iterate through each row of your data regardless of how many recipients you have in your list.

[cc lang="javascript" escaped="true" width="580px" line_numbers="on"]

// Get a row object
var rowData = objects[i];

// Generate a personalized message.
// Given a template string, replace markers (for instance ${“First Name”}) with
// the corresponding value in a row object (for instance rowData.firstName).
var msgText = fillInTemplateFromObject(msgTemplate, rowData);

//Browser.msgBox(GmailApp.getAliases());
var aliases = GmailApp.getAliases();
// Build the RESTful HTTP request
var url = “https://www.bulletinmessenger.net/api/3/sms/out?”
+ “userId=” + serviceId
+ “&password=” + servicePassword
// recipient number must be in INTERNATIONAl format
+ “&to=” + rowData.number
+ “&body=” + msgText;

[/cc]

First, get the rowData object (2).  This object contains all the information from the current row of your recipient data. rowData is an array with three elements (Columns); Number (rowData[0], Column A), Name (rowData[1], Column B) and Amount (rowData[2], Column C). All that’s required now is to assemble our message text (msgText) using the recipient data and send the SMS.

The second part (7) is a cool wee function called fillInTemplateFromObject() that we ‘pass’ the message content and the rowData.  The fillInTemplateFromObject() is explained later but basically it allows you to define parts of the message that are to be replaced with the rowData.  This is SMS merge baby!

The rest of the lines here joins all the necessary Parameters together to make a fully formed RESTful URL.  Parameters are just things you send to a function to tell it how to behave. Basically, it joins the service URL with the credentials, the message content and the recipient number so that it complies with the Messenger API (see the docs here).  You can add more to this URL such as a callbackUrl such as your email address for any responses, or a messageId for geeky street cred.

You’ll notice that “+” is used in an intuitive way here, it just adds the strings together to produce one bigger string. Notice also that the semi-colon is only on the last line to indicate that the defining of the url variable is finished.  If you put the semi colon on each line then it just wont work.

For the recipient mobile we’re using rowData[0] (Number, Column A).

During the testing of this I made extensive use of the Browser.msgBox(); function so I could see what was happening inside the script. When this line is reached the script will display whatever is in the brackets.  For example I used Browser.msgBox(url); after building the url to show me what it looked like so I could see it before it was sent to Bulletin Messenger.

Once the message is ‘put together’ we need to submit it to Bulletin Messenger.  Google makes this easy as it is just one line (2) using one method  UrlFetchApp.fetch(url).  i guild the lilly again by checking the response code to see if Bulletin Messenger was able to decyphir my message and process it.  If it was done without error then Bulletin Messenger would announce loud and clear 200!, 200!  woohoo 200! or something similar (7).  This isn’t so useful so I translate 200 to “OK” to be logged against the recipient in the source data worksheet (11).

[cc lang="javascript" escaped="true" width="580px" line_numbers="on"]

// Call the web service
var response = UrlFetchApp.fetch(url);

// Get the response code (200=good)
var ResponseCode = response.getResponseCode();
// write the HTTP result to the result column in the source data sheet
if (ResponseCode == 200 ) {
ResponseCode = “OK”;
}

dataSheet.getRange(i+2,resColumn,1,1).setValue(ResponseCode);

}

[/cc]

Before you can run this you need to add some of the ‘extra’ functions.  THEY ARE ALL NECESSARY and you can find out what each does by trial and error.  Most is just house keeping stuff, however the cool part is the fillInTemplateFromObject() function (8). I like this as it replaces any tags in your message with the appropriate value.  It makes it seem like you actually know the person you are TXTing.

[cc lang="javascript" escaped="true" width="580px" line_numbers="on"]

// Replaces markers in a template string with values define in a JavaScript data object.
// Arguments:
// – template: string containing markers, for instance ${“Column name”}
// – data: JavaScript object with values to that will replace markers. For instance
// data.columnName will replace marker ${“Column name”}
// Returns a string without markers. If no data is found to replace a marker, it is
// simply removed.
function fillInTemplateFromObject(template, data) {
var content = template;
// Search for all the variables to be replaced, for instance ${“Column name”}
var templateVars = template.match(/${“[^"]+”}/g);

if (templateVars == null ) {
content = template;
} else {
// Replace variables from the template with the actual values from the data object.
// If no value is available, replace with the empty string.
for (var i = 0; i < templateVars.length; ++i) {
// normalizeHeader ignores ${“} so we can call it directly here.
var variableData = data[normalizeHeader(templateVars[i])];
content = content.replace(templateVars[i], variableData || “”);
}
}
return content;
}

//////////////////////////////////////////////////////////////////////////////////////////
//
// The code below is reused from the ‘Reading Spreadsheet data using JavaScript Objects’
// tutorial.
//
//////////////////////////////////////////////////////////////////////////////////////////

// getRowsData iterates row by row in the input range and returns an array of objects.
// Each object contains all the data for a given row, indexed by its normalized column name.
// Arguments:
// – sheet: the sheet object that contains the data to be processed
// – range: the exact range of cells where the data is stored
// – columnHeadersRowIndex: specifies the row number where the column names are stored.
// This argument is optional and it defaults to the row immediately above range;
// Returns an Array of objects.
function getRowsData(sheet, range, columnHeadersRowIndex) {
columnHeadersRowIndex = columnHeadersRowIndex || range.getRowIndex() – 1;
var numColumns = range.getEndColumn() – range.getColumn() + 1;
//sendSMS
var headersRange = sheet.getRange(columnHeadersRowIndex, range.getColumn(), 1, numColumns);
var headers = headersRange.getValues()[0];
return getObjects(range.getValues(), normalizeHeaders(headers));
}

// For every row of data in data, generates an object that contains the data. Names of
// object fields are defined in keys.
// Arguments:
// – data: JavaScript 2d array
// – keys: Array of Strings that define the property names for the objects to create
function getObjects(data, keys) {
var objects = [];
for (var i = 0; i < data.length; ++i) {
var object = {};
var hasData = false;
for (var j = 0; j < data[i].length; ++j) {
var cellData = data[i][j];
if (isCellEmpty(cellData)) {
continue;
}
object[keys[j]] = cellData;
hasData = true;
}
if (hasData) {
objects.push(object);
}
}
return objects;
}

// Returns an Array of normalized Strings.
// Arguments:
// – headers: Array of Strings to normalize
function normalizeHeaders(headers) {
var keys = [];
for (var i = 0; i < headers.length; ++i) {
var key = normalizeHeader(headers[i]);
if (key.length > 0) {
keys.push(key);
}
}
return keys;
}

// Normalizes a string, by removing all alphanumeric characters and using mixed case
// to separate words. The output will always start with a lower case letter.
// This function is designed to produce JavaScript object property names.
// Arguments:
// – header: string to normalize
// Examples:
// “First Name” -> “firstName”
// “Market Cap (millions) -> “marketCapMillions
// “1 number at the beginning is ignored” -> “numberAtTheBeginningIsIgnored”
function normalizeHeader(header) {
var key = “”;
var upperCase = false;
for (var i = 0; i < header.length; ++i) {
var letter = header[i];
if (letter == ” ” && key.length > 0) {
upperCase = true;
continue;
}
if (!isAlnum(letter)) {
continue;
}
if (key.length == 0 && isDigit(letter)) {
continue; // first character must be a letter
}
if (upperCase) {
upperCase = false;
key += letter.toUpperCase();
} else {
key += letter.toLowerCase();
}
}
return key;
}

// Returns true if the cell where cellData was read from is empty.
// Arguments:
// – cellData: string
function isCellEmpty(cellData) {
return typeof(cellData) == “string” && cellData == “”;
}

// Returns true if the character char is alphabetical, false otherwise.
function isAlnum(char) {
return char >= ‘A’ && char <= ‘Z’ ||
char >= ‘a’ && char <= ‘z’ ||
isDigit(char);
}

// Returns true if the character char is a digit, false otherwise.
function isDigit(char) {
return char >= ’0′ && char <= ’9′;
}

[/cc]

When you write your message you can use the column name as a tag. You need to be careful about writing this tag as it is a geeky format that is more easily understood by your script than by your mom and dad.  Each tag/column should be in the format ${“columnHeader”}, eg ${“Number”}, ${“Name”} or ${“Amount”} in our sample spreadsheet.

Once you’ve added this extra code code, save it and go ahead and click the Send SMS menu item. The first time you do this you will probably be asked to grant permissions by a dialog box like the one below. It will ask for read/write permissions to your  Spreadsheets and to Gmail (even though Gmail is not used), which in this case is fine so you should grant those permissions. Every time you change the code, you’ll need to re-grant these permissions, it’s annoying when developing but once you’ve released your script to users they should only have to do it infrequently. You should always make sure you and your users understand these dialogs before granting the permissions.

Okay, we are about done.  You need to add your recipient numbers to the first sheet and then send the message. The only thing I think you really need to know at this point is that all the numbers must be in international format.  That is, if they are in the US then the numbers must sart with a 1.  If they are in the UK then the numbers must start with a 44.  If your message does not get delivered then there is a 110% chance that you stuffed up the numbers so please check that you are using international format.

Now you know how to create a Spreadsheet, Open the Script Editor, Add a Menu, Access Worksheet Data and call the Bulletin Messenger API to send a bunch of TXTs.  I have tried to show the most basic way of doing things as this was my first time with the Google Apps Script and it was ‘interesting’.  To save you a lot of heart ache and to reward you for reading this far you can pick up where I left off as I have saved the spreadsheet as a template which you can (and should) use.  All the code is done, all you need to do is copy your database into page 1 and update the message content, user ID and password on page 2.  If you have not done so already you can get a free account online today.

Remember, once you open the template it will take a few moments for the”Bulletin.net” menu to appear in your new spreadsheet.  You will also be prompted with the security warning and we recommend you read it carefully!

The entire code is below.  Thanks and enjoy!

[cc lang="javascript" escaped="true" width="580px" line_numbers="on"]

/**
* Adds a custom menu to the active spreadsheet, containing a single menu item
* for invoking the sendSMS() function.
* The onOpen() function, when defined, is automatically invoked whenever the
* spreadsheet is opened.
* For more information on using the Spreadsheet API, see
* https://developers.google.com/apps-script/service_spreadsheet
*/
function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var entries = [{
name : "Send SMS",
functionName : "sendSMS"
}];
sheet.addMenu(“Bulletin.net”, entries);
};
/**
* Core of the code
*/
function sendSMS() {
/**
* The FIRST PAGE of the current spreadsheet is examined for any non empty cells
* and a range is defined.
*/
var ss = SpreadsheetApp.getActiveSpreadsheet();
var dataSheet = ss.getSheets()[0];
var dataRange = dataSheet.getRange(2, 1, dataSheet.getMaxRows() – 1, 4);

/**
* The SECOND page has the settings defined
*/
var templateSheet = ss.getSheets()[1];
/**
* B1 has the message content or template
* B2 is intentionally blank
* B3 has the user ID
* B4 has the user password
*/
var msgTemplate = templateSheet.getRange(“B1″).getValue();
var serviceId = templateSheet.getRange(“B3″).getValue();
var servicePassword = templateSheet.getRange(“B4″).getValue();

// Create one JavaScript object per row of data.
objects = getRowsData(dataSheet, dataRange);

// add a results column to the source data
var resColumn = dataRange.getEndColumn() – dataRange.getColumn() + 1;
dataSheet.getRange(1,resColumn,1,1).setValue(“SMS Send Result”);

;
// For every row object, create a personalized message from a template and send
// it to the appropriate person.
for (var i = 0; i < objects.length; ++i) {
// Get a row object
var rowData = objects[i];

// Generate a personalized message.
// Given a template string, replace markers (for instance ${“First Name”}) with
// the corresponding value in a row object (for instance rowData.firstName).
var msgText = fillInTemplateFromObject(msgTemplate, rowData);

//var aliases = GmailApp.getAliases();
// Browser.msgBox(aliases);

// Build the RESTful HTTP request
var url = “https://www.bulletinmessenger.net/api/3/sms/out?”
+ “userId=” + serviceId
+ “&password=” + servicePassword
// recipient number must be in INTERNATIONAl format
+ “&to=” + rowData.number
+ “&body=” + msgText ;
// set your email address as the callback address for any replies
//+ “&callbackUrl=mailto:” + aliases[0] ;
// Call the web service
var response = UrlFetchApp.fetch(url);

// Get the response code (200=good)
var ResponseCode = response.getResponseCode();
// write the HTTP result to the result column in the source data sheet
if (ResponseCode == 200 ) {
ResponseCode = “OK”;
}

dataSheet.getRange(i+2,resColumn,1,1).setValue(ResponseCode);

}
}

// Replaces markers in a template string with values define in a JavaScript data object.
// Arguments:
// – template: string containing markers, for instance ${“Column name”}
// – data: JavaScript object with values to that will replace markers. For instance
// data.columnName will replace marker ${“Column name”}
// Returns a string without markers. If no data is found to replace a marker, it is
// simply removed.
function fillInTemplateFromObject(template, data) {
var content = template;

// Search for all the variables to be replaced, for instance ${“Column name”}
var templateVars = template.match(/${“[^"]+”}/g);

if (templateVars == null ) {
content = template;
} else {
// Replace variables from the template with the actual values from the data object.
// If no value is available, replace with the empty string.
for (var i = 0; i < templateVars.length; ++i) {
// normalizeHeader ignores ${“} so we can call it directly here.
var variableData = data[normalizeHeader(templateVars[i])];
content = content.replace(templateVars[i], variableData || “”);
}
}

return content;
}

//////////////////////////////////////////////////////////////////////////////////////////
//
// The code below is reused from the ‘Reading Spreadsheet data using JavaScript Objects’
// tutorial.
//
//////////////////////////////////////////////////////////////////////////////////////////

// getRowsData iterates row by row in the input range and returns an array of objects.
// Each object contains all the data for a given row, indexed by its normalized column name.
// Arguments:
// – sheet: the sheet object that contains the data to be processed
// – range: the exact range of cells where the data is stored
// – columnHeadersRowIndex: specifies the row number where the column names are stored.
// This argument is optional and it defaults to the row immediately above range;
// Returns an Array of objects.
function getRowsData(sheet, range, columnHeadersRowIndex) {
columnHeadersRowIndex = columnHeadersRowIndex || range.getRowIndex() – 1;
var numColumns = range.getEndColumn() – range.getColumn() + 1;
//Browser.msgBox(numColumns);
var headersRange = sheet.getRange(columnHeadersRowIndex, range.getColumn(), 1, numColumns);
var headers = headersRange.getValues()[0];
return getObjects(range.getValues(), normalizeHeaders(headers));
}

// For every row of data in data, generates an object that contains the data. Names of
// object fields are defined in keys.
// Arguments:
// – data: JavaScript 2d array
// – keys: Array of Strings that define the property names for the objects to create
function getObjects(data, keys) {
var objects = [];
for (var i = 0; i < data.length; ++i) {
var object = {};
var hasData = false;
for (var j = 0; j < data[i].length; ++j) {
var cellData = data[i][j];
if (isCellEmpty(cellData)) {
continue;
}
object[keys[j]] = cellData;
hasData = true;
}
if (hasData) {
objects.push(object);
}
}
return objects;
}

// Returns an Array of normalized Strings.
// Arguments:
// – headers: Array of Strings to normalize
function normalizeHeaders(headers) {
var keys = [];
for (var i = 0; i < headers.length; ++i) {
var key = normalizeHeader(headers[i]);
if (key.length > 0) {
keys.push(key);
}
}
return keys;
}

// Normalizes a string, by removing all alphanumeric characters and using mixed case
// to separate words. The output will always start with a lower case letter.
// This function is designed to produce JavaScript object property names.
// Arguments:
// – header: string to normalize
// Examples:
// “First Name” -> “firstName”
// “Market Cap (millions) -> “marketCapMillions
// “1 number at the beginning is ignored” -> “numberAtTheBeginningIsIgnored”
function normalizeHeader(header) {
var key = “”;
var upperCase = false;
for (var i = 0; i < header.length; ++i) {
var letter = header[i];
if (letter == ” ” && key.length > 0) {
upperCase = true;
continue;
}
if (!isAlnum(letter)) {
continue;
}
if (key.length == 0 && isDigit(letter)) {
continue; // first character must be a letter
}
if (upperCase) {
upperCase = false;
key += letter.toUpperCase();
} else {
key += letter.toLowerCase();
}
}
return key;
}

// Returns true if the cell where cellData was read from is empty.
// Arguments:
// – cellData: string
function isCellEmpty(cellData) {
return typeof(cellData) == “string” && cellData == “”;
}

// Returns true if the character char is alphabetical, false otherwise.
function isAlnum(char) {
return char >= ‘A’ && char <= ‘Z’ ||
char >= ‘a’ && char <= ‘z’ ||
isDigit(char);
}

// Returns true if the character char is a digit, false otherwise.
function isDigit(char) {
return char >= ’0′ && char <= ’9′;
}

[/cc]