Advanced AppleScript Code

AppleScript Droplet, Apple, Inc.
AppleScript Droplet, Apple, Inc. | Source

If you have been to my original site 'AppleScript for Beginners' and still can't get enough of AppleScript, this site is definitely for you. If you find that you don't follow everything that I present here or are otherwise a little rusty, you can click on the link above for a refresher.

This site is mainly dedicated to more advanced AppleScripts. For reasons of logic and because the original site was becoming rather large, some of the posts that you find here were moved from the original website. Also at this site, I will cover issues that are otherwise relevant to AppleScripting and tips relevant to the 'Mac Universe' overall.

Choose from List for Dates

Selecting a Date from a Chronological List

This script compiles a list of dates (beginning with the current date) and displays them in a 'choose from list' dialog

The resulting list can be used with FileMaker, as it is here, as part of a larger script for setting a date in an appointment book database. As you read through this, keep in mind that the calculation of dates revolves around the value stored in the variable targetDate Below this script, I give further explanation on how the script works.

tell application "FileMaker Pro"
	activate
	set saveDelimiters to AppleScript's text item delimiters
	set AppleScript's text item delimiters to ","
	set dateResult to (current date)
	set dateIncrement to 1
	set dateList to {}
	set targetDate to date string of dateResult
	set end of dateList to targetDate
	repeat 14 times
		set longTarget to (dateResult + 24 * 60 * 60 * dateIncrement)
		if dateIncrement = 14 then
			set saveIncrement to longTarget
			set targetDate to date string of longTarget
			exit repeat
		end if
		set targetDate to date string of longTarget
		set end of dateList to targetDate
		set dateIncrement to dateIncrement + 1
	end repeat
	set end of dateList to "Other Date..."
	set newAppointmentDate to (choose from list dateList with prompt "Choose a date for new appointment or select 'Other Date...' below:" default items (text item 1 of dateList) with title "Set Appointment date:" OK button name "Select") as string
	if newAppointmentDate = "Other Date..." then
		display dialog "Edit date ' " & targetDate & "' and click 'Select' or click 'More' for more date options." default answer targetDate buttons {"More", "Select"} default button 2
		set {newAppointmentDate, getMore} to the result as list
		if getMore = "More" then
			set dateIncrement to 1
			set dateList to {}
			repeat 14 times
				set longTarget to (saveIncrement + 24 * 60 * 60 * dateIncrement)
				set targetDate to date string of longTarget
				set end of dateList to targetDate
				set dateIncrement to dateIncrement + 1
			end repeat
			set newAppointmentDate to (choose from list dateList with prompt "Select a date for new appointment:" with title "Set Appointment date:" OK button name "Select") as string
		end if
	end if
	set AppleScript's text item delimiters to saveDelimiters
	set targetDate to newAppointmentDate
end tell

As stated above, the key to the date calculations for this is the variabletargetDate, which contains the value of the current date (i.e. the date string portion). This variable, then, becomes the first value in the 'choose from list' dialog.

Next, the repeat block cycles through dateIncrement times (or 14 times), using dateResult the value of the current date. This repeated incrementing gets us the additional dates that we need through this expression:

set longTarget to (dateResult + 24 * 60 * 60 * dateIncrement)

That basically explains it all. The real important part of this is the formula used:

dateResult + 24 * 60 * 60 * dateIncrement

If you wanted to calculate a date a week from now, you would replace the variable dateIncrement with the number 7, 2 weeks from now, the number 14, and so on.

Address Book, Apple, Inc.
Address Book, Apple, Inc. | Source

Create New Entry in Address Book

This is a script to create an Address Book entry entirely from a script using 'display dialog' queries. It illustrates pretty thoroughly the AppleScript syntax for the objects in Address Book.
The first part creates an entry with a first and last name and sets a variable to a reference to the new entry for use in the second part, which sets the other values for the entry:

