Tuesday, June 10, 2014

URLDecoder: Illegal hex characters in escape (%) pattern

Posting so I can find this easily next time, maybe even I'll remember typing this up.

With Railo (4.2+) and MySQL, I used a generated password that contained a percent sign (%) in the value.  For example:

    thisIsA%Password%Sample

The problem is that Railo attempts to use "URL decoding" on it, like converting %20 to a space, as you've likely seen before.

After a search online, I ran across this StackOverflow article.  To sum it up, you need to pre-escape the % sign for yourself, if you're unable to change the password for some reason.

The above password becomes this now:

    thisIsA%25Password%25Sample

Pretty simple, but a tricky item to encounter.

- Will Belden
June 10, 2014

Wednesday, April 16, 2014

IIS 7, Railo and Rewrite Rules (SES)

I recently added the "suggested" SES rewrite rules for my Coldbox app.  I use IIS7 along with Railo Tomcat.  After the rewrite rules were added to my web.config file and uploaded, my Railo admin became (keywords coming:) ugly, unusuable, missing CSS, no style, missing images...just horrible!

You're a developer.  You've been searching for a while.  (Because you didn't find this post sooner.)  You are struggling with getting the Railo Admininistrator screen to look like it ought to.  Everyone says "Oh...sorry, we don't use IIS."  Or those that do say "Oh...sorry, we use Helicon Rewrite engine."  Or even better: "Windows?  Sorry, man..."

I stumbled on a post finally after getting some community attempts at helping, but no real answer.  I don't have the link to the post handy, but at the end of the discussion, the fella said "Okay, well, I'll go back to using Path_Info."   For me, this was for Coldbox and Railo on IIS.  Perhaps you're using CFWheels or another framework where the SES requires rewrite rules.

The rule I had found initially used SCRIPT_NAME.  Not sure if that's an IIS vs. Railo vs. Tomcat problem, but I gave it shot.  It worked!  No more ugly Railo admin screens.  I could actually see what I was doing in there!  (When it doesn't work, and tries to rewrite the Railo links, you might be butchering your error logs for your app, as well as confusing your IIS log files, I'm sure.)

Here's my current rule from my web.config.  (Or you can adapt it for the visual interface in the IIS admin, if you need to.)

<rule name="Application Administration" stopProcessing="true">
<match url="^(.*)$" />
<conditions logicalGrouping="MatchAll">
<add input="{PATH_INFO}" pattern="^/(.*(CFIDE|cfide|CFFormGateway|jrunscripts|railo-context|fckeditor|ckeditor)).*$" ignoreCase="true" />
</conditions>
<action type="None" />
 </rule>

Rules you may have found previously may use SCRIPT_NAME.  Try swapping it out.  Hope you found this and it solved your problem in 5 minutes instead of the week I've been needing an answer.

- Will Belden
April 16, 2014

Monday, April 14, 2014

Coldfusion 8 and Decrypt function

Found an interesting item today in Coldfusion.

Apparently decrypt() in Coldfusion (8, at least) can apparently figure out when you intentionally change an encrypted value and still decrypt it.


Sublime - Key Binding for Toggle Word Wrap

Tired of choosing the View menu, then Word Wrap?  Are you a keyboard person, not a mouse person?

This will save you a little bit of time.  Add this key binding line to your "Key Bindings - User" to eliminate the new for mouse work.

{ "keys": ["ctrl+shift+w"], "command": "toggle_setting", "args": {"setting": "word_wrap"}}

You can certainly change the key combination to your liking.

For me, this is actually replacing the "close window" default binding.  I can hit ALT+F to bring up the file menu and then "x" to Exit the application just fine.  (Been doing that for years.)  Or even ALT+F4.  Or CTRL+W repeatedly (closes files, then the the application when there are no more open documents.)  I simply don't need yet another "exit the application" keyboard shortcut.

- Will Belden
April 14, 2014

Saturday, April 12, 2014

Coldfusion: Easy Timers for your objects

I've been really getting into logging lately.  A good friend of mine, through repeated "Gibbsing", wore me down on it, and I really do like using it.  (We'll talk about unit testing another time.)  It really helps to leave debugging statements in your code, re-enable debugging for that class later and get an insight into what was going on when you haven't looked at the code for a year.

I'm also a big user of Coldbox.  Therefore it is only logical that I also use Logbox, which is heavily modeled on Log4J.  Now, my solution here is really for classes and components (*.cfc files), not so much for *.cfm files.  Though you could easily put this into an application function or anywhere you want that's easy to access.  Would not take much tweaking at all.  In my case, I'm using this in my Service Layer, where 99% of my objects all inherit from a Base.cfc class.  Here are the functions I added to the Base.cfc component.  (I've stripped off some of the hints for clarity here in the post..)

Sorry for the small font, the layout here isn't very conducive.  Just copy to your favorite editor (Sublime?) to view in a larger font.

Coldfusion Code:

<!--- --------------------------------------------------------------------- --->
<!--- Add to your init() or preconstructor:  --->
<!--- --------------------------------------------------------------------- --->
<!--- <cfset variables.stTimers = {} /> --->
<!--- <cfset variables.nTimerTimeoutMS = 600000 > --->
<!--- --------------------------------------------------------------------- --->
<cffunction name="startTimer" access="private" returntype="string" output="false">
<!--- For Railo only, in CF use createUUID --->
<cfset var sHandle = createUniqueID() />

<cfset purgeTimers() />
<cfset variables.stTimers[sHandle] = getTickCount() />
<cfreturn sHandle />
</cffunction>

<!--- --------------------------------------------------------------------- --->
<cffunction name="endTimer" access="private" returntype="numeric" output="false">
<cfargument name="handle" type="string" required="true" />

<cfset local.nTimeInMS = -1 />
<cfif structKeyExists(variables.stTimers, arguments.handle)>
<cfset local.nTimeInMS = getTickCount() - variables.stTimers[arguments.handle] />
<cfset structDelete(variables.stTimers, arguments.handle) />
</cfif>

<cfreturn local.nTimeInMS />
</cffunction>

<!--- --------------------------------------------------------------------- --->
<cffunction name="purgeTimers" access="private" returntype="void" output="false">
<cfloop collection="#variables.stTimers#" index="local.sPurgeHandle">
<cfif getTickCount() - variables.stTimers[local.sPurgeHandle] GT variables.nTimerTimeoutMS>
<cfset structDelete(variables.stTimers, local.sPurgeHandle) />
</cfif>
</cfloop>
</cffunction>

Usage within inherited objects, in this case in conjunction with Logbox debug logging:

<cffunction name="myFuncNeedingTiming">
<!--- 'log' is in my component's 'variables' scope --->
<!--- *Always* wrap debugging code with log.canDebug() --->
<cfif log.canDebug()>
<cfset local.sTimerHandle = startTimer() />
</cfif>

<cfset someOperationThatWillTakeSomeTime() />
<cfset anotherOperationThatWillTakeSomeTime() />

<cfif log.canDebug()>
<!--- Sending the handle back, will kill the timer and return the milliseconds --->
<cfset log.debug('myFuncNeedingTimer complete in #endTimer(local.sTimerHandle)# ms') />
</cfif>
</cffunction>


Fairly easy to implement, should be mighty fast.  In the case of a transient bean inheriting from your Base class, you could modify to add another variables (or override in your BaseBean/BaseEntity class) for whether purging should be performed or not.  (Or create an override function that does nothing.)

Seemed like an idea worth sharing!

- Will Belden
April 12, 2014


Friday, March 28, 2014

Sublime - Correcting your common misspellings automatically

