Wednesday, December 2, 2009

TimeMachine Backup Then Sleep or ShutDown

With some Googling and piecing together some found scripts, I have put together these two scripts - Apps which I use very often.
  1. TimeMachine_Backup_Then_Sleep.scpt   >>   TimeMachine_Backup_Then_Sleep.app
  2. TimeMachine_Backup_Then_ShutDown.scpt   >>   TimeMachine_Backup_Then_ShutDown.app
You can save scripts as apps to be run at-will. I have no schedules, no crons, no calendar triggers.
When and only when I want to I do a TimeMachine Backup I run one of these programs at the end of the day and I head for bed. It's so nice!
I use QuickSilver, so it's a couple of keystrokes and it's running. I then dim my screen until it's black.
I like to leave the keyboard partially lit so I know if the laptop is indeed on or not.

The scripts source:
  1. do shell script "/bin/bash -c '/System/Library/CoreServices/backupd.bundle/Contents/Resources/backupd-helper > /dev/null 2>&1  &'"
    repeat
        delay 5
        if not IsProcRunning("backupd") then
            ignoring application responses
                tell application "Finder" to sleep
            end ignoring
            exit repeat
        end if
    end repeat
    on IsProcRunning(theProc)
        try
            do shell script "ps auxc | grep \"" & theProc & "\""
            return true
        on error
            return false
        end try
    end IsProcRunning

  2. do shell script "/bin/bash -c '/System/Library/CoreServices/backupd.bundle/Contents/Resources/backupd-helper > /dev/null 2>&1  &'"
    repeat
        delay 5
        if not IsProcRunning("backupd") then
            ignoring application responses
                tell application "Finder" to shut down
            end ignoring
            exit repeat
        end if
    end repeat
    on IsProcRunning(theProc)
        try
            do shell script "ps auxc | grep \"" & theProc & "\""
            return true
        on error
            return false
        end try
    end IsProcRunning

An open "Thank You!" to all you Apple-Scripters out there who have posted code to contribute to my learning. I return the favor by posting my source code for open use.

And that's a wrap!

Saturday, October 17, 2009

Long-Time-No-Blog

In my recent hiatus quite a lot has happened in life. None of which I am willing to post on the internet. Ha ha.

But I will write to announce I upgraded from Leopard to Snow. That was fun.

To all you CyberDuckies out there, you probably had a similar experience to mine. Opening files from a sub-folder no longer opened in my TextMate Project - it opened in a separate window. Upong further investigation, it appears the new beta CyberDuck no longer has true subfolders/subdirectories down in it's secret hiding place: '/private/var/folders/XX/MUMBOJUMBO-03xyz++whatever/-Tmp-/' directory. It's actually one folder with colons (:) in stead of slashes (/). Example: lets say my project was named 'widget1' and I had a subfolder for 'addons' it would actually appear as '.../-Tmp-/widget1:addons'.  This sure changed a lot for TextMate because now '.../-Tmp-/widget1:addons' is a separate folder than '.../-Tmp-/widget1:addons:images' - no more subfolders is bad news.

One up side to the new beta version of CyberDuck is that TextMate with the Projects Bundle installed can now open all CyberDuck files in the same tabbed window without opening separate windows or separate projects.

This can be done by editing the TextMate project file in TextEdit, find the line:

<string>/private/var/folders/XX/MUMBOJUMBO-03xyz++whatever/-Tmp-/some/more/folders</string>

Now, remove the some/more/folders so that it appears as:

<string>/private/var/folders/XX/MUMBOJUMBO-03xyz++whatever/-Tmp-/</string>

Now, all CyberDuck downloads will open in the same tabbed project window.


I used to like then in separate project windows, but it just got annoying on those rare cases. I just want to open files in a tabbed window and edit them.

Now I can.

Ps.  This might have been available before. I just never tried it.

Tuesday, June 30, 2009

Show Full Database Schema (mysql) via Coldfusion