tell application "Address Book"
	activate
	set firstName to text returned of (display dialog "Enter first name for new contact:" default answer "" with icon 1 buttons {"OK"} default button 1)
	set lastName to text returned of (display dialog "Enter last name for new contact:" default answer "" with icon 1 buttons {"OK"} default button 1)
	set theEntry to make new person with properties {first name:firstName, last name:lastName}
	set streetAddress to text returned of (display dialog "Enter street address for new contact:" default answer "" with icon 1 buttons {"OK"} default button 1)
	set cityName to text returned of (display dialog "Enter city for contact:" default answer "" with icon 1 buttons {"OK"} default button 1)
	set stateName to text returned of (display dialog "Enter state:" default answer "" with icon 1 buttons {"OK"} default button 1)
	set theZip to text returned of (display dialog "Enter zip code:" default answer "" with icon 1 buttons {"OK"} default button 1)
	set thePhone to text returned of (display dialog "Enter phone number:" default answer "" with icon 1 buttons {"OK"} default button 1)
	set theEmail to text returned of (display dialog "Enter email address (if any):" default answer "" with icon 1 buttons {"OK"} default button 1)
	set theURL to text returned of (display dialog "Enter contact's URL:" default answer "http://www." with icon 1 buttons {"OK"} default button 1)
	tell theEntry
		make new address at end of addresses with properties {label:"Home", street:streetAddress, city:cityName, state:stateName, zip:theZip}
		(make new phone at end of phones with properties {label:"Home", value:thePhone}) make new email at end of emails with properties {label:"Home", value:theEmail}
		make new url at end of urls with properties {label:"Work", value:theURL}
	end tell
	save
end tell

A few notes on the script above:

This script line creates the entry, sets it's name and creates a variable reference to the new card:

set theEntry to make new person with properties {first name:firstName, last name:lastName}