In the past 8 months or so that I've been using Sublime (version 2, as of this writing v3 is still in Beta), I have found it to be the best coding editor I have ever used.  I was a die-hard UltraEdit fan, but after trying Sublime, I haven't gone back to UltraEdit at all.
Enough with the fanboy raving, now to the meat of this post...
In our coding we use the "local" scope quite a bit.  I have a horrible habit I can't break myself of:  I type "lcoal", not "local", constantly.  Sometimes I catch it, most often the compiler does instead!  So I set out to solve it.
In Sublime, keyboard shortcuts aren't just ctrl+shift+x, they can be series of key combinations, like ctrl+k, ctrl+b to toggle the visibility of the file navigator on the left of the screen.  Sublime also supports macros, which are pre-recorded actions, such as typing.  Here's what you can do.
  1. First, record a macro of what you WANT to type.  To start recording a macro, choose "Record a macro" from the Tools menu or hit ctrl+q.  
  2. Next, type the correct word you want to appear.  In my case, I typed out the letters l-o-c-a-l-(period).   (I only wanted this to kick in when I typed "lcoal.", with the dot.)  
  3. Now, stop recording the macro with Tools...Stop Recording Macro or shift+ctrl+k.
  4. The next step is to save the macro, also available from the Tools menu.  In my case, I saved it as "type-local.sublime-macro" in the folder Sublime suggests, the Packages/User folder.
  5. Now, open your Key Bindings.  From the Preferences menu, choose "Keybindings - User".
  6. Now, add an entry like so:
    , { "keys": ["l","c","o","a","l","."], "command": "run_macro_file", "args": {"file": "Packages/User/type-local.sublime-macro"} }
    You'll notice that the keys value is a JSON array of keys, in order, that I always type incorrectly.  This is the incorrect order.  I want this misspelling to trigger the macro that types it correctly.  
  7. If you don't get the JSON format right (watch your commas and closing brackets and braces), Sublime will tell you and not let you save the file until you correct it.
It's important to note that the keys in the key combination array above are replaced with whatever actually happens.  It took me three times to wonder why my recorded macro of hitting backspace 6 times turned "" into "".  I was actually backspacing over the "cfset" portion of my text.  The key combination is just a trigger and after recognition by Sublime is no longer considered as text you've added to the file.
Enjoy, hope this works out for you!

Acknowledgement:  After much Googling for the right information, this post kind of got me on track, though it doesn't discuss macros specifically.  I needed it to be transparent and not slow down my work.  The use of key bindings combined with macros accomplished it perfectly.

Monday, January 06, 2014

Buffalo Linkstation - Partition not Found

Mostly putting up this content so I can find it again later, but it might help some folks that struggled to find an answer.  Original post was here:  http://www.herzig-net.de/prog/?page=unbrick_ls-wxl  (Never know when a page might no longer be alive!)

Now, this post refers to a "Buffalo Linkstation Duo".  Mine happens to be a Linkstation 421e (or 421ED), with installable drives of your choosing.

NOTE:  I performed these steps because I had placed new, unformatted drives in here.  Neither I nor the original article author can or will be held responsible for this content as applied to drives with existing data.  Please proceed at your own risk.

-------------------------

Unbricking of a Buffalo LinkStation Duo

  • Buffalo LinkStation DUO 1TB (LS-WXL/R1)
  • 2x Samsung 500 GB Drives

Bricking


I removed the RAID0-array to rebuild as a RAID1-array. Because there were errors during the creation of the array, I tried rebooting the device. Unfortunately, now it would not want to boot anymore.

I tried resetting to factory defaults (hold FUNCTION while powering on, then release and press once), but to no avail.

NASNavigator2 reported the device as in EM-Mode (Emergency) and requested a firmware update or a service call.LS-Updater would not update the firmware since it could not find the partitions.

So I removed the drives and connected them to my Windows PC with a USB-to-SATA-adapter. After removing all partitions, I inserted them back into the device.

The Function LED glows permanent red and now it was seriously bricked, since it had no operating system and it would not boot via TFTP.

Ouch.

Unbricking


Edit LSUpdater.ini
[Flags]
VersionCheck = 0
NoFormatting = 1

[SpecialFlags]
Debug=1

Start LS-Updater, it should find the device in EM-Mode. Open System Menu and go to Debug-Options.  