A lovely gem I just invented:


DATABASE SCHEMA:

<cfquery name="gettables" datasource="#request.pmdb#">
    show tables
</cfquery>

<cfloop query="gettables">
       
    <cfquery name="getcreate" datasource="#request.pmdb#">
        show create table #gettables["#gettables.columnlist#"]#
    </cfquery>
    <br /><br />
    <cfoutput>
        <div style="font-size:16px;font-weight:bold;">#getcreate.table#</div>
        <div style="font-size:12px;">#REPLACE(getcreate["create table"],request.NL,"<br />","ALL")#</div>
    </cfoutput>

</cfloop>


Good wrap!

Sunday, June 28, 2009

Railo - MySQL - Allow Multiple Queries [allowMultiQueries=true]

This has been blogged about by a number of people in the community.


But none that I could find has done it with Railo.... Until now!

Creat a new generic 'Other - JDBC Driver' datasource, then these are the values; Railo's "CLASS" field will be "org.gjt.mm.mysql.Driver", and the "DSN" field will be "jdbc:mysql://{host}:{port}/{database}?allowMultiQueries=true".

Railo's 'CLASS' = ADOBE CF's 'Driver Class'
Railo's 'DSN' =
ADOBE CF's 'JDBC URL'
Ben Nadel has some good screenshots at the first link listed above.


You will first notice that Railo does not have a "Connection String" value for the MySQL datasource as Adobe Coldfusion provides. This was what confused me and sent me hunting and testing until I got the below solution to work successfully.


If you want to modify your existing native MySQL datasource without creating a new generic (
Other - JDBC Driver) datasource, and if your not afraid of getting deep into the Railo back-end config files, this is how to do it in 5 easy steps:


1.a. If your datasource is set up in the Railo Server Admin then navigate to your [RAILO-INSTALL-DIR]/lib/railo-server/context/railo-server.xml
1.b. If your datasource is set up in the Railo Web Admin then navigate to your [WEBSITE-ROOT]/[WEB-INF]/railo/railo-web.xml.cfm

2. Make a back-up copy of the file in case something goes wrong.

3. Open the file in a text editor and locate this xml tag:

<data-sources preserve-single-quote="yes">
(Inside this you will find a tag for each datasource.)

4. Locate the datasource you want to edit.

Find the 'dsn' value and add '?allowMultiQueries=true' to the end of the string, so it is looks somewhat like this:


<data-source allow="###" blob="false" class="org.gjt.mm.mysql.Driver" clob="false" connectionTimeout="20" custom="CharacterEncording=UTF8" database="***DATABASE***" dsn="jdbc:mysql://{host}:{port}/{database}?allowMultiQueries=true" host="***SERVER***" name="***DATASOURCE***" password="***PASSWORD***" port="3306" username="***USERNAME***"/>

5. Then restart Railo and you're in business.


You will notice a change in the Datasource Admin page after completing the above edit.

It will change from "Update datasource connection MySQL" to "Update datasource connection Other - JDBC Driver" as if you had created it it using the method which the above mentioned bloggers have outlined.


That's the wrap.

Friday, May 8, 2009

ColdFusion Start New Session - Not so hard?

So there have been issues with sessions on logout or timeout. Dealing with the issues for a long time. I can't believe it's this simple. I've never been a big fan of dealing with cookies, but that, my friend, is the answer. Take a look:

This is partly why I love ColdFusion, it takes care of all session management for you. Settings are in the ColdFusion Administrator, piece of cake. We don't even think about cookies. but depending on your CFAdmin settings it stores more or less information in those cookies that we don't have to worry about. But cookies are required for sessions, we can't get around that unless you want to take the painful route of adding your tokens in the URL of every internal link in your site. I hate it, but whatever. Back to cookies.

On logout, I and many others have resorted to this (or similar) code to end a session

<cfset StructClear(session)>

Which other have argues is not good practice. But googling the answer doesn't turn up good results.

Here is the answer:


<cfcookie name="JSESSIONID" value="deleted" expires="NOW">
<cfcookie name="CFID" value="deleted" expires="NOW">
<cfcookie name="CFTOKEN" value="deleted" expires="NOW">
And I'll explain why.

Digging into the guts of Coldfusion, the Java guts, and discovering what is actually going on in the session management is interesting and frustrating. But lets take a look:

<cfset variables.tracker = createObject("java","railo.runtime.SessionTracker")>
<cfset variables.sessions = tracker.getSessionCollection("my_application_name")>
<cfdump var="#variables.sessions#">

This will show is us a lot of this:



After doing the <cfset StructClear(session)> it looks like this:



As you can see, we have cleared out all of the actual data members but we have not deleted the actual session allocation in memory. You could say we accomplished 90% of what we intended by using <cfset StructClear(session)>. But the, if we were doing session monitoring using the session tracker we lose that data and may still have problems with the users login because their browser still thinks they have those CFID and CFTOKEN values. <-- that is the underlying issue with using . Crazy things happen. Usually the session tries to be used again and the URLTOKEN get set their cookie, but the CFID and CFTOKEN are missing. Unless you want to to other additional code checks you are going to have issues.

That's why the solution is to clear the JSESSION, CFID, and CFTOKEN cookies. The server generates a new session, the old session data is available but orphaned.

If you wanted to be reeeeeeealy safe, just in case there are cookie hijackers out there and they stole the user's cookie info and were able to duplicate all header info, cookie and IP stuff to spoof the server, and the server didn't catch it, then you would do both <cfset StructClear(session)> and clear the cookies.

Am I the first to really document this simple and straight forward? I can't be,,,

Tuesday, May 5, 2009

Coldfusion List Validator

When working with coldfusion lists from user-entered-data, or from a database of user-entered-data, it's very important to make sure it's a valid data and validly formatted - one comma between each value, only numeric (if desired - as in this case), and no leading or trailing commas.

Coldfusion is abolutely amazing with lists. So much easier than arrays and structures, and with instant conversion to and from an array. Beautiful! But lists can become invalid very easily, especially when working with numeric lists and using those lists in queries.

This is an easy, solid solution to validating numeric lists:

<cfset test = ",22,,345,456,7 8,4x,1,,,">
<cfoutput>#test#</cfoutput><br /><br />
<cfset test = REPLACE(REREPLACE(test,"^,*|,*$|[^\d,]","","ALL"),",,",",","ALL")>
<cfoutput>#test#</cfoutput>

22,345,456,78,4,1

In the case of '..,7 8,..' one might want to replace spaces with commas so that the resulting number in the list '78' is not created.

As a function:

function listval(listin) {
listin = REPLACE(REREPLACE(listin,"^,*|,*$|[^\d,]","","ALL"),",,",",","ALL");
if(ListLen(TRIM(listin)) IS 0  OR  TRIM(listin) IS "") { listin = "0"; }
return listin;
}

Safe.

And that's a wrap.

Tuesday, April 28, 2009

Coldfusion - Determine File Mime Type

Wasting time on something that *should* be a very simple task is one of my worst pet-peeves. It just burns me up.

This one, for instance, in Coldfusion when you do a CFFile Upload a file you get a boat load of matadata about the file in the CFFile and File structures. There should be a way to get that metadata again using the CFFile tag, but NOOOOOOOOO you would have to dig around in java to do that. I'm cool with that. Googling, googling... still googling. This should be more readily available. How come nobody is talking about this in coldfusion? It must be simple. An hour and a half later, one (1) site has the answer, and two answers at that! http://www.coldfusionmuse.com/index.cfm/2006/8/2/mime.types I'll blog about if no one else will. Get this around!

Here it is:

<cfset variables.contenttype = getPageContext().getServletContext().getMimeType(variables.filename)>

Or there is:

<cfset obj = createObject("java","coldfusion.util.MimeTypeUtils")>
<cfset variables.contenttype = obj.guessMimeType(variables.filename)>