After compiling the variables containing the address data, the next script line (just after (tell theEntry) fills in all of the address data:

	tell theEntry
		
		create new address at end of addresses with properties {label:"Home", street:streetAddress, city:cityName, state:stateName, zip:theZip}

Finally, the data is placed for the phone number, and email and website, in a similar fashion:

make new phone at end of phones with properties {label:"Home", value:thePhone}

Comments, suggestions or even bugs ? Please leave a comment below.

Converting Month of Date into a Different Format

How to Convert Month Name to its Numerical Data and Visa-Versa This can be very useful when, for instance, you have databases in which you need to display the date in a long, more user-friendly form, and in another, where you want a more condensed, short date for a concise report in tabular form that you may want to print out at a later date. I will also show you the basics of function handlers so that when you have repetitive tasks that need to be performed often, they can be called from your main scripts 'on-the-fly'.

This converts a month name to its numerical data:

set convertMonth to text returned of (display dialog "Enter a month to convert to numerical data:" default answer "" buttons {"Cancel", "Set"} default button 2)
set monthText to convertMonth
set convertMonth to (convertDate1(convertMonth))
display dialog "Numerical conversion for month of " & monthText & ": " & convertMonth with icon 1 buttons {"OK"} default button 1 giving up after 6

The function handler called by the main script (see 'set convertMonth to (convertDate1 (convertMonth))' above):

on convertDate1(theMonth)
	set monthList to {January, February, March, April, May, June, July, August, September, October, November, December}
	repeat with i from 1 to 12
		if theMonth = ((item i of monthList) as string) then
			set monthNumber to (text -2 thru -1 of ("0" & i))
			exit repeat
		end if
	end repeat
	return monthNumber
end convertDate1

This converts a month number to its actual name data:

set convertNumber to text returned of (display dialog "Enter a number from '01 to 12' to convert to month name:" default answer "01" buttons {"Cancel", "Set"} default button 2)
set numberText to (convertNumber as string)
set convertNumber to (convertDate2(convertNumber))
display dialog "Month conversion for number " & numberText & ": " & convertNumber with icon 1 buttons {"OK"} default button 1 giving up after 6

The function handler called by the main script (see "set convertNumber to (convertDate2 (convertNumber))" above):

on convertDate2(theNumber)
	set theNumber to (theNumber as text)
	if (text -2 of theNumber = "0") then set theNumber to (text -1 of theNumber)
	set numberList to {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"}
	set monthList to {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}
	repeat with i from 1 to 12
		if theNumber = (text item i of numberList) then
			set monthName to (text item i of monthList)
			exit repeat
		end if
	end repeat
	return monthName
end convertDate2

The How and Why: Coercing Record and List Data Types

When I was new to scripting, I had a lot of problems with coercing records into lists and visa-versa. It wasn't really the coercing that was so difficult, it was getting the resulting data into a useable form. In addition, I didn't see any real advantage to doing so.

Here, I will try to make clear to my readers, through a number of examples of how to coerce these data types into each other and how to transform that info into a form suitable for further manipulations. I hope that you will come away from this with a sense of the usefulness of these coercions.

Keep in mind, that where I use -- result-->...etc.., it indicates the result of execution of a script line.

Note that, due to some formatting problems, if you want to cut and paste any of this for your own use, you will have to convert the quotes from curly quotes so that Script Editor will be able to compile.

First, the statement:

set employee to {name:"Amber Clark", address:"1156 Bendelow Lane", phone:"1-456-228-4338"}
-->result{name:"Amber Clark", address:"1156 Bendelow Lane", phone:"1-456-228-4338"}

This is straightforward record syntax. Nothing earth-shattering. It essentially assigns an identifier to a given value, similar to when you assign a value to a variable.

Using this we can say:

phone of employee
set employeePhone to (phone of employee) --> result, in both cases "1-456-228-4338"

Again, nothing earth-shattering. If we want to extract the values without their corresponding identifiers we just say:

employee as list
--> result{"Amber Clark", "1156 Bendelow Lane", "1-456-228-4338

So far, we've established that we can go back and forth fairly easily and extract specific elements.

Using the 'display dialog' construct, we can set any number of records for any number of employees, i.e.: set employee1, set employee2 etc.

Take a look at this example:

set employeeName to text returned of (display dialog "Enter employee name" default answer "" with icon 1)
set employeeAddress to text returned of (display dialog "Enter employee address" default answer "" with icon 1)
set employeePhone to text returned of (display dialog "Enter employee phone number" default answer "" with icon 1)
set employee to {name:employeeName, address:employeeAddress, phone:employeePhone}
--> result returns: {name:"Amber Clark", address:"1156 Bendelow Lane", phone:"1-456-228-4338"}
--where "Amber Clark","1156 Bendelow Lane" and "1-456-228-4338" is entered

If we want to use the data for other manipulations, we must assign the desired info to a variable.

This will store a 'choose from list' selection in the variable 'employeeChoice', but if we try to use it as raw data, AppleScript will send an error that it cannot be processed in it's present form because it is still seen as a list item.

set employeeList to (employee as list)
--> result {"Amber Clark", "1156 Bendelow Lane", "1-456-228-4338"}
set employeeChoice to (choose from list employeeList with prompt "Choose from data for " & employeeName & ":")
--> result {"Amber Clark"}

However, if we end the statement with 'as string' as below, it is coerced into a form that can be used for text manipulations (in other words, without the curly quotes):

set employeeChoices to (choose from list employeeList with prompt "Choose from data for " & employeeName & ":") as string
--> result"Amber Clark"

You can easily see how this can be useful when, for instance, you want to coerce a string into an alias, or an alias into a POSIX path.

Working with Dates and Using Math Operators

An Unexpected Use of Less than and Greater than Operators One of the more curious aspects of AppleScript that inexperienced scripters are not aware of (and even more experienced scripters often overlook) is the fact that you can use the greater than [>] operator and the less than [<] operator with dates to determine, for instance, which of two given dates occurs first in the calendar year.

This, of course, contradicts everything that we did in math class at school, but it actually is a bullt-in capability of the AppleScript language.

If you run this first script in Script Editor you can see that AppleScript can understand the use of greater than and less than. This script coerces default or entered text to date format with the time appended and returns a result reflecting which time of the entered date occurs logically before the other:

set targetDate to date string of (current date)
set targetDate to text returned of (display dialog "Enter a date:" default answer targetDate buttons {"OK"} default button 1)
set dateTime1 to date (targetDate & " 1:00:00 PM")
set dateTime2 to date (targetDate & ":" & " 7:00:00 AM")
set datetext to date string of dateTime1
set time1 to time string of dateTime1
set time2 to time string of dateTime2
set dateTimeString1 to dateTime1 as string
set dateTimeString2 to dateTime2 as string
if (dateTime1 > dateTime2) then
	display dialog (datetext & return & return & time1 & " occurs after " & time2 & ".")
else if (dateTime1 < dateTime2) then
	display dialog (datetext & return & return & time2 & " occurs after " & time1 & ".")
end if

And then this example that uses just a little bit of FileMaker scripting at the beginning. It uses the 'exists' keyword to determine if the date can be found before proceeding and therefore is faster than if you tried this by using a repeat loop. Also, since the conditional pre-qualifies the show statement, there is no need for an error handler, although I include one here, because it is always a good practice, since there can always be some circumstance that you may have not anticipated. (FileMaker is in bold):

Freeze Window
Perform AppleScript [see below]

tell application "FileMaker Pro"
	activate
	tell database 1
		show every record
		sort layout 0 by {field "sortDate"} in order ascending
		--'sortDate' is a field defined as type date
		set targetRecord to (get ID of current record)
		try
			set targetCalcDate to (current date)
			set targetFound to true
			set searchDate to date string of (targetCalcDate)
			if exists (some record where searchDate is in cell "AppointmentsDate") then
				--'AppointmentsDate' is a text field that contains the long date of each record
				show (every record where searchDate is in cell "AppointmentsDate")
			else
				set targetFound to false
			end if
			if targetFound = false then display dialog "The date \"" & searchDate & "\" was not found!" with icon 0 buttons {"OK"} default button 1 giving up after 10
		on error errorMsg
			display dialog errorMsg
			show every record
			sort layout 0 by {field "sortDate"} in order ascending
			set targetRecord to (get ID of current record)
		end try
		set targetRecord to (get ID of current record)
		show every record
		sort layout 0 by {field "sortDate"} in order ascending
		go to record ID targetRecord
	end tell
end tell

Extracting Text Using Offset and Reverse vs Text Item Delimiters

Two Different Methods There are times when you want to extract part of a text string from another for some specific purpose. There are two basic methods and each has its advantages and disadvantages. We'll start with a combination of offset and reverse to remove the suffix from "seattleSunset.jpg":

set jpgFile to characters of "seattleSunset.jpg"

This gives us the characters as a list: {"s", "e", "a", "t", "t", "l", "e", "S", "u", "n", "s", "e", "t", ".", "j", "p", "g"}

set jpgFile to (reverse of jpgFile) as string
-->result: "gpj.tesnuSelttaes"

Or we can combine the statements into one:

set jpgFile to (reverse of characters of "seattleSunset.jpg") as string
-->result: "gpj.tesnuSelttaes"

Next we extract the file name without the sufffix:

set periodDelimiter to offset of "." in jpgFile
set jpgFile to text (periodDelimiter + 1) thru -1 of jpgFile
-->result: "tesnuSelttaes"

set AppleScript's text item delimiters to ""

We must reset the item delimiters to empty for this to work correctly.

set jpgFile to (reverse of characters of jpgFile) as string

After resetting the item delimiters, we use the same syntax as above.

First, remembering that what is in parentheses is performed first, jpgFile is coerced to list form and converted to the reverse order.

Then it is coerced back to a string: "seattleSunset"

If we start with set jpgFile to characters of "seattleSunset.jpeg" we still get the result: "seattleSunset"

Note that we could set the text item delimiters to "." to get the same result:

set AppleScript's text item delimiters to "."
set jpgFile to text item 1 of "seattleSunset."
-->result: "seattleSunset"

The problem with this method is that if we have something such as "http://www.scriptsforapple.com/" , the result is: "http://www", which is probably not the result that we want. The original version, however gives us"http://www.scriptsforapple" which is useful if we want to change ".com/" to ".org/":

set AppleScript's text item delimiters to "."
set theURL to "http://www.scriptsforapple.com/"
set AppleScript's text item delimiters to ""
set trimURL to (reverse of characters of theURL) as string
set periodDelimiter to offset of "." in trimURL
set trimURL to text (periodDelimiter + 1) thru -1 of trimURL
set trimURL to (reverse of characters of trimURL) as string
set theURL to trimURL & ".org/"
-->" http://www.scriptsforapple.org/"

The point here being that if you use this method, you can get the correct result for many, if not most, cases that you will encounter. That is not to say that there are not times when using text item delimiters alone will not be the right way to go depending upon the situation.

Working with Dates in AppleScript

If you have ever worked with date coercions and manipulations in AppleScript, you know how frustrating it can be, from something as simple as trying to coerce it to text so that it can be displayed in a dialog, to trying to convert it to a different date format; you have one simple thing in your syntax that keeps causing errors and you just can't figure it out!

Here, I will try to help you through some of the most common frustrations that you will encounter. First, something that I have found very useful in my specific work, a script that verifies whether or not a date is valid in the first place. It is really pretty simple, and relies on AppleScript error messaging.

The second will deal with two aspects of coercions: 1) Converting a date in textual form to date format and then 2) Determining a future date (1 week hence, 1 month hence, etc) from the given date. This is particularly useful in databases when you want to determine a future appointment for a customer, when it is supposed to be scheduled at a regular given interval.

First, validating a given date. Keep in mind that getting the current date will also include the time of day, which may not be useful for what you want to do. Run this in the Script Editor:

set dateRecord to (current date)
set defaultDate to (date string of dateRecord)
try
	set apptDate to text returned of (display dialog "Enter a date:" default answer defaultDate buttons "Set" default button 1)
	set datetext to apptDate as text
	set testDate to date string of (date apptDate) as text
	if datetext is not equal to testDate then error
	--if an invalid date is entered, the next dialog is aborted and it triggers the error alert below.
	display dialog datetext & " is a valid date." with icon 1 buttons "OK" default button 1
on error
	set alertText to "An error has occurred!"
	set messageText to quote & datetext & quote & " is an invalid date."
	display alert alertText message messageText as warning buttons "OK" default button 1 giving up after 15
	return
end try

Now the second part, which is used here in a FileMaker database and is a bit more complex, but, once you understand how it works, can be used with other types of database formats that support AppleScript.

Like the previous script, it begins by getting the current date and coercing the result to text for further manipulations. Run this in Script Editor. The result will appear in its result pane:

set AppleScript's text item delimiters to ","
set dateResult to (current date)
set comparisonDate to (date string of dateResult)
set calcBoolean to button returned of (display dialog "Determine date for next appointment?" with icon 1 buttons {"No", "Yes"} default button 2)
if calcBoolean = "Yes" then
	set AppleScript's text item delimiters to "@"

This next line would be used with FileMaker, otherwise something like the line of code that follows this line would compile just fine, in case you want to test this on your system:

set prevAppointment to "Saturday, November 7, 2009 @ 8:00 am - see Joe Palmer about specs on upcoming contract"
	set prevReference to (text item 1 of prevAppointment)
	set dateResult to date prevReference
	set scheduleInterval to (choose from list {"1 Week", "2 Weeks", "1 Month"} with prompt "Schedule interval:") as text
	if scheduleInterval = "1 Week" then
		set dateResult to (dateResult + 24 * 60 * 60 * 7)
	else if scheduleInterval = "2 Weeks" then
		set dateResult to (dateResult + 24 * 60 * 60 * 14)
	else if scheduleInterval = "1 Month" then
		set dateResult to (dateResult + 24 * 60 * 60 * 28)
	end if
	set targetDate to (date string of dateResult)
else if calcBoolean = "No" then
	set targetDate to comparisonDate
end if

Questions or comments? Please go to 'Comments, Suggestions or Bugs ?' below or contact me at: hyperscripter@gmail.com

New Drawing Document with AppleWorks 6

The Basics of Creating a Drawing Document with AppleWorks 6 are Similar to those for Creating a Text Document

The script below, appropriately named 'Graphics Hodgepodge', shows a variety of graphics objects that can be created and some of the properties that can be set with a script. There are a lot of details in this script, so we won't go into all of them. Reading the script should be explanation enough for most of what you will be likely to use:

property cyan : {0, 65534, 65534}
property yellow : {65534, 65534, 0}
property red : {65534, 0, 0}
property blue : {0, 0, 65534}
property violet : {55000, 0, 65534}
tell application "AppleWorks 6"
	make new document at front with properties {document kind:drawing document, name:"Graphics Hodgepodge"}
	tell document "Graphics Hodgepodge"
		set firstObject to (make new oval at front with properties {fill color:cyan})
		set {xleft, ytop, xright, ybottom} to bounds of firstObject
		make new rectangle at end with properties {fill color:yellow, bounds:{0, 250, 800, 500}, fill pattern:18}
		make new rounded rectangle at end with properties {fill gradient:8, bounds:{xleft + 0, ytop + 40, xright + 400, ybottom + 40}, fill color:blue}
		make new polygon at end with properties {fill color:red, fill pattern:16} with data {{xleft + 60, ytop + 60}, {xleft + 60, ytop + 160}, {xleft + 160, ytop + 160}, {xleft + 60, ytop + 60}}
		set lastOval to (make new oval at front with properties {fill color:red})
		select lastOval
		set properties of firstObject to {bounds:{xleft + 0, ytop + 40, xright + 400, ybottom + 40}}
		set properties of firstObject to {fill color:violet, fill pattern:64}
	end tell
end tell

First we use properties to store RGB info on the colors we will use (saves some typing). Next we tell AppleWorks to create a drawing document for us:

make new document at front with properties {document kind:drawing document, name:"Graphics Hodgepodge"}

In the next part, we direct statements to our new document "Graphics Hodgepodge":

set firstObject to (make new oval at front with properties {fill color:cyan})
set {xleft, ytop, xright, ybottom} to bounds of firstObject

This creates our first object, an oval, with the variables xleft, ytop, xright, ybottom for the default object dimensions that will be used later and assigns a reference to the object (also needed later) to the variable firstObject.

The rest of the script pretty much explains itself. To create a new object use the syntax: make new objectType, where objectType can be oval (used also for circle), rectangle (used also for square), rounded rectangle and polygon. Use the bounds parameter to determine the size of the object.

You use fill gradient and fill pattern with an integer reference to the gradients (there are 32) and patterns (there are 64) available from their respective palettes.

By the way, for other types of AppleWorks documents, document kind can be any of the following:

drawing document,text document,spreadsheet document,database document, painting document, presentation document

For more AppleScript with AppleWorks 6, go to: Free AppleScripts for AppleWorks 6

Universal Access Preferences: Enabling GUI Scripting

From the Apple Menu, Choose 'System Preferences...', then click on 'Universal Access'

To Enable GUI Scripting, be sure that the checkbox entitled 'Enable Access for Assistive Devices' is checked.

Apple Mail
Apple Mail | Source

Mail to Multiple Recipients with Attachment

A good start to getting acquainted with the syntax for scripting Mail. This is a script to send mail through Apple's Mail App and optionally to multiple recipients and append an attachment to the email.

Copy this script and paste it into Script Editor:

tell application "Mail"
	activate
	try
		set mailSubject to text returned of (display dialog "Subject line for new message" default answer "")
		set theMessage to make new outgoing message with properties {visible:true, subject:mailSubject, content:"Check this out !"}
		-->outgoing message id 3 of application "Mail"
		set attachFile to (choose file "Select an attachment file:" of type {"jpg", "gif", "png"})
		-->"Mac HD:Users:userAccount:Desktop:Airport-Extreme.png"
		tell theMessage
			set messageName to text returned of (display dialog "Enter a name for new message" default answer "")
			set messageRecipient to text returned of (display dialog "Enter an email address for new message" default answer "")
			if messageRecipient = "" then error
			make new to recipient at end of to recipients with properties {name:messageName, address:messageRecipient}
		end tell
		tell content of theMessage
			make new attachment with properties {file name:attachFile} at after last paragraph
			send theMessage
		end tell
	on error
		display alert "No Recipient" message "Cannot continue, no recipient was entered" as critical buttons "Abort" default button 1
		return
	end try
end tell

This is pretty straightforward and doesn't require further explanation. A few Script editor results are commented above. The Mail window looks something like this:

© 2013 AppleScripter

More by this Author

  • AppleScript and FileMaker
    4

    Learning How to Write FileMaker Pro Scripts for Beginners. Free AppleScripts for those who are new. Many scripts are a mix of AppleScript and FileMaker.

  • More Advanced AppleScript Code
    0

    For those of you who still cannot get enough AppleScript to feed your fix, some more free applescript code,Finder,Microsoft Word,Pages,AppleWorks,PowerPoint,TextEdit,iTunes,POSIX paths,database events

  • Free AppleScript Code Examples
    1

    Write AppleScript Code,free AppleScripts of display dialog,display alert,choose from list,finder,choose file,choose file name,choose folder,choose application,choose color,Finder,TextEdit


Comments, Suggestions or Bugs ?

No comments yet.

    Sign in or sign up and post using a HubPages Network account.

    0 of 8192 characters used
    Post Comment

    No HTML is allowed in comments, but URLs will be hyperlinked. Comments are not for promoting your articles or other sites.


    Click to Rate This Article
    working