[Editor note: If you don't know, the system menu is the menu that comes up when you click (in Windows, typically) the icon in the top left corner of the window. This is where things like "Maximize", "Minimize" can be found.  In Windows, this is usually also available by clicking CTRL+SPACE.).]


Deselect everything. Select Ignore Version, Rebuild table, Force Update.

Select Update.

This will recreate the disk structures. It will take a while and end with an error message which can be ignored. 


[Editor note:  The formatting took about 10 minutes or so for the 3TB drives I installed.]

Now back to the Debug-Options. Deselect Rebuild table, select everything in the left Update column.

Choose OK and then click "Update" on the main window.

Since we have partitions, the update process can install the firmware. This may take a while.

[Editor note:  I went through a very long time of two progress meters with the message "LinkStation booting...".  The top progress meter went through several iterations quickly and the bottom progress meter went a bit more slowly, but only needed to go about a third of the way before I received the message "LinkStation has been updated."]

And it ends with an error message:

[Editor note:  I did not receive this message.  I suspect the original author may have because of the "Use DHCP Client" checkbox, and after the device rebooted, it may have received a new IP address, but I'm not 100% sure of this.  It also may be because of the model differences between his Linkstation and my 421e.]

------------------
At this point, I was able to go into my configuration and do the changes I needed to do.  I purchased this LinkStation with the intention of using the 2x3TB drives in a RAID1 fashion (mirrored drives, not total storage).  My initial setup placed it in RAID0 where I would get ~6TB of space because of the RAID striping.  This needed to be reconfigured.

Thanks to the original author for his problem solving that got me up and running.

- Will Belden
January 6, 2014

Tuesday, August 13, 2013

Coldfusion: Issue with application mappings and expandPath()

This is just a quickie regarding Coldfusion's per-application mappings and what happens when you try to use expandPath() with your mapping.  (Note:  This is under CF9, our company hasn't yet gone to CF10.)

Working in a test file of testSandbox/testFolder/test.cfm, I needed to access a CFC outside my webroot.  I added this to my testProjection/Application.cfc. (Because there's no way to add per-app mappings at runtime (outside of the Application.cfc) that I could find.)
   this.mappings['cfc'] = 'c:\Development\Sandbox\someOtherFolder';

In my testSandbox/testFolder/test.cfm file I had these lines:
  <cfset local.sPath = expandPath('cfc') />
  <cfdirectory action="list" directory="#local.sPath#" name="local.dir" />
  <cfdump var="#local.dir#" />
  <cfdump var="#local.sPath#" />

The query contained no records.  The local.sPath variable showed (an assumed) path of my working directory, with 'cfc' at the end.  I had no testSandbox/testProject/cfc folder!  But I had added a per-app mapping for it!  What gives?!?!

So I looked at our actual code, and noticed that all the mappings had a leading forward slash.  Okay, so I changed the mapping line to:
   this.mappings['/cfc'] = 'c:\Development\Sandbox\someOtherFolder';

...and ran my lines again.  The query was still empty, and the sPath output still showed 'testProject/cfc'!  Next, I edited the .cfm code to also add the leading slash:
  <cfset local.sPath = expandPath('/cfc') />
  <cfdirectory action="list" directory="#local.sPath#" name="local.dir" />
  <cfdump var="#local.dir#" />
  <cfdump var="#local.sPath#" />

NOW I get a list of the files in the actual cfc folder outside my root.   Out of curiosity, I went back and took out the leading slash in the Application.cfc, so back to:
   this.mappings['cfc'] = 'c:\Development\Sandbox\someOtherFolder';

and ran again.  The results were completely different.  This time it pointed to:
   testSandbox/cfc

That sort of makes sense, as it pointed to the [webroot]/cfc and I'm using a leading forward slash, except I kept asking "why isn't the mapping honored?".

Clearly, you have to create the mapping with a leading slash like:
  this.mappings['/cfc'] = ....

....and you have to access it with the leading slash, at least for directory- and file-based operations.  

Running a createObject with just the mapping name (the only way you can):
  <cfset local.marshaller = createObject('component', 'cfc.integrations.Gateway') />

seems to work just fine, whether the Application.cfc this.mappings key has the leading slash or not.  So createObject() seems to treat the value differently than does a file/directory operation.  Again, this is for Coldfusion 9, I haven't tested the behavior on CF10 or Railo yet.

- Will Belden
August 13, 2013

Sunday, June 09, 2013

Google Chrome Loading Blank Pages

Making this quick post so I don't have to search forever to find this solution in the future.  (You know, where you scratch your head and say "I've had this problem before.  How did I resolve it?")

Sometimes Google Chrome gets weird.  For me this is often when I put my Windows machine in sleep or hibernate mode.  Next thing I know, all currently open page in Google Chrome or any new pages I open simply contain nothing.  Blank.  Zip.  Nada.  They aren't even trying to hit the network.  They do nothing.

Here is one solution I've tried that works:

  • Shut down Chrome.
  • Check your hidden systray icons to see if there's another running.  There often is.  Right click and shut it down, too.
  • Next, go into this folder:
    C:\Users\[your username]\AppData\Local\Google\Chrome\User Data\Default\Local Storage
  • Delete everything in there.  If you feel nervous about deleting the contents, move them to a different folder instead.
  • Start Chrome up.

You should be good to go.

- Will Belden
June 9, 2013

Saturday, April 13, 2013

UltraEdit -- Syntax Highlighting not Working (How to fix)

Just a quick post here, if for no other reason so I can find it later myself.

With the last few versions of UltraEdit (up to v19 as of this writing) on my home machine (but not another machine I use UltraEdit on daily), my Coldfusion files would not correctly highlight upon opening.

There were two symptoms:
1. CFM files would highlight, but not CFC files.
2. The CFM file highlighting seemed "off" somehow.

Turns out the two symptoms had two causes:
1. The "cfm" file extension was associated with the HTML wordfile
2.  The line terminators were wrong on the Coldfusion wordfile.

Steps to corret:
1.  Removed the CFM extension from the HTML wordfile.
2.  On the Coldfusion wordfile, which did have the CFM and CFC extensions, I had to convert the file.

On the Coldfusion wordfile, after opening, I could see "UNIX" in the status bar:

As of UltraEdit v19, you change this by choosing:
    File > Conversions > Unix/Mac to DOS

You get a dialog about "can't undo", just choose "OK".

I had a CFC file open in another editor tab.  As soon as I saved the converted Wordfile, it automatically picked up the syntax highlighting.  Yay.

I found the original information on how to correct here, but it mentions hitting F12, but that might be old.  Use the steps above with "Conversion" to properly correct.
http://www.ultraedit.com/support/tutorials_power_tips/ultraedit/add_a_wordfile.html

- WIll Belden
April 13, 2013

Sunday, October 07, 2012

Customer Service / Phone Menus

I found myself needing to call AT&T (Mobile) today to ask some questions about my account.

When you begin to wade through the phone menu, one of the first things the system does is ask you for your wireless phone number and then the last four digits of the account holder's Social Security number.  After sitting on hold for however long, what's the first thing the representative asks you?  They ask you for your wireless number and the last four of your SSN.  What *is* the point of entering it in the first place?

After I finished what I needed, I had a question about a (basically bogus) feature on my plan called "International Calling - Expanded".  The rep indicated she should transfer to me another department to get more information. Okay, fine.  I have no problem with that.

I get to the next department and, sure enough, the system asks for my wireless number and last four SSN digits.  And, sure as the sun rises in the east, the rep asks me for the same information again.

This definitely falls under my blog's title of "rants".  I don't mind that the system asks me for it and I don't mind that the representative on the phone asks for it.  But pick one!

AT&T isn't the only vendor that does this either.  I would say that 85% of all vendors I deal with on the phone, that have phone menus, do exactly the same thing.

It's not so much that it's a waste of time (which is actually is), but it's just plain annoying and shows no respect for the customer's time.

- Will Belden
October 7, 2012

Thursday, June 14, 2012

(Possible) Tool for managing Scottrade Portfolios (not OFX)

(I hope you stumbled on this post trying to find a solution for a stock portfolio management/status solution because you're frustrated with everything else out there and you're a Scottrade customer.)

I am Scottrade customer.  I have a bad habit (maybe) of wanting to watch my portfolio.  Now, I'm in it for the long haul, meaning I don't really do day trading or even monthly trading.  We usually put funds into my wife's IRA account at tax time for the deductions or, if we have some spare cash, into our joint non-retirement account.

I, too, also have an IRA account and sometimes use dividend payment amounts to purchase new stocks within the account.  But now that I have a 401K at work, any contributions I make to the account (if allowed at all) are not tax-deductible.  You can't contribute to both a 401K and an IRA.  Why would you, really, when a 401K has much higher contribution limits (and typically, employer matching) than does a self-managed IRA?  However, please take any tax-related information I provide with a grain of salt and do your own research.  I am not a CPA.

For a long time, I used Google Portfolios to watch my stocks and ETF's.  However, I became extremely frustrated with the limitations of their system.  I love Google, don't get me wrong, but Google Portfolios just doesn't provide what I want. (And who can really complain? It's free, after all.)  Here are some of the areas that I wanted improved, but haven't seen:
  • They offer imports  OFX and CSV, but they don't work very well.Best I can tell, Scottrade doesn't provide an export to OFX.  Scottrade only offers CSV exports from your account history.  
  • Their OFX import isn't perfect and can't handle all transactions types.
    (I went through many downloads and trial installations of CSV-to-OFX software (paid and free) just to end up more frustrated than when I started in the first place.)   I attempted to import a three-line Scottrade account history CSV export containing three dividend payments.  The "Preview Import" seems to show them, but once you commit, you just get:  "Some transactions in this portfolio are invalid. Edit transactions to correct errors." with Google Portfolios.
  • Google Portoflios cares pretty much nothing about dividends.Why does this matter?
    • Dividends affect account cash balances.
    • To me, dividends are a part of performance.  (A $10 purchase of a stock now at $20 a share, that's 100% growth.  But if you also received another $100 in dividends, wouldn't you say that stock is performing better than another stock at the same purchase/growth that hasn't paid any dividends?)
    • To be fair, I think you can enter dividends (or at least cash transactions) manually.  But who wants that.
  • I can pretty much guarantee you that every brokerage's data exports are going to be different.
    So, I can understand Google needing to make things a bit generic.  I use Scottrade and am going to continue to use Scottrade for the forseeable future, so that's where my focus is.  If Scottrade puts "CASH" as a ticker symbol in the export, I need to be able to deal with it.
  • I have multiple accounts I manage.
    With my IRA, my wife's IRA and our joint non-retirement account, I want to see three different account cash balances but I want to see performance of all three accounts as a combined portfolio.  (And perhaps each account individually, too.)  There are some stocks that we own that we have purchased by different accounts.  So I might have 10 shares of (F)ord in my IRA and another 30 in our joint account.
  • More things I can't think of offhand.
    It wasn't just Google that had incompatibilities with my needs.  It was pretty much every other free online or downloadable portfolio manager I tried.
So.... to the solution.  I'm a web developer.  I think I'm pretty good.  I've been developing software and websites for right about 20 years now.  So I wrote my own portfolio manager, specifically to handle Scottrade.  Before you get any further in your reading, let me state that I have nothing production ready for anyone but myself.  There's no login security yet, I run the webserver that powers it in a local VMWare setup.  There's also no separation between my accounts and anyone else's I might put in.  The purpose of this post is to gauge public interest in my developing this further.

Here are some features I've included:
  • Security
    There is never a need to provide your login information for Scottrade to us.  You don't want to, we don't want you to.  You handle the exports from Scottrade manually.  (Perhaps later we'll add an API call (if Scottrade makes that possible in the future) or some sort of screen scraping.  Personally, I'd like to have the system check my Scottrade accounts one or two times a day.  I'd like to see Scottrade offer some sort of public-key API that lets a service pull transactions, but never, ever be able to modify anything about the account.  That'd be swell!)
  • Account Creation
    If you're like me, and have multiple accounts, you can create those accounts, with any label you want. It is not necessary to reveal your Scottrade account number to the site.
  • Transaction Import:
    Handles the [current] standard Scottrade export you find under My Account (tab), Account History (left nav link).  You choose what dates you want to view, then you can click the "Export to Excel" link to receive a CSV file download.  Then in (the tentatively named) "PortfolioWatcher" (PW) system, you can import the files to the appropriate account you've created.  In addition, the import process automatically updates the stock with the 
    Scottrade account history export tool
    Scottrade account history export tool (Image courtesy Scottrade)
  • Positions Report
    This is the screen you'll look at most of the time.  Shows all your stocks, the semi-current values of each stock, what type it is (Stock, ETF, etc.) and all the values regarding investment, unrealized value, growth, growth with dividend, dividends total, average dividend, etc.  The page can be set with a customizable refresh time (15 minutes at a minimum or more) so that if you keep the page open in your browser, it will automatically update all the values as the stock prices change.  (The stock prices are updated every 15 minutes, so any refresh on the report less than that is a waste of bandwidth and webserver processing because there will be no difference shown most of the time.)

  • A "slim" version of the Positions Report
    My wife and I like to be able to see the report on our customized Google home pages, too.  There are a couple different Google page "gadgets" that allow for an iframe tag to pull content from another site.  In the slim view, the totals are at the top to avoid scrolling.

  • Stock quote updates via Google API every 15 minutes during market hoursThis system isn't meant to be realtime.  It's meant to give you an idea of how things look in your portfolio.  It answers "Am I up?", "How much am I down?" and "How's my portolio doing?" in a rough fashion.  If you need more detailed and much quicker information, try the Java app that Scottrade provides after meeting minimum account balance criteria.
  • Daily Closing Balance retrievals
    After the market closes each day, the system automatically looks at all the stocks ticker symbols it knows about (assuming some account has an active positions for it) and retrieves the balance for each and stores in our history.   Also, if I were to import a new stock that I purchased, they system will go to the earliest transaction date I imported and retrieve all possible history for that stock from that date through today.
  • History Charts (incomplete)
    The Daily Closing Balance retrievals are important to create stock position graphs.  The feature is not yet complete (drawing the charts, etc.), but will allow you to filter by one or more of your available accounts and by a given date range.  I also intend to allow multiple chart line comparisons (limit five stocks) for a given date range.  Charts would be available by most of the value fields such as by growth, growth with dividend, dividend totals, etc.

I hope this gives you an idea of what I've developed and where I'd like to go with it.  If there's enough interest by folks wanting to use the site to view their own Scottrade portfolios I'd like to continue my development and allow a few beta testers to sign up and work out the kinks once the security model is firmly in place and has passed my own QA process.

Long term, I'd like to make it a free-mium type site.  Free accounts would be limited to a single brokerage account and probably less-frequent data refreshes, such as 30 or 45 minutes instead of a 15 minute minimum.  Still functional, highly useful, but just, well, free users would hammer the server a lot less and utilizes less bandwidth.  The likely price-point would be around $8-10/month or $80-100/year (shaving off two months cost for a yearly purchase).  Another option would be to offer a certain time frame (probably 30 days) free to let folks see how great it is.

In addition, once the Scottrade portion is complete and running bug-free we could begin to offer support for other brokerage houses if people feel like what they get with other tools or a given brokerage's built in tools doesn't meet their needs.

Drop me a line if you think you might be interested in being a potential user of the system.  If I get enough response, I will focus some time on it and get it up to speed with proper security, encryption, etc.  If there is enough interest and I get it to that point, I'll likely create some "sample" portfolios so that you could see it in action and browse through the features.

- Will Belden
June 14, 2012

Wednesday, March 02, 2011

CSS Trick for HTML5, Edit CSS inline for the page

We all have our favorite RSS feeds to follow and I'm no exception.  One my favorites, CSSTricks.com, had a great post this morning about how you can use HTML5 along with an easy setup to edit CSS for a page right there *on* the page.  Pretty neat trick.  Be sure to try the demo!


Check it out for yourself:
http://css-tricks.com/show-and-edit-style-element/

Wednesday, June 02, 2010

Very cool Javascript debugging trick (Firefox, Javascript)

I'm working along on a page, an interface for some configuration data.  I have a javascript validation routine that runs upon hitting save.  I had all my various dynamic HTML elements exactly like I wanted them, and didn't want to hard reload the page, yet again, to get the new Javascript code.

In Firefox, I opened Firebug, went to the "Console" tab, and pasted a whole new copy of the function into the console line.  After pasting a multiline piece of code into the small console line, a larger side window popped up to allow better editing, also available from the small icon to the bottom right of that section:


I proceeded to hit my "Save" button to begin my validation and, volia!, my new function worked correctly with the bug fix in place.  And I didn't have to refresh the entire page and start from scratch.  Not a bad little trick!

- Will Belden
Wednesday, June 2, 2010

Saturday, August 22, 2009

Gmail Notifier -- Wasn't working, here's the fix...

For some months now, I've been having errors with Google Gmail Notifier. Whenever my machine restarts, I'm asked to login for that little app, which I do. It promptly says "Can't connect..." or some such thing. I typically just exit the app and don't think about it until my next reboot. The wheels on the bus go round and round....

I finally decided to investigate after installing the latest round of Windows Updates (which, of course, nags me to death until I reboot!) Seems that the culprit lies in the Gmail setting of "always use https" to connect to Gmail. Apparently that setting prevents the native Gmail Notifier of being able to fetch the data.

After some brief searching, it appears there is a very simple registry hack (done by double clicking a .reg file in a zip file you can grab.)

Here's the Google post with the zip and the details:
http://mail.google.com/support/bin/answer.py?hl=en&answer=9429

- Will Belden
August 22, 2009

Tuesday, May 19, 2009

Better Javascript in Coldfusion

I gave a presentation today at work on improving your Javascript skills, as it relates to Coldfusion development. While there were a million things I would've like to cover, I only had an hour. Here are some highlights that might be worth passing on:
  • Avoid <cfinput> and <cfform>
    These tools, while helping to make your Coldfusion development faster, really cripple us as coders. I believe that every HTML developer (those who code in PHP, CF, etc.) needs to know Javascript. The js code generated by Coldfusion is very bulky and not necessarily optimized.

  • Avoid using Coldfusion variables in your Javascript code.
    Think it through and parameterize your JS rather than being lazy and including #variable# directly in the code.
    Good and Bad Javascript example

  • Move your Javascript to external files
    By placing your js in an outside file, linked to by your Coldfusion code, you allow the browsers to cache something that doesn't change too often. This results in increased bandwidth savings, better logical separation and enforcement of keeping CF out of JS.

    In addition, if you have access to a "resource service" that you can tell to include a particular js file (as opposed to using the <script> tag) you'll be able to implement a minify/pack/gzip solution as well as a combining technique at a later date. A service like this can prevent multiple script tags for the same file when the HTML is rendered.

  • Think cross-browser, at all times.
    Sure, maybe today your company says "We only support IE". But I can almost guarantee you that tomorrow it will be "We only support IE and Firefox." In one set of code I saw recently, the js would simply reference "myInput.value". Apparently this works in IE, but doesn't work as well in Firefox. If they had done a proper getElementById() or even
    document.myForm.myInput.value there wouldn't have been issues.

  • Get behind jQuery (or some Javascipt abstraction library)
    By using a tool like jQuery for DOM element selection, like $('#myInput'), you enable abstraction of how you get the object. These tools are also optimized differently for different browsers, allowing you to use a single style of object fetching, without writing a lot of "if IE" statements.

  • If you name an object, also give it an ID.

  • Remember, ID's are meant to be unique amongst all elements on a page.

  • If you need to "group" objects, just add a non-styled class element to the objects. Then you can use something like jQuery to get all the elements with that class.

  • Don't use versioning in your file names.
    If you have myCode.1.2.3.js and you reference that in your code, then you have to refactor all your pages that reference that file when you want to upgrade. Just copy that file to myCode.js, then you swap out the files when a newer version comes along with no code changes.

  • Comment, comment, comment!
    Can't stress this enough. Even if you're the only developer on the project and always will be, commenting is still valuable. I can't tell you how many times I've come back to some code, no matter what language I used, and had no immediate recognition of the code I had written or how it worked. Commenting is so important.

  • Try dynamic event binding
    If you have 10 phone fields with onblur="formatPhone(this);", why not add a class to those fields, like class="phone". Then with something like jQuery, you can create an document.ready event that will bind the formatPhone() custom function to all objects of input#phone that it can find. You could save a whole lot of bandwidth on a site that dishes out such a page frequently.

  • Remember, there's always more optimization to be done
    Most developers are receiving a paycheck from a company that has hired them to produce results. Because of this we have to balance speed with quality. Typically, however, a little forethought can go a long way. Rush, rush, rush is never the answer. Spend 3 hours now to do it right versus 1 hour to "bang it out" and you'll be spending that 1 hour now and 5 later trying to refactor it and correct it. (And that's just you....what about other developers on your team that may get saddled with having to fix your poorly thought out code?)
- Will Belden
May 19, 2009
Updated: August 22, 2009

Monday, March 16, 2009

SQL Server Error: Dynamic SQL and 'you must declare scalar variable @whatever'

A good CF-er friend of mine says blogging about mistakes makes me look bad to potential employers. I think that it might help someone out there save some time, and to remind myself that I certainly don't know as much as I think I do!

So here's a fun one for today.

I had to modify an MSSQL stored procedure to pass an already defined parameter to another proc. That inner proc helps build dynamic SQL. So I [roughly] modified the WHERE clause setup of the query like so:

SET @dSQL = @dSQL + ' AND PersonId = @PersonId'

Drove me crazy trying to find out why it kept telling me to declare the variable. After about 20 minutes of digging, I realized my mistake.

When the dynamic SQL runs, @PersonId is no longer defined! Seems obvious now that I mention it, but, well...you had to be there. The correct syntax is:

SET @dSQL = @dSQL + ' AND PersonId = ' + @PersonId

Again...it might seem obvious now that you're reading it, but trust me...it wasn't at all obvious when I was trying to debug it.

- Will Belden
March 16, 2009

Wednesday, February 11, 2009

Trillian Astra -- Awesome hidden feature

So I've been on the Trillian Astra (multi-service instant messenger program) beta for some time now. I totally love it and can't wait for it to go to production so I can pay these guys for their great work.


I just discovered a nifty feature today by accident and wanted to share. Typically, I use the custom hotkeys to show and hide the contact list, then double click the contact I want to IM with.


You can, however, drag individual names or entire groups out of the contact list and drop it, and it will create an always-on-top mini list. I tend to only IM about three people most of the time, so it fits quite nicely hovering in the corner!




Way to go Trillian!

Monday, November 17, 2008

Implementing Transfer Observers across all your decorators, the easy way!

In our framework, we use Transfer "Decorators" as a common way to extend the functionality of the generated objects that are based on the configuration XML.

For this system, we have a record (media) that represents each user upload of images. For example, we allow multiple profile images to be uploaded, and you can select your current profile image from the "gallery" of your previous uploads. In addition, however, you can delete these images. If you're familiar with transfer, you know it's as easy to delete the database record as saying oMedia.delete(). That removes the object from the database and from Transfer's cache. In this case, however, we also need to remove the actual files from the webserver.

One possible solution was to create a manager service, and make sure that all media deletions go through it. However, this removes some of the intuitive nature of Transfer providing a delete() function for you to use. With Transfer Observers (or "Transfer Event Model"), you can easily extend your decorators to do this on the normal delete() call.

After my initial creation of a mediaObserver.cfc, which I register with Transfer as an observer, I realized I was going down the wrong path. The problem with this is that all observers registered with Transfer get called on each of these seven events:

observerAfterNew,
observerBeforeCreate,
observerAfterCreate,
observerBeforeUpdate,
observerAfterUpdate,
observerBeforeDelete,
observerAfterDelete


The problem with that? Naming my file MediaObserver has nothing to do with my Media records. The events in the observer get called for any object that is getting ready to be created, updated, deleted, etc. So the first thing I did was to rename the file as TransferObserver.cfc. This is a more generic name, obviously, and reflects more accurately what the file is.

So...the question remains at this point: How do I get it to fire an event specifically for my Media records being deleted? Each of the functions you place in the observer receive a single argument when called: transfer.com.events.TransferEvent

From that event, you can do:

arguments.event.getTransferObject()


This gives you the actual Transfer object being modified for this event. That still doesn't tell us this is the Media object, though. But we can do this:

arguments.event.getTransferObject().getClassName()


That returns, in my case, "media.Media". Now I know that this is the object I want rather than, say, an invoice, product or customer object. So I could now write:

<cfif arguments.event.getTransferObject().getClassName() IS "media.Media">
  <cfset arguments.event.getTransferObject().deleteMyFiles()/>
</cfif>


After writing this, though, it occurred to me that every time I wanted to have a decorator respond to a Transfer event, I would have to modify my TransferObserver.cfc to respond to a new class name. It seemed that I could perhaps do this in such a way that I could just add a function, with a specific naming convention, to each decorator, as needed, and it would just work. And you can. Here is the format now for every function I added to the TransferObserver.

<cffunction name="actionBeforeDeleteTransferEvent" returntype="void" access="public" output="false" hint="I am called BEFORE a Transfer object has been deleted from the database.">
  <cfargument name="event" type="transfer.com.events.TransferEvent" hint="The event object" required="true" />
  <cfset var stLocal = structNew() />
  <cfif structKeyExists(arguments.event.getTransferObject(), "observerBeforeDelete")>
    <cfset arguments.event.getTransferObject().observerBeforeDelete() />
  </cfif>
</cffunction>


What is this? The Transfer observer looks to see if there is a function named "observerBeforeDelete" in the Transfer object (or the decorated Transfer object, since this function naming convention is not part of Transfer's generated file format). If the function exists, it calls it. It's that simple, really.

If you'd like to download the entire TransferObserver file, along with a portion of the Coldspring file showing how to set it up. I've linked it here on my site as a tiny zip file (1.2K). Enjoy!

Just a note: Performing a structKeyExists() on a Coldfusion component, as in structKeyExists(object, "functionName") is not a guaranteed way of ensuring that "functionName" is indeed a function. If you have certain property types (like object.propertyName = true), then that "propertyName" is also a structure key. The correct way is to use the getMetaData() function, then you can ascertain for sure that what you are looking for is actually a function. However, the getMetaData() is a slow performing method and would decrease performance significantly to implement. The structKeyExists() should work just find, because you probably won't have a property of the object using this naming convention. And you can actually use a different decorator naming convention for these event-related functions, too. The cffunction names in the TransferObserver.cfc must, however, remain as in my example.

- Will Belden
November 17, 2008

Tuesday, November 11, 2008

How to reintegrate SVN branch back to trunk using Tortoise

We've begun in our dev shop to use SVN (Subversion)branches to develop, test and implement new features. Like many shops I've run across, we use Tortoise as our SVN client. I didn't fully understand the process of reintegrating my branch back to the trunk, and after some reading (along with some trial and error), came up with the basic steps to get everything back together.

Now, these steps below do not include manually merging any changes. I was fortunate enough in this first exercise to have auto-merge ability for my changes to shared files and all my other files were new.

(Be sure you have any files saved and closed, like edits in Eclipse.)

1. Commit your branch back to the repo.
2. IMPORTANT! Export your branch for backup. Quick way: Make sure you can see your desktop, open a window that shows your root branched folder (in my case, "wwwroot"), right-drag it to your desktop, choose "Export here". Ignore this new export folder from here, unless you have problems.)
3. Right click on your branched folder ("wwwroot" again for me), choose "Merge" from the Tortoise submenu.
4. On the Merge screen that comes up, choose the first option: "Merge a range of revisions". Click "Next".
5. Change the "URL to merge from" to the trunk path. Leave the "Revision range to merge" field empty to bring the HEAD changes to you. (This example is assuming that the trunk has received commits after you branched and committed changes to your branch.) Click "Next" (or test merge to see what will happen).
6. Resolve any conflicts you might have, if this applies to your example.
7. You have now brought the latest trunk changes, and integrated them into your branch, bringing your branch up to date. Your branch now contains the most current commits to the trunk, as well as your branch's deviated changes.
8. Now, with the branch containing trunk changes, you need to re-commit your branch to SVN. Do this now.
9. Now, do an update on your branch, just to be sure. You should receive no updates, but this will ensure the metadata is up to date.
10. Next, do a "switch" on your folder, back to the trunk counterpart. This is in in the Tortoise submenu after right-clicking your branched folder. This allows you to merge the changes from your branch into your working copy of trunk, so that you can commit the branch-to-trunk merge back to SVN. (Earlier you brought the latest trunk changes to your branch, the opposite.)
11. After the switch is complete, go ahead and do an update.
12. Right click on your [trunk] folder, choose Merge from the submenu.
13. Choose "Reintegrate a branch" then click "Next".
14. Change, if needed, the "From URL:" dropdown to the branch SVN location.



Tuesday, November 04, 2008

FancyBox, jQuery and z-index

So yesterday I'm working with the jQuery plugin called FancyBox. It's a great little popup gizmo, similar to Lightbox, Thickbox, et. al. But I'm having a problem. In the page I'm working in, I find that we have some crazy high z-index values having been set. One of them is 100,000. Dude. Crazy.

Anyway...so I wrote a small jQuery-based javascript to determine the highest z-index value of all the elements within the page. After some research into the jQuery selectors, I find what I need. Unfortunately, as I return the .css("zIndex") value back from each object, compare it to a running max, I find that in the end the value "auto" is the highest. That's not helpful. I end up finding a simple isNumeric() function I can include, but it only checks the characters in the value against numbers and the decimal point. So I find that, with my routine, 2000 > 100000. Um...that's not right. That lets me know, though, that it's not comparing numbers to numbers, but rather numbers and character values. The parseInt() function solves this.

In the end, here's the basic function I came up with, how to determine the greatest z-index on the page, using jQuery:
<script>
  var zmax = 0 ;
  function buildZMax() {
    $('*').each(function() {
      var cur = parseInt($(this).css('zIndex'));
      zmax = cur > zmax ? $(this).css('zIndex') : zmax;
    });
  }
</script>

With this, you can now call buildZMax() and the var zmax will hold the highest value. Now, that's not all I set out to do. Getting the highest z-index value was the prelude to modifying my FancyBox setups to make sure the FancyBox is on top of everything.

Here's how it ended up looking, though we will modify more today to actually incorporate this functionality directly into the FancyBox code, submit it to the author, and perhaps he'll include it in his next version. But this will get you by:

 <script>
   var zmax = 0 ;
   
   function buildZMax() {
     $('*').each(function() {
       var cur = parseInt($(this).css('zIndex'));
       zmax = cur > zmax ? $(this).css('zIndex') : zmax;
     });
   }

   function goFancy() {
     buildZMax();

     // Get all the outermost fancy_wrap id'ed objects built by the FancyBox calls
     // ...then bump the z-index to whatever the highest we found, plus 1
     $('#fancy_wrap').each(function() {
       zmax = zmax + 1 ;
       $(this).css("z-index", zmax);

       // Get the overlay children in each iteration of the outer
       // ...fancy_wrap, bump it's z-index up.
       $(this).children("div#fancy_overlay").each(function() {
         zmax = zmax + 1 ;
         $(this).css("z-index", zmax);
       });

       // And again for another major child div
       zmax = zmax + 1 ;
       $(this).children("div#fancy_outer").each(function() {
         zmax = zmax + 1 ;
         $(this).css("z-index", zmax);
       });
     });
 });

   $(document).ready(function(){
     $("a#myFancyLink").fancybox({
       'frameWidth': 600,
       'frameHeight': 600,
       'overlayShow': true
     });

     // Call our z-index fixer.
     goFancy() ;

   });
  </script>