Another wrap!

Friday, April 24, 2009

Amazon S3 Sub-Directories SOLVED!

Today was 'S3 DAY'. A number of ups and downs for success and frustration on this project.

I was frustrated with the inability to have sub-directories or sub-folders in S3.

However, thanks to these posts: http://developer.amazonwebservices.com/connect/message.jspa?messageID=36250, it's a snap!

All you have to do is put slashes in the file name and S3 assumes the rest. No fuss like there is with Buckets.
For example: [BucketName]/projectid_00000001/fileid_0000000001/ActualFileName.txt
where you tell S3 that the file name is "projectid_00000001/fileid_0000000001/ActualFileName.txt".


Progress on the RiaForge S3.cfc
I have made quite a number of custom modifications on the RiaForge s3.cfc project. I have stripped it down to remove all bucket support, fixed the issues raised from differences using Railo on Linux, and re-programmed a number of variables to work from the Application scope.

I was also able to design it to maintain a project sub-directory schema using the project ID numbers. S3 seemed to get fussy with subfolders as numbers, so I put some characters in front of the ID number (like 'projectid_00000001').

I was previously using a sub-sub-directory schema to maintain file versions. The file names are stored in the database and the record Primary Key ID padded with zeros to ten characters in length enabled multiple files in the same directory with the same file name.

The S3 schema ends up like this:

[BucketName]
projectid_00000001
fileid_0000000001
ActualFileName.txt
fileid_0000000002
ActualFileNumber2.txt
fileid_0000000003
ActualFileName.txt    (This is actually a newer version of fileid_0000000001 by storing the 'parentid' DB field if '1', code handles the rest)
projectid_00000002
fileid_0000000004
WhateverFileName.txt     (Again, here is the original file, newer versions follow)
fileid_0000000005
WhateverFileName.txt     (This is a newer version of fileid_0000000004, handled by code, parentid=4, sorted by createdate for all children)
fileid_0000000006
WhateverFileName.txt     (This is the newest version of fileid_0000000004, handled by code, parentid=4, sorted by createdate for all children)



Hmm, the parent file ID schema is a little bit different and more complicated than the above example, but you get the idea. There is a directory for each file. The directories are each unique allowing the file within the directory to be identical to other files in the same project. The code is doing all the heavy lifting, all required file info for the display is stored in the database, including Category IDs, Taggings, or whatever. Authenticated links are generated for instant download form Amazon S3 so the entire bucket can be private and secure.

It's a sweet setup.

S3.cfc on Railo - my fix

RiaForge has an awesome project S3.cfc for Amazon's S3 storage. http://amazons3.riaforge.org/

I love it. But it didn't work on Railo out of the box.

I was getting Signature doesn't match errors when attempting to run the s3test.cfm file in Railo on Linux.

After much research and dumping the s3 xml response I discovered that the difference is in the 'StringToSign'.

Using cf8 the 'StringToSign' it was expecting was: "GET Fri, 24 Apr 2009 17:28:00 GMT /"

However, using Railo on Linux the 'StringToSign' it was expecting was:
"GET text/html; charset=UTF-8 Fri, 24 Apr 2009 17:59:00 GMT /"

Notice the 'text/html; charset=UTF-8'.

This was comparing tests from CF8 on windows and Railo on Linux. I'm not actually sure if this is a Linux issue or a Railo issue. I have not tested the reverse (Railo on Windows & CF8 on Linux).

The strange thing is that Amazon was expecting it to be different when Windows CF8 and Linux Railo were passing the exact same request. I reset the 'datetimestring' to drop the seconds on the time [<cfset var dateTimeString = GetHTTPTimeString(DateAdd("s",-(DatePart("s",NOW())),Now()))>] so that I could verify that the signature on the generated signatures from the two machines were identical, and they were. So this really doesn't make sense to me, but I'm glad there was an easy solution.

