Posted in ColdFusion | Posted on 04-19-2008 | 6,882 views
I've "formally" released the new version of my YouTube CFC to it's RIAForge home. This new version doesn't have a one to one relation to the older API so I've included the old code in the zip as well. Right now it supports:
- Various 'top' video feeds (most popular, etc)
- Videos by category, keyword, or both
- Videos by user
- Comments for a video
- Playlists for a user
- Videos for a playlist
And of course the big one - video upload.
The major things left to do include posting new comments and updating video information. Hopefully I can get the YouTube API Blog folks to notice.


Regardless, this is really helpful - thank you!
I'm always concerned about timeouts / problems connecting to third party services - how would getVideos() tell the calling app "sorry, I couldn't contact the youtube website"
Could (should?) you change getVideos() to return a struct - one key has the results recordset, and one key has a "statuscode" message maybe?
Then put a timeout on the cfhttp call, and try/catch it?
just a thought...
So I will add this later today.
trying the test2.cfm file in the youtubeapi1 folder and keep getting "Bad, unknown, or disabled dev_id specified."
i want to test the upload function and can't get started.
the cfc is installed and i have a valid dev key.
any advice or other documentation? where to start with uploads?
thanks!
<cfset yt = createObject("component", "assets.cfcs.youtube")>
<cfset pl = yt.getVideosByUser('marjenningstv')>
any suggestions?
FYI - upload is currently broken. I hope to have it fixed w/n a week. It turns out there is a bug in CF that only gets exposed with the YT api.
<cfinvoke component="youtube" method="init" returnvariable="yt"><cfinvokeargument name="devkey" value="#request.YouTubeDeveloperKey#"></cfinvoke>
<cfdump var="#yt.upload(video='#cffile.SERVERDIRECTORY#\#cffile.SERVERFILE#',title='Upload Test',description='Testing',categories='Education',keywords='YouTube ColdFusion')#">
Upload Result:
--------------
ErrorDetail: I/O Exception: Software caused connection abort: socket write error
Filecontent: Connection Failure
Mimetype: Unable to determine MIME type of file.
Statuscode: Connection Failure. Status code unavailable.
Long story short: You can't do the upload now- period. But you will be able to with a hotfix sometime in the (I would assume!) near future.
http://kb.adobe.com/selfservice/viewContent.do?ext...
but i get an error when trying to upload:
the error is in your cfc, trying to read an error.
can you give an example of the code needed to upload a video?
Element ERRORS.ERROR.DOMAIN.XMLTEXT is undefined in RESXML.
The error occurred in /home/mylifesp/dev_html/my-account/youtube.cfc: line 691
689 : <cfset resxml = xmlParse(result.fileContent)>
690 :
691 : <cfthrow message="YouTubeCFC Upload Error: Domain=#resxml.errors.error.domain.xmlText#, Code=#resxml.errors.error.code.xmlText#">
692 : <cfelse>
Both the Client ID and Developer Key should be provided in every API request (see Using a developer key and client ID). Each application/product should have its own unique Developer Key and Client ID.
http://code.google.com/apis/youtube/dashboard/prod...
Has it changed since the last update?
Everything was working at first. Then I started getting connection failures. I did some testing and by removing the V2 param, I got it working again.
So now the past couple of days it is no longer working on the prod server which is 7,0,2,142559 , but works fine on 8 from my home dev box.
Charset [empty string]
ErrorDetail Unknown host: gdata.youtube.com: gdata.youtube.com
Filecontent Connection Failure
Header [undefined struct element]
Mimetype Unable to determine MIME type of file.
Responseheader
struct [empty]
Statuscode Connection Failure. Status code unavailable.
Text YES
here is a test page I am using
http://justs10.com/videos/t.cfm
If anyone could help, be mucho appreciated.
Thanks,
D
<cfset yt = createObject("component", "youtube")>
<cfset yt.setDeveloperKey("AI39n2n17CzpcDAt6GMrXc8z6DA")>
<cfset yt.login("cfjedimaster", "password")>
<cfset r = yt.upload(expandPath('./actual.mov'),'Test/Upload Jack-O-Latern','Playing/with Jack-O-Latern youtube aug29','Music','testing fun')>
<cfoutput>id=#r#</cfoutput>
Everything is working just as it should with the exception of the upload. I used the example upload code you supplied (altered to my id, login and video location) and I'm getting the:
Element ERRORS.ERROR.DOMAIN.XMLTEXT is undefined in RESXML.
Any thoughts?
Thanks!
One last question does not it return rows more than 25 either try to fetch by category or keywords:
Just curious
i am just using getplaylist, not getplaylists
is there any example to that
i just used #yt.getplaylist#
and it keeps on loading. how can i know in youtube playlists
Regards
@Misty: It only returns 25 if you don't set a max attribute. You can set it to 50. Also, look at the result query. It tells you how many total items there are. With that, you can build your own pagination.
i am fetching the gettopratedvideos, when i run it, it just returns 25 results, if u can show me a viable example here, I shall be nice. i wanna get all results and show like 1 to 10 of 3773438 results:, then i can add my pagination. currently i am bit confused as there seems to me no result query in cfc which does that stuff
the error i encountered is
The web site you are accessing has experienced an unexpected error.
Please contact the website administrator.
The following information is meant for the website developer for debugging purposes.
Error Occurred While Processing Request
Element ENTRY.CONTENT.XMLTEXT is undefined in ARGUMENTS.
The error occurred in C:\inetpub\wwwroot\project2\admin\com\youtube.cfc: line 392
Called from C:\inetpub\wwwroot\project2\admin\com\youtube.cfc: line 167
Called from C:\inetpub\wwwroot\project2\admin\com\youtube.cfc: line 83
Called from C:\inetpub\wwwroot\project2\playlist.cfm: line 8
390 : <cfset s.categories = categoryList>
391 : <cfset s.title = arguments.entry.title.xmlText>
392 : <cfset s.content = arguments.entry.content.xmlText>
393 : <cfset s.author = arguments.entry.author.name.xmlText>
394 : <cfset s.authorurl = entry.author.uri.xmlText>
<cfset yt = createObject("component", "youtube")>
<cfset pl = yt.getPlaylists("PhilipDeFranco")>
<cfdump var="#pl#">
<cfif pl.recordCount>
<cfset plurl = pl.url[1]>
<cfdump var="#yt.getPlaylist(plurl)#">
</cfif>
Error i got
Element FEED.ENTRY is undefined in RESULT.
The error occurred in C:\inetpub\wwwroot\project2\admin\com\youtube.cfc: line 98
96 : <cfhttp url="#baseurl#" result="result">
97 : <cfset result = xmlParse(result.filecontent)>
98 : <cfif not arrayLen(result.feed.entry)>
99 : <cfreturn results>
100 : </cfif>
test_getplaylists.cfm and ran it but encountered above errors. if i change the users' name it shows
Element FEED.ENTRY is undefined in RESULT. error.
i have changed nothing in youtube.cfc code. i am just running it as copied from your demo folder and that's it
http://www.coldfusionjedi.com/downloads/youtubecfc....
Please download and confirm. Once you do, I will update the main project.
Please check the url again for download
Regards
404 - File or directory not found.
The resource you are looking for might have been removed, had its name changed, or is temporarily unavailable.
http://www.coldfusionjedi.com/downloads/youtube.se...
just let me know one example like gettopratedtags video or any other. it should all videos not only 25 please
while i am trying to get all related to that function gettoprated
suppose 100 topratedvideos are listed on youtube, i ran query it just returned 25. i have added pagination but it has restricted itself to 25 only, while i want the ful youtube 100 listings as on youtube. The same is the case with all queries.
Maybe i am able to clarify what exactly my point is
I am happy i am able to pinpoint my message clearly to you
Cheers
http://www.coldfusionjedi.com/downloads/youtube.se...
It contains updates to support max/start for the 'top' video type searches. Note max still has a MAX value of 100.
i mean API does not go beyong 50 records for every function
getTopratedvideos("jshjsdsd",1,50)
it retur 50 recs
if try
getTopratedvideos("jshjsdsd",1,100)
it automatically comes to 25
so i have checked it does fetch more than 50, maybe issue with youtube api fetching results
now if i use like this:
<cfset query = #yt.getVideosBySearch("song",1,50)#>
Element FEED is undefined in PACKET.
if i remove 1,50, it shows records but only 25. i think i have very hard time locating this that if i return total of 1000000. i can use it can get max of 50 in one shift and that shift also needs pagination to say 10 in a row.
question arises. when it reached end of the 50, how does it know to run th cfc again to get another. i think i am doing wrong
http://youtubecfc.riaforge.org
I've updated it there.
i am correct, but exactly i do not know how this can be done
http://www.coldfusionjedi.com/index.cfm/2006/4/24/...
If you google for ColdFusion and Pagination, you will see other examples. This is not a Youtube specific issue. Pagination can be done to any set of data, and there are many examples out there, not just the blog entry I linked to above.
i tried to make it simple by means that rather than fetching 50 first time and paginate, why not fetch 10 at a time and then paginate, but issue persists, how to fetch the next 10 after first 10.
If I'm still not reading you right... well, I hate to say I give up, but the language barrier is difficult here.
suppose there is a method which does not have start and max attributes, can i add to it/
Regards
so i tried the start and max in the url also but still no luck as:
abc.cfm?start=1&max=10&pagenumber=2
but it did not worked either way too
I really think you need to look at the blog entry I mentioned before as it _does_ explain this concept.
how i rerun the cfc again to fetch next 25 or 50 recs,
I am going my blow my balls away with a shotgun! i am too much confused
:((
_Thats_ how the CFC is run the 2nd time. The first time the user hits the page, url.start doesn't exist, so it defaults to 1, right? You determine there are more than 50 records so you build a link (again, look at the article), and now url.start is 51 and that is passed to the CFC.
<cfset perpage = 10>
<cfparam name="url.start" default="1">
<cfif not isNumeric(url.start) or url.start lt 1 or url.start gt toprated.recordCount or round(url.start) neq url.start>
<cfset url.start = 1>
<cfif StructKeyExists(URL,'time')>
<cfset tr = #yt.getTopRatedVideos("#url.time#",#url.start#,50)#>
<cfelse>
<cfset tr = #yt.getTopRatedVideos("")#>
</cfif>
</cfif>
but it does seems to work, i think i am missing one big step, i am near the end but can't find the end
now running pagination on 25 or 50 is easy and it works, how it should fetch next 50.
because pagination has toprated.recordcount which is count to every time 50 or 25, so it is possible it keeps on fetching the very next records. seems impossible to me instead
That all
http://gdata.youtube.com/feeds/api/standardfeeds/t...
it clearly indicated that it cannot go and fetch the records, max 50 allowed, so i think there is no way how it can done.
I downloaded version 6 from RIAForge early last week, I'm wondering if I have the latest version. Thanks again for the great CFC's.
Cheers,
Eric Wilkinson
Anyway, I took your changes as is and pushed it live. Download and check it out please.
I'm trying to use the "update" function of youtube.cfc. When I do, I get a 400 / Explanatioin: Bad Request error.
Here is the code that I'm using:
<cfset yt = createObject("component", "/yt/youtube")>
<cfset yt.setDeveloperKey("mykey")>
<cfset yt.login("uname", "pword")>
<cfset r = yt.update('#form.cause_name#','#form.before_description#','Music','#cause.tags#','#cause.before_video_ytid#')>
Here are the values to the above:
form.cause_name = sample cause
form.before_description = This is a test description.
cause.tags = Online, Contribution
cause.before_video_ytid = my video id displays here...
I checked the URLs and they seem to be correct, not sure what else to try. Any help is greatly appreciated!
- Anthony
<cfset yt = createObject("component", "/yt/youtube")>
<cfset yt.setDeveloperKey("mykey")>
<cfset yt.login("uname", "pword")>
<cfset r = yt.update('Test Name','This is a description','Music','Testing','videoidvalue')>
Can you maybe provide me with a sample code? I may be missing something.
Thanks again!
Thanks for being such an active and professional commentator and teacher over the years. I know I have certainly benefited from your examples and posts.
You are probably tired of talking about this CFC, but...
I am trying to use the YouTubeCFC, and like many above, can get everything working except the upload.
I think I may be missing something conceptually about the authorization process, but here is what I am trying.
I had to modify your CFC to work in openBlueDragon (ver 1.2)- basically replace all =& and also the ReMatch function in the keywords wasn't happy. For this example I am just passing a single word to avoid YT formatting issues with keywords.
<cfset yt = createObject("component", "youtube")>
<cfset yt.login("whittonr", "mypassword")>
<cfset r = yt.upload('E:\Video_Files\B\Cyprinus_carpio_Common_carp_Wide_Angle_742_S5Q5_ID~33085.m2t','Koi','Test description','Tech','Koi')>
<cfoutput>id=#r#</cfoutput>
I keep getting "YouTubeCFC Upload Error: Status: 415 / Explanation: Unsupported Media Type". I have gone and manually added the same clip to YouTube with not problem, so I do not believe that the file is bad.
The authtoken... where is that coming from? My username and password? Is that the session authorization required to then submit the uploaded file?
The DevKey - that is your specific key to go with your YouTubeCFC tool, correct? I don't need to use my Google Dev Key. correct?
Thanks in advance for your help,
Rob
DevKey - don't need to change it.
So - I'd like you to try something. I know that m2t may work for you on the public site, but the API may be more anal about what it requires. Try one of the more common types and see if it works ok.
Sorry for the delay. I just tried both an mpg and an mp4, and had the same error: YouTubeCFC Upload Error: Status: 415 / Explanation: Unsupported Media Type.
Both uploads took several minutes before failing, as both files were large - around 50mb. I then tried a smaller mp4 - 2.7MB and received the same error.
Here is the code I am using:
<cfset filename="M.grandoculis640x480.mp4">
<cfset fileLocation = "D:\Explorers_Log\webapps\log\Temp\">
<cfset yt = createObject("component", "youtube")>
<cfset yt.login("whittonr", "mypassword")>
<cfset r = yt.upload('#fileLocation##filename#','Angelfish','Test description','Tech','Shark,Reef,Whitton')>
<cfoutput>id=#r#</cfoutput>
<cfdump var="#yt.getVideosByUser('whittonr')#" top="5">
<cfabort>
Any other ideas on things I should try to narrow down the issue?
Thanks again for your help,
Rob
When ever i try and upload a video im getting this error, is this anything you have seen before?
Thanks for taking the time to read this.
Jason
Element XMLATTRIBUTES.REASONCODE is undefined in a Java object of type class coldfusion.xml.XmlNodeMap referenced as ''
The error occurred in F:\sports\webroot\youtube.cfc: line 816
Called from F:\sports\webroot\youtube.cfc: line 388
Called from F:\sports\webroot\video-view.cfm: line 150
Called from F:\sports\webroot\video-view.cfm: line 138
Called from F:\sports\webroot\video-view.cfm: line 1
814 : <cfset s.videostatus = "public">
815 : <cfif structKeyExists(arguments.entry, "app:control")>
816 : <cfset s.videostatus = arguments.entry["app:control"]["yt:state"].xmlAttributes.reasonCode>
817 : </cfif>
818 :
Jason
I am getting:
<app:control>
<app:draft>yes</app:draft>
<yt:state name='processing'/>
</app:control>
I have worked out that the problem is that once a user uploads a video I relocate them back to the video page where it displays the latest video & if it has not been processed yet then it throws up the error. I have a feeling youtube might be taking a little longer to process video than the were when I originally put the page together.
I shall check yt:state before displaying the video and get round it that way.
<cfset yt = createObject("component", "youtube")>
<cfset foo = "http://gdata.youtube.com/feeds/api/videos/#videoId...;
<cfset z = yt.getVideo(foo)>
I have used:
<cfhttp url="http://gdata.youtube.com/feeds/api/videos/#videoId...;
<cfif #cfhttp.Statuscode# contains '200' AND #cfhttp.Filecontent# DOES NOT CONTAIN "<yt:state name='processing'/>">
<cfset yt = createObject("component", "youtube")>
<cfset foo = "http://gdata.youtube.com/feeds/api/videos/#videoId...;
<cfset z = yt.getVideo(foo)>
<cfdump var="#z#">
<cfelse>
#errorMSG#
</cfif>
If you do work on a fix id be more than happy to test it.
<cfset result = result.filecontent>
<cfif result is "Invalid id">
<cfthrow message="YouTubeCFC: Invalid id">
</cfif>
to:
<cfset statuscode = result.Statuscode>
<cfset result = result.filecontent>
<cfif result is "Invalid id" OR statuscode EQ "403 Forbidden">
<cfthrow message="YouTubeCFC: Invalid id">
</cfif>
It is now throwing up the message when I pass it the ID of a invalid/deleted/duplicate video.
<cfhttp url="#arguments.myid#" result="result">
<cfset resulttext = result.filecontent>
<cfif resulttext is "Invalid id" OR result.statuscode EQ "403 Forbidden">
<cfthrow message="YouTubeCFC: Invalid id">
</cfif>
It seems like there is another bug. Please review the error below. It seems like the code is making an assumption that app:control existence will result in status attribute. If you have fixed it thats great. If you are going to explore a solution my suggestion would be to add to the conditional statement where you check for the attribute before assigning the value. I will be happy to test this for FYEGUY.com site.
Thanks for your help
Element yt:state is undefined in a Java object of type class coldfusion.xml.XmlNodeList.
The error occurred in E:\fyeguy.com\youtube2\youtubecfc\youtube.cfc: line 799
Called from E:\fyeguy.com\youtube2\youtubecfc\youtube.cfc: line 400
Called from E:\fyeguy.com\youtube2\youtubecfc\youtube.cfc: line 650
Called from E:\fyeguy.com\promotions\lolla\lookup.cfm: line 5
797 : <cfset s.videostatus = "public">
798 : <cfif structKeyExists(arguments.entry, "app:control")>
799 : <cfset s.videostatus = arguments.entry["app:control"]["yt:state"].xmlAttributes.reasonCode>
800 : </cfif>
I just saw the latest file and indeed that is what I was exploring and I can confirm that its fixed.
Thanks,
Das
<b>Element SUMMARY.XMLTEXT is undefined in ENTRY.</b>
The error occurred in youtube.cfc: line 249
247 : <cfset querySetCell(results, "updated", handleDate(entry.updated.xmlText))>
248 : <cfset querySetCell(results, "title", entry.title.xmlText)>
249 : <cfset querySetCell(results, "summary", entry.summary.xmlText)>
250 : <cfset querySetCell(results, "url", entry["gd:feedLink"].xmlAttributes.href)>
251 : <cfset querySetCell(results, "videocount", entry["gd:feedLink"].xmlAttributes.countHint)>
I just finished spending about 30 minutes looking into this and can't for the life of me figure out why the entry.summary.xmlText value is not available in the output. I dumped the entire "result" and sure enough it's not there. Interestingly, neither is the videocount.
Can anyone else duplicate this? The only way I was able to get my code working again was to comment out those two lines in the CFC, which if fine for now, but I hate when things all of the sudden break (after 1.5 years of no trouble) and I can't figure out why. Any idea? Thanks.
Anyway - it would be trivial to check for this. Do you have a reproducable case though so I can confirm it here? If your case involves NDA crap, you can send it to me directly and I'll delete when done.
here is the link to the api info:
http://code.google.com/apis/youtube/2.0/developers...
<cffunction name="deleteFromPlaylist" access="public" returnType="any" output="false" hint="I delete a video.">
<cfargument name="playlistId" type="string" required="true">
<cfargument name="videoId" type="string" required="true">
<cfset var theurl = "http://gdata.youtube.com/feeds/api/playlists/#argu...;
<cfset var result = "">
<cfset var resxml = "">
<!--- Video ID may include the URL, strip it --->
<cfset arguments.videoid = replace(arguments.videoid, "http://gdata.youtube.com/feeds/api/videos/",&...;)>
<cfset arguments.videoid = listFirst(arguments.videoid, "&")>
<cfset theurl &= arguments.videoId />
<cfhttp url="#theurl#" method="delete" result="result">
<cfhttpparam type="header" name="Host" value="gdata.youtube.com">
<cfhttpparam type="header" name="Content-Type" value="application/atom+xml">
<cfhttpparam type="header" name="Authorization" value="GoogleLogin auth=#variables.authtoken#">
<cfhttpparam type="header" name="X-GData-Client" value="youtubecfc">
<cfhttpparam type="header" name="X-GData-Key" value="key=#variables.devkey#">
</cfhttp>
<cfif result.responseheader.explanation is "OK">
<cfreturn "Video successfully removed.">
<cfelse>
<cfif isXml(result.filecontent)>
<cfset resxml = xmlParse(result.fileContent)>
<cfthrow message="YouTubeCFC Upload Error: Domain=#resxml.errors.error.domain.xmlText#, Code=#resxml.errors.error.code.xmlText#">
<cfelse>
<cfthrow message="YouTubeCFC Upload Error: Status: #result.responseheader.status_code# / Explanation: #result.responseheader.explanation#">
</cfif>
</cfif>
</cffunction>
<cffunction name="deleteFromPlaylist" access="public" returnType="any" output="false" hint="I delete a video from playlist.">
<cfargument name="playlistId" type="string" required="true">
<cfargument name="videoId" type="string" required="true">
<cfset var theurl = "http://gdata.youtube.com/feeds/api/users/#variable...;
<cfset var result = "">
<cfhttp url="#theurl#" method="delete" result="result">
<cfhttpparam type="header" name="Host" value="gdata.youtube.com">
<cfhttpparam type="header" name="Content-Type" value="application/atom+xml">
<cfhttpparam type="header" name="Authorization" value="GoogleLogin auth=#variables.authtoken#">
<cfhttpparam type="header" name="X-GData-Client" value="youtubecfc">
<cfhttpparam type="header" name="X-GData-Key" value="key=#variables.devkey#">
</cfhttp>
<cfreturn result>
</cffunction>
This is what i was using, the return i get with this is:
401 Token invalid
So i think has to do with the second part of my original question about the authtoken in the cfc, where would i get that?
<cfset yt = createObject("component", "youtube")>
<cfset yt.login("username", "password")>
<cfset dp = yt.deleteFromPlaylist('62D2AB95BFB9F362','http://gdata.youtube.com/feeds/api/playlists/62D2A...')>
<cfdump var="#dp#">
<cfset dp = yt.deleteFromPlaylist('62D2AB95BFB9F362','tEsesCpfljvXjvB_LBoDK-aBCrzoWfdG')>
So for anyone looking to do this, here is the function i added to the cfc.
<cffunction name="deleteFromPlaylist" access="public" returnType="any" output="false" hint="I delete a video.">
<cfargument name="playlistId" type="string" required="true">
<cfargument name="videoId" type="string" required="true">
<cfset var theurl = "http://gdata.youtube.com/feeds/api/playlists/#argu...;
<cfset var result = "">
<cfhttp url="#theurl#" method="delete" result="result">
<cfhttpparam type="header" name="Host" value="gdata.youtube.com">
<cfhttpparam type="header" name="Content-Type" value="application/atom+xml">
<cfhttpparam type="header" name="Authorization" value="GoogleLogin auth=#variables.authtoken#">
<cfhttpparam type="header" name="X-GData-Client" value="youtubecfc">
<cfhttpparam type="header" name="X-GData-Key" value="key=#variables.devkey#">
</cfhttp>
<cfreturn result>
</cffunction>
Ray, as always, thank you for you time and masterful knowledge. The new site template looks fantastic by the way.
<cffunction name="addPlaylist" access="public" returntype="any" output="false" hint="Adds a playlist for a user.">
<cfargument name="title" type="string" required="true">
<cfargument name="description" type="string" required="true">
<cfset var theurl = "http://gdata.youtube.com/feeds/api/users/default/p...;
<cfset var result = "">
<cfset var meta = "">
<cfset var tmpFile = expandPath("./#replace(createUUID(),'-','_','all')#")>
<cfset var resxml = "">
<cfsavecontent variable="meta">
<cfoutput>
<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:yt="http://gdata.youtube.com/schemas/2007">
<title type="text">#xmlFormat(arguments.title)#</title>
<summary>#XMLFormat(arguments.description)#</summary>
</entry>
</cfoutput>
</cfsavecontent>
<cfset meta = trim(meta)>
<cfhttp url="#theurl#" method="post" result="result">
<cfhttpparam type="header" name="Host" value="gdata.youtube.com">
<cfhttpparam type="header" name="Content-Type" value="application/atom+xml">
<cfhttpparam type="header" name="Content-Length" value="#len(meta)#">
<cfhttpparam type="header" name="Authorization" value="GoogleLogin auth=#variables.authtoken#">
<cfhttpparam type="header" name="X-GData-Client" value="youtubecfc">
<cfhttpparam type="header" name="X-GData-Key" value="key=#variables.devkey#">
<cfhttpparam type="body" value="#meta#">
</cfhttp>
<cfdump var="#result#"><cfabort>
</cffunction>
[Add Comment] [Subscribe to Comments]