Now, something a bit important to note here. You very likely, if you're a jQuery user, have other scripts that might be creating objects, etc. as you go along. It might be beneficial to put your goFancy() call near the end of your document.ready() code to ensure this ends up where you need it. But the buildZMax() function might very well come in handy for other things you might develop with.

Also, while the selectors in jQuery are screaming fast, if you know that you never, ever put z-index on anything but, say, <div> tags, then replace the "*" in the line:
$('*').each(function() {
... with "div" or whatever you apply your z-index'es to. This will make the whole function run faster, obviously.

Post a comment if you're interested in our incorporation to Fancybox code directly.

- Will Belden
Tuesday, November 4, 2008

Wednesday, June 18, 2008

Losing my mind with a form...

Yesterday I created a form. I actually had two on the page. One that did a search, and the results allowed for inline editing. After saving the values in the fields that accompanied the search results, I wanted the search to run again, showing the saved values.

Unfortunately, while my save operation worked just fine, the search wouldn't run again. I didn't understand. My form variables existed in the form scope, but they were always blank. I had added the search criteria to hidden variables within the
tag, but they just wouldn't process. I even threw in some onsubmit() javascript testing alerts, which also indicated that the hidden form values were blank. Looking at the source, prior to submit, I could CLEARLY see the values were there. See for yourself:

<form name="saveForm" action="catmappings.cfm" method="post">
  <input type="hidden" name="site" default="#site.siteid#" />
  <input type="hidden" name="action" default="saveEdits" />
  <input type="hidden" name="searchKey" default="#param.searchKey#" />
  <input type="hidden" name="searchGen" default="#param.searchGen#" />
....


It took me twenty minutes to figure out the problem. I had copied and edited these from commands. Instead of value="#whatever#", the all have default="#whatever#". So you get the fields in the form scope, but, well..no values.

Maybe this post will save someone 5-10 minutes of their life. Clearly, I'm never getting those 20 minutes back for mine!

- Will Belden
June 18, 2008

Tuesday, March 25, 2008

Eclipse and getting .htm and .html files to open in CFEclipse...

I've been working lately with a lot of HTML files that primary templates, read in by ColdFusion and Java for processing. I love CFEclipse, with it's great color coding making my files easier to read and scan.

However, with my current "company-provided" Eclipse setup, .htm* files opened in the regular text editor. I finally figured out how to change it, instead of right clicking on each file in the navigator and selecting "Open With...CFML Editor".

Select the Window menu, then choose Preferences. Under General, Editors select File Associations. Then, scroll down in the list to .htm and .html. Click on the first, ".htm". In the bottom section, called "Associated Editors", depending on your configuration, you might see multiple options. These, apparently, are the choices you have when you right click the specific file. But highlight "CFML Editor", then click the "Default" button to the right. Do this again for .html in the top list, and you'll be set!

- Will Belden
Tuesday, April 25, 2008

Thursday, March 20, 2008

ColdBox Framework, Filename Incorrect error I keep getting...

If you're using the [awesome] Coldbox framework from Luis Majano, you might have run into this error more than once, but can never remember why it happens, even though you've solved it forty million times already.

Application Execution Exception
Error Type: java.io.IOException : [N/A]
Error Messages: The filename, directory name, or volume label syntax is incorrect
ID: CFINCLUDE
Line: 107
Template: C:\[your root]\html\coldbox\system\plugins\renderer.cfc


Well, here's what it is, so you can quit banging your head. You've set the view in your handler, but you included the .cfm at the end, like thus:
<cfset Event.setView("tester/testDumper.cfm") />

Since I've already hit this error many times, and cannot seem to learn from my mistakes, I'm hoping like crazy that actually blogging about it might help me remember for next time!

- Will Belden
Thursday, March 20, 2008

Friday, December 28, 2007

SQL, WHERE clause vs. JOIN clause conditions...

Today I found that there's a difference between the a condition in the WHERE clause and in the JOIN clause in a SQL Statement. Now, I realize there really isn't a difference, but in this case...it made all the difference.

Here's an approximation of the original SQL:
SELECT A.id_a, B.id_B
FROM apple A
LEFT JOIN banana B ON B.id_a = A.id_a
WHERE GetDate() BETWEEN B.start_date AND B.end_date

The idea here is to obviously only get the records where the current date falls in the range provided by the Banana table record. This worked great in all my scenarios where I had a Banana record. When I went to try it on a set of Apple records that did not have corresponding Banana record, I got no results at all.

So I took the WHERE clause (or the line containing the date check) and placed it on the LEFT JOIN clause, like so:
SELECT A.id_a, B.id_B
FROM apple A
LEFT JOIN banana B ON B.id_a = A.id_a AND GetDate() BETWEEN B.start_date AND B.end_date

Now it only applies to excluding out of range records in the JOIN only, rather than applying to the result set as a whole. In the initial flavor of the SQL statement, the date comparison would be made against two NULL values for the date fields. The Banana record requires those date values if it exists, but I want Apple records even if there is no corresponding Banana record, and do no date comparison at all. Only exclude the Banana record if the dates are out of range.

Just a gotcha to keep an eye out for!

- Will Belden
Friday, December 28, 2007

Wednesday, October 03, 2007

Apache and Local vs. Remote on the same network...

Okay...the subject is almost misleading. But not intentionally. Here's the deal.

Don't ask why, but I had to reinstall Apache on my laptop. My laptop is better than my desktop, so I use it as my local development server. I do all my browsing, Eclipse, graphics, etc. on the desktop, though, because of the bigger screen, keyboard, etc.

So I reinstall Apache and all of a sudden, I can't get to the site anymore. (http://local.site.com). Been doing this for months. I haven't changed webroot paths, IPs, nothing but the reinstall. So I'm going crazy and I'm asking all my buddies what could cause this.

One of them suggests the firewall, but I never use it on my laptop since I'm always behind the router. So I sweat and sweat some more, about an hour of this. Finally, I use my old test that I did for testing SMTP servers. From a command line you can run:
telnet www.google.com 80

You get a blank screen, hit enter, escape, whatever and you'll get a bunch of HTML and be returned to the command prompt. So I tried it with local.site.com and got nothing...but "Connecting to....." until it times out. So...clearly port 80 is blocked on either the desktop or the laptop.

On a whim, I pull up the Windows Firewall configuration. Somehow, it got turned on! I never turn it on, therefore never thought to check it.

So, thanks, Tom. Who would of thought! You, obviously.

- Will Belden
October 3, 2007

Friday, September 14, 2007

Network Solutions, Nameservers and DNS work...

Look -- I've been in this web business for a long time. I first started web design, while doing other programming, back in 1995, 1996? I know the web. I'm pretty handy with the concepts of routing, DNS, etc. I'm no network guru, but after looking up the color sequences, I can build an RJ-45 cable. I even have my own tools. I've owned a website design business, pretty successful, too. We had staff and everything before we sold it off. We made Dallas Business Journal's Top 20 Web Design and Hosting companies three years in a row!

All this having been said, Network Solutions really angered me today. I quit using them for personal (or side business) stuff several years ago. GoDaddy rocks, in my opinion, whereas Network Solutions charges an arm and a leg for less services, less quality.

Now, even though *I* don't use them anymore, the company I work for does have several domain names registered with NetSol. That's fine...I'm not sweating it. But this week I needed to setup a new dedicated server (which I did at CrystalTech because they also rock) but didn't want to go through the hassle of having our current hosting company do DNS work, when we'll just be leaving them. And I wanted the control over the DNS records that I'm qualified to have.

So I finally got access and I see that they offer DNS management, much like GoDaddy does, so I'm thinking "Okay...I can do this." So I do.

First problem: I couldn't setup new DNS entries under the NetSol system unless I went ahead and confirmed that the nameservers would be switched. Why can't I set it all up, then make the nameserver change when I'm ready. Makes more sense...but noooooo.

Second problem: This is the one that really lit me up. I've done this a million times. I get the DNS concepts. I understand DNS propagation takes time. For those of you who might be reading and don't understand, here's a brief explanation.
  • Zog wants to go to the website for www.foobar.com
  • Zog asks the Internets to take him there.
  • Zog's ISP says "foobar.com?" Wuzzat?
  • Zog's ISP goes to "the almighty root servers" and asks "Where do I find foobar.com?"
  • The root servers say "Check with Network Solutions".
  • Zog's ISP asks NetSol, "Where's foobar.com?"
  • Netsol says, "I know the answer, you want the www? Go to IP 266.266.266.5" (Yeah, yeah).
  • Zog's Firefox says "Okay...I know that www.foobar.com is 266.266.266.5" and goes there.
Pretty simple. Now here's where NetSol screwed up. When it made itself the active registrar for the domain, it SHOULD have been able to pick up the IP address records VERY quickly. After all, it's their system. It's not like with propagation where all the ISP's in the world try to keep a list of domain names and who knows all the mail, www, etc. individual records. Those only get updated once or twice a day or more, I don't know.

The point is that NetSol's "worldnic" nameservers should immediately know the answer to "where's the www IP?" Once you (or an ISP) starts looking there, it should know the answer. Propagation is about all the ISP's getting the right information. Propagation is NOT about their own nameservers not knowing how to answer the questions.

Using DNSStuff.com, another great site, tells me whats' going on. First, it says that I have "lame nameservers". Other than the obvious pun there, it means that the nameservers associated with my domain name do not answer authoritatively. What? Why don't they? Another test on the DNSStuff site tells me that the root servers say "Check NetSol nameserver A". Nameserver A says "No...check back with the root servers." The root servers say "Okay...check Nameserver B, then." Nameserver B says "Check back with the root servers." Being round-robin, the root servers tell us again, "look at Nameserver A". You can see where I'm going with this. DNSStuff.com says it stops automatically after 20 rounds of this crap.

I didn't expect to bring down the site, email, etc. today. But I did. And it's not my fault. I did everything right, but Network Solutions decided to screw it up. And then their technical support tries to tell me this is normal. Lies. Period. I've done this same thing with GoDaddy enough to know that once you change the nameservers, it should say SOMETHING. Maybe not what you set in the last five minutes, but something.

How long will the site be down? I don't know. The nice tech support man said that it could be 2 to 3 hours before it has the right information. And that I should expect this. Made me angry, but I was polite. Now I have a batch file running an ipconfig /flushdns and ping www.foobar.com loop running. It's been running the whole time I've been writing this, and for an hour and a half before. Let's call it about one hour and 45 minutes. And it's still not working.

As soon as I get this straightened out, I'm moving the domain name to GoDaddy, where domain names belong.

- Will Belden
September 14, 2007

Monday, September 10, 2007

Illudium PU-36 Code Generator and Matching table and column names...

First, let me say that I love the Illudium PU-36 Code Generator. It has made my life a lot simpler, even when I find myself editing the xslt files to get code more like I want. But I truly cannot imagine life without it since Rob Gonda introduced me to it.

I will readily admit that I may not have the latest version. Once you start editing those xslt files, you kinda want to stick with it. But I ran into this issue today, and it took me a bit to figure it out. Here's the error:


Bean creation exception in com.model.vendorTypeA.vendorTypeAService
Cannot declare local variable vendorTypeA twice.:Local variables cannot
have the same names as parameters or other local variables.:

Line: -1



Obviously a line number of -1 isn't helping. It did tell me, though, that the object can't be created. This error, technically, is thrown by Coldspring, but has nothing to do with it.

The issue here is that I have a table called "vendorTypeA". It has a field called "vendorTypeA". This is bad. Here's the code portion, and it seems obvious, once you've been through this.

<cffunction name="createVendorTypeA" access="public" output="false" returntype="com.model.vendorTypeA.vendorTypeA">
<cfargument name="vendorTypeID_A" type="numeric" required="true" />
<cfargument name="vendorTypeA" type="string" required="false" />
<cfargument name="isActive" type="boolean" required="false" />

<cfset var vendorTypeA = createObject("component","com.model.vendorTypeA.vendorTypeA").init(argumentCollection=arguments) />
<cfreturn vendorTypeA />
</cffunction>


Note the two portions in bold, red. I have an argument of "vendorTypeA" and I'm trying to create a local variable of the same name. One is the field, the other is the object, which uses the table name as the object name. The easy solution here is to simply add "_obj" to the last two lines, as in:

<cfset var vendorTypeA_obj= createObject("component","com.model.vendorTypeA.vendorTypeA").init(argumentCollection=arguments) />
<cfreturn vendorTypeA_obj />


Problem solved. Now the object can be created, either "manually" or through Coldspring.

- Will Belden
September 10, 2007

Tuesday, September 04, 2007

SQL Server 2005, Views, Optimizing and UNION

I'm not typically a SQL View fan. I know many who are, and their arguments are all completely valid. In fact, I'm not much of a trigger or stored procedure fan, even though I clearly understand the benefits. It's just a "I like to have my code in one place" kind of thing. Crazy, but there it is.

Well, I needed a view. It was a three table UNION'ed join and....I just needed it simpler than putting all that nasty SQL in my ColdFusion objects. However, my modeling tool, PowerDesigner (PD), isn't always great with views that have computed columns. This particular view was performing too slowly, so I set about to add some indexes to it. Because of the PD problem, the indexes couldn't be built through the modeler. So I'd have to write the index code manually. As I began looking for the code samples, I found this page:
Improving Performance with SQL Server 2005 Indexed Views

One of the things I found was that if you do a UNION'ed view, and you use the same table names again, you should use different table identifiers. For example:

BAD:
SELECT * FROM Table T WHERE T.type="A"
UNION
SELECT * FROM Table T WHERE T.type="B"

GOOD:
SELECT * FROM Table Ta WHERE Ta.type="A"
UNION
SELECT * FROM Table Tb WHERE Tb.type="B"

When I changed my view's code to have this style, the speed on it more than doubled. And I hadn't even done the indexes that I was planning. I will, though...you just watch!

- Will Belden
September 4, 2007

Monday, October 23, 2006

Sunday, October 01, 2006

ColdFusion MX 7, VMWare, VM Shared Folders, Win2003 and Model Glue: Unity

I found myself using a VMWare workstation setup to run my CF7 server with IIS, JRun (Multiserver) configuration and SQL Server 2000 to handle development for a new project. I could have used my live production server, but wanted it to be completely separate as I am learning to use Model Glue as my framework.

Initially, I was simply doing an "upload" via Eclipse to the "server", but the Deployer plugin I use for Eclipse only allows a single file upload, no folders per round. I often modify four or more files at a time and quickly tired of picking each file, right clicking, choosing Upload, and hitting the spacebar to push the OK button on the "Overwrite...?" dialog. Times 4. Wore me out. ( I have never been able to get the builtin FTP of Eclipse to be my friend.)

So my next option was to see if I could use the Shared Folders feature to have the website setup in IIS point to that shared folder as the site. Then I could simply save the file after editing within Eclipse and click Refresh/Reload in the browser.

( I should note that the "shared folder" of which I speak is on the host machine. I wanted the VM "server" to see that folder on my real machine, as all my development code is on an external USB drive connected to my network. - WB)

Let me say this...the right combo can be a bit tricky. I think, honestly, more so because I didn't want the ColdSpring, Reactor and ModelGlue folders in the root, which means adding CF Mappings. (I wish there was another way to do this without adding mappings for the WHOLE server!!!)

Here was the solution that I came up with after much trial and error. (I had to reinstall the VM setup this morning and had to trial-and-error it until I got it right again because I didn't have my earlier successful attempt as a reference. (Blogging here means *I* can find it again if I need it...)

With the VM Workstation or higher, a "network share" looks like this:
\\.host\Shared Folders\MySite

Now you can map these to a drive letter, but don't even try it. Works fine for Windows in general, but not for IIS and CF mappings.

I buried the Reactor, ColdSpring and ModelGlue folders within [siteroot]\_system\, which meant adding those pesky mappings.

In the VM's IIS config, you set the Home Directory of the site to:
\\.host\Shared Folders\NewDevSite
...assuming your site is "NewDevSite", which I'm sure it isn't. You have to make sure that you have the radio button "A share located on another computer" checked first.

That allows IIS find the site itself. Then you have the ColdSpring globalConfig rootPath mapping in the ColdSpring.xml file:

\\.host\Shared Folders\NewDevSite\


And finally...the CF mappings:
\\.host\Shared Folders\NewDevSite\_system\ModelGlue

The problem was that I had [mis]remembered being able to use a mapped drive in IIS, but you cannot do this, at least I wasn't able to to that. I tried and tried, but to no avail.

Hope that helps someone out there!

- Will Belden
October 1, 2007