The fix to making this cfc work on Railo on Linux was to change the following line inside the 'getBuckets' function in s3.cfc

from:
<!--- Create a canonical string to send --->
<cfset var cs = "GET\n\n\n#dateTimeString#\n/">

to:
<!--- Create a canonical string to send --->
<cfset var cs = "GET\n\ntext/html; charset=UTF-8\n#dateTimeString#\n/">

The same edit is required inside 'getBucket' and 'getObject'. Insert "text/html; charset=UTF-8" after the second '\n'.

Then everything worked perfectly. (So far.)

Monday, April 20, 2009

First difference between Railo CF & Adobe CF

I've been working with Railo for a short time now. Migrating from Adobe CF on Windows IIS to Redhat Apache and Railo. It's been great with some added bonuses.

This is the first case where something didn't work with the exact code from Adobe CF. It's using CFLDAP.


From an LDAP UIDNumber stored in the local DB I to an LDAP Query,

    <!--- Get the old data --->
    <cfldap action="QUERY"
           name="actualldap"
           attributes="dn,uidNumber,uid,givenname,street,city,state,postalcode,telephonenumber,email"
           start="uid=XXX,cn=users,dc=XXX,dc=XXX,dc=lan"
           filter="(&(uidnumber=#variables.ldapuidnumber#))"
           server="#variables.LDAPIP#"
           timeout="1"
           username="uid=XXX,cn=users,dc=XXX,dc=XXX,dc=lan"
           password="#variables.LDAPPW#">
   

When I did a cfdump and a cfabort right here, on the Adobe CF server it returned the DN equal to the 'username' passed in. In Railo CF it returns blank, which consequently makes the update LDAP error witht he blank DN. Once I discovered it was the same at the 'username' I was passing in I was able to easily overwrite the blank value with the known value and it was working again.

    <!--- OVERWRITE THE DN RETURNED BLANK!!! --->
    <cfset actualldap.dn = "uid=XXX,cn=users,dc=XXX,dc=XXX,dc=lan">
   
    <!--- Check any changed fields, write the attributes string 'variables.atbs' for the LDAP Modify --->
    ...
   
    <!--- update the changed LDAP fields --->
    <cfldap action="MODIFY"
        DN="#actualldap.dn#"
        attributes="#variables.atbs#"
        modifytype="REPLACE"
        server="#variables.LDAPIP#"
        username="uid=XXX,cn=users,dc=XXX,dc=XXX,dc=lan"
        password="#variables.LDAPPW#">


It was an easy enough fix, but it's strange that the results would be different. I'm not sure if there is a standard or which is not standard. I'm just really glad it was an easy fix.... After wasting 3 hours checking everything else.

That's a wrap.


Wednesday, April 15, 2009

Prevent Nested Execution of a Custom Tag

After discovering this little gem of a function "GetBaseTagList()" I was able to find an easy solution to an issue I was facing on a recent project. (Thank you once again, Ben Nadel, http://www.bennadel.com/blog/657-Determine-The-Parent-ColdFusion-Custom-Tag-Hierarchy-Using-GetBaseTagList-.htm.)

I needed to wrap each display box with a shadow, and I wanted to be able to edit it, site-wide, easily in one place.

The issue was that if a content box was included within another content box I did not want to display the nested execution of the shadow wrapper. I tried to think if various ways to count the executions to do this manually, but they were all messy and potentially buggy. Thanks to the native function "GetBaseTagList()" that is no longer an issue. It displays the nested execution hierarchy with the current one first and the initial ancestor last. So, "ListRest(GetBaseTagList())" will display any and all parents in order. But if things were complicated and there were other nested tags involved (probably not a good idea), or we just wanted to be clear, specific, on the safe side and prepare for whatever idiot might touch the project in the future, then we might want to count only instances of the current custom tag "ListFindNoCase(ListRest(GetBaseTagList()),"CF_CONTENTWRAPPER")". This worked beautifully. See the full code example below.



<!--- contentwrapper.cfm  -  <cf_contentwrapper>content</cf_contentwrapper> --->

<!--- DON'T ALLOW NESTED INSTANCES OF THIS CUSTOM TAG CONTENT WRAPPER! --->


<cfif (ListFindNoCase(ListRest(GetBaseTagList()),"CF_CONTENTWRAPPER") IS 0)>

    <cfif thisTag.executionMode EQ "start">


    <table border="1" cellspacing="0" cellpadding="0">
        <tr>
            <td class="wrapshadow_tl"></td>
            <td class="wrapshadow_tc"></td>
            <td class="wrapshadow_tr"></td>
        </tr>
        <tr>
            <td class="wrapshadow_ml"></td>
            <td class="wrapshadow_mc">
                <!--- tag body contents are displayed in here --->
   
    <cfelse>

                <!--- tag body contents are displayed in here --->   
            </td>
            <td class="wrapshadow_mr"></td>
        </tr>
        <tr>
            <td class="wrapshadow_bl"></td>
            <td class="wrapshadow_bc"></td>
            <td class="wrapshadow_br"></td>
        </tr>
    </table>

           
    </cfif>

</cfif>




Now, this will display as intented:


<!--- content1.cfm --->

<cf_contentwrapper> <!--- this custom tag will only execute when it's not included inside another instance --->
    <div style="width:400px; height:50px;">testing content 1</div>
</cf_contentwrapper>



<!--- content2.cfm --->

<cf_contentwrapper> <!--- this custom tag will only execute when it's not included inside another instance --->
    <div style="width:400px; height:50px;">testing content 2</div>
    <cfinclude template="content1.cfm"><!--- the nested custom tag in the included file will not process, but the content1 html will display --->
</cf_contentwrapper>



Isn't that just grand?


Friday, March 27, 2009

MySQL Missing Function DayOfWeekAsString()

MySQL has so much functionality, it's hard not to love.

But there are rare occasions when I wonder why they missed some simple function like DayOfWeekAsString()

Without it I have to manually to this all over the place whenever I need it:

ELT(DOWnumber,'Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday')b


Dear MySQL,

Please all this function natively.

Sincerely,

Your devoted developer.

Tuesday, March 17, 2009

Optional Parameters within CFScript Functions

This stumped me for a long time. How to make parameters optional in a cfscript function?

Tangent: I rarely use CFScript. It's an optional way to write encapsulated Coldfusion code. Some love it, some hate it, some couldn't live without it, some can't find a use for it and wonder why it was invented. Me? I'm neutral. There are clearly times when CFScript will greately reduce the lines of code, simplify functionality, and increase code readability. That's when I love it - Except when I wanted to use it but couldn't do what I could otherwise do with tagged markup. For example:

I wanted to achieve this MySQL function in Coldfusion:

SELECT STR_TO_DATE('200442 Monday', '%X%V %W');

Here is a function that I wrote in CFScript

    // This returns the Sunday DATE of the Week of the year passed in.
    // Last line of code is also in 'sys_query_projects.cfc' method 'weekrep'. ***
    // ADDED: second optional parameter, dayofweek number for the return date.
    function YWtoDate(yw) {
        var year = LEFT(yw,4);
        var week = INT(RIGHT(yw,2));
        var dow = 2;    //default to Monday
        var retdate = NOW();
        if (LEN(yw) NEQ 6 OR
yw NEQ INT(VAL(yw))) {
            retdate = DateFormat(NOW(),'yyyy-mm-dd');
        } else {
            retdate = DateFormat(DateAdd('ww',(week-1),DateAdd('d',IIF(DayOfWeek('#year#-01-01') IS 1,0,8-DayOfWeek('#year#-01-01')),'#year#-01-01')),'yyyy-mm-dd');
        }
        // Check the Day of the Week passed in - if any
        IF(ArrayLen(Arguments) GTE 2 AND INT(VAL(Arguments[2])) GTE 1 AND INT(VAL(Arguments[2])) LTE 7) {
            dow = INT(VAL(Arguments[2]));
        }
        return DateAdd('d',dow-1,retdate);  //returns the proper day of week requested
    }



Optional parameters in tagged markup is easy

<cfargument name="dow" required="No" type="any" default="2">

The other easy think about tagged markup is that the ORDER pf passed parameters does not matter. (Which is a terribly bad habit and runs against all other programming language conventionality, but is super convenient with you want to pass in only the second and fourth of five non-required parameters.)

Then I stumbled across this little gem called the Arguments[] structure. I never knew it existed! This opens a whole new ball game within CFScript Functions. It puts CFScript on an equal level with CFFunction. I believe CFFuntion has the same structure and a better way to catch any passed parameters, but somehow it never made it through my skull that functions within CFScript would have this. Order still maters and you can validate the incoming data however you please.


Monday, February 16, 2009

Useful UDF's: YEARWEEK, YWtoDate, Monday, & NumberSuffix

A few User Defined Functions that I use all the time...

Enjoy.


<cfscript>
   
    // This returns the Sunday DATE of the Week of the year passed in.
    function YEARWEEK() {
        var datein = NOW();
         var yearin = YEAR(NOW());
        var weekin = WEEK(NOW())-1;
        IF(ArrayLen(Arguments) IS 1 AND IsDate(Arguments[1])) {
            datein = Arguments[1];
        }
        yearin = YEAR(datein);
        weekin = WEEK(datein)-1;
        if (weekin IS 0) {
            weekin = 52;
            yearin = yearin-1;  // first couple days in WK 1 count for end of previous YR
        }
        return toString(yearin) & toString(Numberformat(weekin,"00"));
    }
   
   
    // This returns the Sunday DATE of the Week-of-the-year passed in in YYYYWW format.
    function YWtoDate(yw) {
        var year = LEFT(yw,4);
        var week = INT(RIGHT(yw,2));
        if (LEN(yw) NEQ 6) {
            return DateFormat(NOW(),'yyyy-mm-dd');
        } else {
            //return DateFormat(DateAdd('d',((week-1)*7)-(DayOfWeek('#year#-01-01')-1),'#year#-01-01'),'yyyy-mm-dd');
            return DateFormat(DateAdd('ww',(week-1),DateAdd('d',#IIF(DayOfWeek('#year#-01-01') IS 1,0,8-DayOfWeek('#year#-01-01'))#,'#year#-01-01')),'yyyy-mm-dd');
        }
    }
   
    
    // This returns the monday of the week date passed in.
    function Monday() {
        var monday = NOW();
        var currentDay = DayOfWeek(monday);
        IF(ArrayLen(Arguments) GTE 1 AND IsDate(Arguments[1])) {
            monday = Arguments[1];
            currentDay = DayOfWeek(monday);
        }
        if (currentDay IS 2) { //already monday
            return DateFormat(monday, "yyyy-mm-dd");
        } else if (currentday is 1) {
            return DateFormat(DateAdd('d', 1, monday), "yyyy-mm-dd");
        } else {
            return DateFormat(DateAdd('d', -(currentDay-2), monday), "yyyy-mm-dd");
        }
    }
    
   
    // To get the suffix on [1st, 2nd, etc.] use this:
    function numbersuffix(thenumber) {
        return IIF(VAL(RIGHT(thenumber,2)) GT 10 AND VAL(RIGHT(thenumber,2)) LT 20,
                    DE('th'),
                    DE(IIF(VAL(RIGHT(thenumber,1)) IS 1,
                            DE('st'),
                            DE(IIF(VAL(RIGHT(thenumber,1)) IS 2,
                                    DE('nd'),
                                    DE(IIF(VAL(RIGHT(thenumber,1)) IS 3,
                                            DE('rd'),
                                            DE('th')
                                      )   )
                              )   )
                      )   )
                   );
    }
</cfscript>