Unsetting Response Headers in an Apache Reverse Proxy Configuration When Serving PDF to Internet Explorer

Written by Sean Ryan on . Posted in App Dev

Yuck. IE.

Sometimes, we just need to suck it up and support IE even if it goes against everything we believe in. It’s well known that IE has a problem downloading PDFs over HTTPS when certain cache control headers are sent in the response.

See Microsoft’s own support site for this one: http://support.microsoft.com/kb/812935

The workaround for a developer is to make those headers disappear. There are several ways you can do this.

  1. In your application, don’t set them
  2. In your Web server, unset them.

Usually, the better approach is to configure your Web server to unset the header site-wide since the origin of the PDF behind your server is inconsequential. Removing them at the server level makes serving PDFs to all browsers work.

Unset Headers in Standard Apache Configuration

If you are using Apache in a standard way to front your application or site you can identify PDF requests using the Files directive.

<Files ~ \.pdf$>
   Header unset Cache-Control
   Header unset Pragma
</Files>

You should place this in the <VirtualHost *:443> section since this is a problem related only to serving over HTTP.

Unset Headers in Reverse Proxy Configuration

If you are using Apache as a reverse proxy and your PDFs are not on the filesystem relative to the site root, then you need to match the PDFs differently. In this case, you need to use a Location directive since the Files directive is used to match unproxied files.

<Location ~ \.pdf$>
   Header unset Cache-Control
   Header unset Pragma
 </Location>

Again, this should be placed in the <VirtualHost *:443> section.

Convert MySQL Database Character Encoding to UTF8

Written by Sean Ryan on . Posted in App Dev

Create a Database

To create a database that will default to UTF8 without modifying the server defaults run the following command

CREATE DATABASE dbName DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci

Broken down, it means:

CREATE DATABASE dbName – create a database named dbName (best name, ever)

DEFAULT CHARACTER SET utf8 – this database will use utf8 as its default character encoding. All tables created, will be configured to use utf8 for character columns.

DEFAULT COLLATE utf8_general_ci –  when comparing characters, ignore case (ci=case insensitive)

Convert an Existing Database

If you already have a database in some other character set, such as latin1, or ISO 8859-1, you can easily convert it to UTF8 by walking through a few simple steps.

1. Export your database

$> mysqldump -u -root -p \
       --complete-insert \
       --extended-insert \
       --default-character-set=utf8 \
       --single-transaction \
       --add-drop-table \
       --skip-set-charset \
 > dump.sql

This will include column names for your insert statements, efficient insert statements that don’t repeat column names, export in utf, not include setting the existing charset, and include drop table statements prior to create table statements.

2. Edit the Dump to Use UTF-8

cat dump.sql | \
    sed '/DEFAULT CHARACTER SET latin1/DEFAULT CHARACTER SET utf8/' | \
    sed '/DEFAULT CHARSET=latin1/DEFAULT CHARSET=utf8/'
  > dump-utf8.sql

This will just swap out latin1 for utf8. You can accomplish however you want to. I’m a fan of sed and awk and all things command line but the goal is clear; make latin1 stuff, utf8 stuff. Just be careful to qualify your  replacements. You don’t want to accidentally change data.

3. Drop Your Database

From the mysql prompt, run

> drop database dbName;

4. Import UTF8 Version

mysql -u root -p < dump-utf8.sql

 

That’s it. You could easily make a little shell script to do this and when need to convert a database from one encoding to another, just run it. Perhaps the command would look something like:

swap-encoding dbName fromEncoding toEncoding

How to Swap Out a Time Warner Modem With Your Own Faster One

Written by Sean Ryan on . Posted in App Dev

If you live in an area serviced by Time Warner Cable and you subscribe to high-speed Internet access, you’ve recently been mailed a notice with the infamous announcement of their plan to begin changing a “leasing” fee of $3.95/month for your cable modem. The mailing includes a way to avoid the fee by buying your own cable modem but with a caveat that doing so may leave you in dust when they “update” their network and your modem no longer supports their new network technology.

What they fail to mention is that over time, their equipment fails to give you the best experience and fastest speeds they have to offer but that you need to figure this out yourself and swap out your own equipment. When was the last time you ran some speed tests and researched Time Warner’s current network offerings [in your area] so you could decide if it was time to swap out your equipment ?

There are several points to consider when making this decision, so I’ll help lay it our for.

Cost

The cost of doing nothing is known outright: $3.95/month X 12 months = $47.40/year. Assuming they never ever increase that cost, you’re looking at about $50/year. I could shovel my driveway or I could have it plowed for about $50 so you really need to ask yourself, what it is that you value more. That being said, once I buy the modem, I never have to buy it again. Once I shovel my driveway, I’ll need to shovel it again 🙂 So let’s look at this a little differently. I’ve had Time Warner for 13 years now. If I was paying [an avoidable fee] all along, I would have donated $616.20 to Time Warner Cable by now.

Time Warner supplies you with a list of approved modems (http://www.timewarnercable.com/en/residential-home/support/topics/internet/buy-your-modem.html) and the prices range from around $50 to a little over $100. However, I found the SB6121 for $53 online even though it retails at $109.  A little sweat equity goes a long way sometimes.

How “Tech-Savy” Are You?

The process of doing all this is remarkably simple. I have to hand it to Time Warner on this one. I went through the process and the hardest part of all was picking out the modem – and even that was pretty simple after I understood what I needed.

Once you’ve selected your modem (see below) all you have to do is plug it in and move the Ethernet cable from your old one to the new one. Then, call Time Warner (1-866-321-2225) and say you need to activate a new modem. Trust me, they’re expecting your call. They know exactly what you need. They’ll ask one important question: “What’s the MAC address of your modem?” The MAC address, or Media Access Control number, is the way Time Warner authorizes your device to be on their network. To get this number, turn your modem over. It’s plastered right next to the serial number, model number, and all the other FCC stuff. If you run into any problem, Time Warner can and will help you through it.

Bandwidth

Unless you subscribed to Time Warner high-speed Internet in the last few months, it will almost certainly increase your bandwidth and consequently, your download speed – by a lot. Time Warner is in the process of upgrading their network to use the DOCSIS 3.0 protocol and without going into any detail, DOCSIS 3.0 is faster than DOCSIS 2.0, which most Time Warner Cable modems are able to handle. This boils down to you getting a faster download speed simply by using a modem that can handle it; without paying more. Yes, you could bring your current modem back and get one that has the DOCSIS 3.0 firmware on it, but you’d still be paying $3.95/month for it.

There are a lot of variables that determine network speed, such as which day and what time of that day but with a DOCSIS 2.0 (most Time Warner modems) and without turbo should give you about 10-15 Mb/second download and very close to 1Mb/second upload. With turbo, you’re looking at around 2 Mb/second upload.

When I swapped out their 2.0 modem with my own 3.0 modem, I saw my download speed jump from 15Mb/second to 32Mb/second! This test has been repeated dozens of times with similar results. Never has my download speed dropped below 29.

Other Considerations

I don’t want to get political but it’s worth a mention that the new policy of leasing the modem has the potential to be discontinued down the road. They’re already being sued because of it. “Send customers confusing notice of the fee in a junk mail postcard they’ll throw in the garbage, sock them with a $500 million dollar a year rate hike, then announce on your website that customer satisfaction is your No. 1 priority. That’s some way to deliver satisfaction.” That was said by one lawyer initiating a class action law suite on behalf of a New York and New Jersey client. (http://www.pcmag.com/article2/0,2817,2412196,00.asp)

For me, I see this as a way to take a little more control over my Internet access, increase my own speed, and avoid a little monthly fee. It’s not much but then again, buying a modem and calling Time Warner really doesn’t take all that much time.

What Model?

If you haven’t done so, check out the ist of modem they allow and what features they offer. I don’t need wireless access from my modem but you might. DOCSIS 3.0 was important to me and it should be to you too. Multiple ports was not important to me because I have a switch that goes to two routers. Spend ~$60 now or spend $600 over the next 13 years. The selection process really isn’t all that complicated so long as you’re realistic about your own needs.

 

Selecting Cloud Backup Software

Written by Sean Ryan on . Posted in App Dev

The need to backup data is nothing new but how we backup data does evolve and today we should all be at least exploring the cloud for a number of reasons; chief among them is that the cloud is offsite and maybe least among them is that all the cool kids are doing it. But, they are.

Recommendation

If you just want to know my recommendation for which cloud, it’s Amazon (http://aws.amazon.com/s3/). If you just want to know my recommendation for some client-side software, it’s CloudBerry (http://www.cloudberrylab.com/) for Windows and Arq (http://www.haystacksoftware.com/) for Mac users – both by a long shot. Read on to find out why.

Selecting The Cloud

I looked at several clouds for use beyond just backups and some for only backups. I kept coming back to the Amazon cloud because of its maturity, its massive economies of scale, its security model, the APIs, and its insane durability of eleven 9s – as they call it. The eleven 9s is interesting. It means that if you put a file up on the Amazon cloud, there is a .000000001% chance that file will be lost forever. Or, a 99.999999999% it will not be. They even offer a less durability level of 99.99% for about 25% of the cost if you want to “roll the dice.” Considering that until now, I’ve backup all my data on an external 1T drive, I’d be hard-pressed to estimate my own durability level at 90%. For one, the drive is roughly three feet from my computers (not offsite), for another it’s all on one drive (hope it doesn’t fail),  and not exactly the most physically secured device I have.

Let’s face it, if you can get over your trust issues with letting someone else watch over your [unreadable] data, then cloud storage hardly needs an argument. This article is about selecting how to PUT and GET your backup data and not how to choose a cloud so let’s move on…

Interacting with the Cloud

Depending on your nerd level, there may be several ways to interact with the cloud when using it for a backup store. With Amazon, you can build your own urls and use the RESTful services they provide – nerd level, awesome. Or, like a mortal, you can and should use a backup utility like Arq or CloudBerry that does the heavy lifting for you. There are many client utilities to choose from so I took a look at eleven of them and settled on two that stood far above the rest in almost every category of concern to me.

How To Select a Utility

There are plenty of aspects to look at when selecting a utility for your own backups but in my case, I narrowed it down to the ones that meant the most to me and sort of ordered them in my head and knew I would have to give some features up no matter what I found.

What’s the Cost?

Cost is obviously important. Almost all utilities have an upfront cost and most have transfer and storage fees. Some have monthly fees but they can usually be discounted if you sign up for 6 months, 1 year, or more at a time. Both Arq for Mac and CloudBerry for Windows have a one time cost of $29 for the software and you pay your cloud provider transfer and storage fees. $29 is pretty low when compared to the other nine popular solutions on my list.

Which Cloud?

Does the software support multiple clouds? This may not matter to you. Since I knew I wanted to use Amazon, I was only concerned with one cloud. However, not all utilities can use Amazon. For example, Carbonite uses their own cloud and there are no other options. Arq uses Amazon and CloudBerry support many clouds.

Does it deduplicate?

This is a very important feature and I refused to use a utility that was not capable of de-duplication. Simply, it means that if two files are found to have the exact same parts – such as an Excel chart embedded into multiple Microsoft Office Documents – then the duplicated part of those files is only backed up once. During a restore, the documents that shared the same content are restored properly as expected. When paying for transfer and storage, this reduction in backup sizes becomes a tremendous cost saver as your backup data grows. Both Arq and CloudBerry support this.

Does it Encrypt?

Even if the cloud provider encrypts your backup data, you may still want to encrypt the data yourself and prior to transfer. For example, Dropbox stores and encrypts your files on their own cloud but only after it gets to the cloud. If your data is interrupted on its way to the cloud, you’re information is exposed; even when using SSL. Moreover, Dropbox can technically un-encrypt your data – though they say the never do. If you encrypt your data prior to transmission, only you can decrypt it. In fact, if Dropbox un-encrypts your data (because remember, they always encrypt whatever you send to the cloud), all they’ll see is your encrypted version. This is exactly how 1Password syncing over Dropbox works. Arq and CloudBerry both offer encryption. CloudBerry actually offers a very wide range of options on this front.

How Much Space Do I Get and do I have and Control?

Unlimited space is what I needed but you may not need so much. This may depend on the tier you select with a provider. Carbonite, for example has an unlimited option for personal use but very limited to less limited and very expensive options for businesses. All tiers with Carbonite come with monthly or yearly fees that may be worth paying since there are no transfer or storage fees. If you end up with unlimited storage, you may want impose your own logical limits on the size of your storage to keep other costs down, such as long-term storage. Arq and CloudBerry both offer access to clouds with unlimited storage and both offer a way to keep your size within a designated budget. Very useful.

Does it Support Versioning?

Version is pretty cool. It’s a way to keep multiple copies of your files in case you need to restore a file before you overwrote changes and backup them up. Let’s say I backup some Apache configuration files and then make changes to them over the next several hours and by the end of the day, I realize I’ve messed up my http.conf file so badly, I need to start over but I never created a http.conf.orig file like a god little tinkerer. You can use your backup utility to find the original version even though you backed up up seven different version over the last seven hours (assuming you have your utility set to run once/hour). You’ll want to set a max version if possible, otherwise, your backups will grow very large in very little time. I keep mine for 30 days. Both Arq and CloudBerry support versioning from the cloud provider.

Can it be set to Run Automatically?

If you have an awesome backup strategy but forget to run it, what’s the point? I’m not a system administrator; I’m a software developer with no time to manage a system.  I rely heavily on automated tasks and calendar reminders. It was important to me to select a backup utility that could be set to run in the most flexible ways for me.  I have my utility set to run incremental backups once each hour on the hour. This recently proved invaluable to me and indirectly, to my company when I spilled an entire cup of coffee into my laptop. I was mad but lost zero bits of data because minutes before I spilled my coffee, the automated backup ran – and completed. Even if it had not run, the most I could ever be out is one hour’s work. Eating one billable hour isn’t as bad as eating 80 hours (10 days, the default for Time Machine). Both Arq and CloudBerry offer this functionality.

Can I Control its Network Usage?

You need to get your backup data to the cloud somehow and although some cloud providers offer a way for you to physically mail your hard drive to them, this isn’t a solution here 🙂 You’ll be transferring your files over the Internet and if you want to do this while you’re using the network, it would be very nice to have  way to control the network resources that your utility consumes. This is analogous to lowering a thread’s priority in a multi-threaded applications. If you plan to run your backups once per day at 2am while you’re sleeping, then this may not matter to you. Both Arq and CloudBerry offer network throttling.

Conclusion

For me, the choices were clear. For Windows user’s CloudBerry is a phenomenal solution. Not only does it offer everything I needed, it also offered everything I wanted. Like car insurance, I’ll be re-evaluating providers again down the road, but the next time, I’ll be using CloudBerry’s many features as a benchmark when comparing other utilities. My Mac has been running Arq for several weeks now without a problem and I’ve made several individual file restores without any complications.

Cloud backups are the way to go, but be sure to chose an awesome utility to make your life easier.

 

Singletons Business Objects in CFWheels

Written by jbriccetti on . Posted in App Dev

Like many application development frameworks, there is lots of plumbing within that you don’t have to use, but hey, it makes a ton of sense. Singleton object management is a good use case.

Now let’s be clear, I could add something like ColdSpring to offload my object factory pattern to a separate  framework – that often makes sense, but depending on the client and how encapsulated you want to keep things, sometimes just a good clean way to do it on your own makes the most sense.

So we want to make instances of a component and keep these instances around beyond a request. In CFWheels, what’s the best way?

As it turns out, the answer is mind-bogglingly simple – but we have to consider (2) things:

  1. Where do we create the object instances?
  2. How will we be able to reference them?

In straight-up ColdFusion (no framework), we have Application events like onRequestStart, onSessionStart, OnApplicationStart & onServerStart that answer question#1. As for how to reference them, well, that’s easy too – we can just use the “scope” of choice for the persistence – “request, session,application or server” and your done. Of course you may need a trigger to “refresh” the cached instances (now you’re adding some plumbing). Here’s the “old school” way of handling this (or at least the non-framework way)

<cffunction name="onApplicationStart" returntype="boolean" output="false">
	<cfset buildCache() />
	<cfreturn true />
</cffunction>

<cffunction name="onRequestStart" returntype="boolean" output="false">
	<cfif structkeyExists(url,"reload")>
		<cfset onApplicationStart() />
	</cfif>
	<cfreturn true />
</cffunction>

<cffunction name="buildcache" hint="I'll build the app cache of singletons">
	<cflock scope="application" type="exclusive" timeout="10">
		<cfset util = createObject("component","lib.util.widget").init() />
	</cflock>
</cffunction>

But with CFWheels, we really should leverage the framework and not worry about micro-managing these events (although we certainly can if we want to get that granular) – so check it out. Answer #1: config/settings.cfm Answer#2: use the CFWheels set() function:

<cfscript>
	set(util= createobject("component","lib.util.widget").init());
</cfscript>

The Beauty of this solution is that settings.cfm only fires when the application loads (or reloads) – essentially (but not identical to) the onApplicationStart event. Secondly, to provide visibility of our variable anywhere in the application, using the set() function allows us to access the variable by using the get() function

<cfscript>
	util = get("util");
</cfscript>

please note: This solution is specifically for application singletons – behind the scenes, CFWheels is using the application scope for these settings – in fact, the documentation on config/settings.cfm explicitly states this file is for configuration – which is in fact a good use case for application level persistence, but not the only use case. Singleton (Business) Objects are also perfectly viable candidates for this same sort of persistence.

 

User Input, Part 1 – Encoding

Written by jbriccetti on . Posted in App Dev, Gotchas

The Problem

Security 101 – ensure you are implementing input validation to prevent XSS. From the OWASP Top 10 Attack Vector #2

You need to ensure that all user supplied input sent back to the browser is verified to be safe (via input validation), and that user input is properly escaped before it is included in the output page. Proper output encoding ensures that such input is always treated as text in the browser, rather than active content that might get executed.

Example 1: outputting request parameters

<cfset form.name = "Jon" />
Thank You, <cfoutput>#form.name#</cfoutput>

In the above example we are setting the form field “Jon” But if we collect the value from a user (like forms normally do), AND if  the user supplied the name as follows:

<cfset form.name = "<script>document.location='http://en.wikipedia.org/wiki/Cross-site_scripting'</script>" />
Thank You, <cfoutput>#form.name#</cfoutput>

What happens when the output gets “displayed” to the screen? What happens is an instruction is executed by the browser! The script instruction redirects the browser to wikipedia. Imagine if that website was Evil. Really Evil. We’re not talking “the diet coke of evil” or the “margarine” of evil, we’re talking Real Evil. Bad news for your browser.

So we have to figure out a way to tell the browser not to treat these characters as instructions? But before we try to figure out how to do that, what characters are we talking about?

 

character encoding
 <  &lt;
 >  &gt;
 “  &quot;
 ‘  & #39;
 &  &amp;

The bracket characters you already know are characters that can embed a <script> tag into a page. These are big naughty characters. Big. Naughty.

But what about the ” and the ‘ character? Well, checkout this example:

<cfset form.name = 'Jon" onMouseOver="javascript:alert(document.location);"' />
<input name="name" type="text" value="<cfoutput>#form.name#</cfoutput>" />

So it’s pretty obvious where this is going. Any characters that are used for markup should be encoded, lest they be used for big naughty things. Or small naughty things for that matter.

The solution (or at least a solution)

The simplest of solutions is encoding the data on the way out (when sent to the browser). So in the above examples, if we were to simply squeeze our output through the built in ColdFusion function xmlFormat(), we’re good to go:

<cfset form.name = "<script>document.location='http://en.wikipedia.org/wiki/Cross-site_scripting'</script>" />
Thank You, <cfoutput>#xmlformat(form.name)#</cfoutput>

<br />
<cfset form.name = 'Jon" onMouseOver="javascript:alert(document.location);"' />
<input name="name" type="text" value="<cfoutput>#xmlformat(form.name)#</cfoutput>" size="100" />

 

Next Steps:

In part duex, we’ll look at a slight drawback to using the xmlFormat() function. Also, we’ll examine an approach to encode the input on the way in. Finally, we’ll look at filtering input to wipe out any other characters that are used for naughty purposes, such as tabs, carriage returns and other non printable characters. Until then, stay safe…

 

 

A Mobile App with Offline Maps using Titanium

Written by Tim Varney on . Posted in App Dev, Mobile

This past week I was presented with a typical request, but with an unusual twist.  I needed to create a Titanium mobile app which features custom raster and vector layers.  The challenge: the map had to be available when the end user was not connected to the Internet.

Titanium’s implementation of the Ti.Map object doesn’t support offline maps, so I knew right away that I’d have to find a third party solution.  I’m not an Objective C or Java programmer, so writing a custom module was out of the question.  That left me one option.  I needed to find a JavaScript mapping library which I could present in a webview.

During my research, I came across a blog post that mirrored what I wanted to do.  Scott Sheri had created an offline map mobile app using PhoneGap, Leaflet and TileMill which was very similar to what I wanted to accomplish.  Seeing how Scott had blazed the trail for me, I decided to follow his path, only using Titanium instead of PhoneGap.  I knew there would be a lot of differences in implementation, but it gave me a strong starting point.

Generating the Raster Images with TileMill

Years ago, I spent a lot of time working with GIS data, so I have a very strong understanding of how to produce and display spatial data.  I chose TileMill to produce my raster layer because it was easy use and readily saved the images in the mbtiles format.  The beauty of this is that an .mbtiles file is nothing more than a SQLite database.  I could imbed my generated .mbtiles in my application and query it natively using Titanium.

Pay no attention to my horrible choice of colors.  I won’t go into details about how I produced this map.  TileMill has some pretty good tutorials on their website.  Needless to say, what we’re concerned about here is how it’s formatted when it’s exported.

The mbtiles files produced by TileMill are simple SQLite databases.  The schema can be found on the MapBox website.  To view the data within the file, I’m using SQLite Manager add-on for Firefox.

Now that we have our raster layer, we can work on getting Leaflet to work in a Titanium webview.

Using Leaflet in a Titanium Webview

This was relatively simple.  I created an HTML page which included all of the JavaScript needed to produce a Leaflet map.  I then took the two Leaflet source files (leaflet.js and leaflet.css) and included them in the Titanium /Resources/ directory to allow it to run offline.  I then created a Titanium webview to display the page.  Quite quickly I had Leaflet up and running in Titanium.

Extending Leaflet to Utilize a SQLite .mbtiles Database

Leaflet doesn’t support .mbtiles out of the box.  The good news is that because Leaflet is open-source and well documented, it was possible to extend its functionality.  I extended L.TileLayer to create a new JavaScript constructor for adding mbtile layers.  The new constructor is L.TileLayer.MBTiles.

L.TileLayer was intended to add raster layers where the images are server by a tile server with a standard URL format.  (For example, http://{s}.tile.cloudmade.com/[API-key]/997/256/{z}/{x}/{y}.png.)  It was going to be necessary to modify this so that the images would instead be drawn from a BLOB field in the .mbtiles SQLite database.

This is where my implementation had to differ from Scott Sheri’s.  Because Scott was using PhoneGap, he queried the .mbtiles database using a SQLite plugin.  With Titanium, I have native database functionality and would be using that instead.  The big hurtle was that the main Titanium app and the webview are in different JavaScript contexts and I would have to pass information between the two using the Ti.App.addEventListener() and Ti.App.fireEvent() methods.  The fireEvent() method is not asynchronous and does not allow for a callback function.

I overrode three of the L.TileLayer methods (_loadTile(), _createTile(), and _addTilesFromCenterOut()) and added one new method (_onLoad).

  • _createTile() – Originally, the Leaflet tiles (which are simply img html elements) didn’t have an id attribute that I could reference.  This was going to be a necessity because the fireEvent() and addEventListener() methods are not asynchronous.  I was going to have to reference the tile by id when the Titanium response for a request for a tile was returned.  I simply created a random guid and set it as the id.
  • _loadTile – I removed the setting of the tile’s src attribute in this method.  I placed the relevant information needed for requesting tiles (i.e. x, y, z, and id) in an array named aUpdate.  When loaded, the map will consist of blank tiles and they will be populated by Titanium through a later request.
  • _addTilesFromCenterOut() – Leaflet uses a document fragment to load the img tiles to the DOM.  I had to wait until this document fragment was added before I could send the request to Titanium to query for the actual image data.  At the end of this method, I just added a call to _onLoad().
  • _onLoad() – This new method will fire once the blank map tiles are added to the DOM.  It calls a Titanium application level event named getMbTiles.  It passes a JSON form of the aUpdates array.

The getMbTiles event triggers the query of the database for the needed tiles.

SELECT tile_data
FROM images
INNER JOIN map ON images.tile_id = map.tile_id
WHERE zoom_level = ?
AND tile_column = ?
AND tile_row = ?

These tiles are then base64 encoded and sent back to the webview using a custom event named receiveTileUrl.  receiveTileUrl sets the src of the various tiles to the appropriate image data.

Source Files

Leaflet Demo  (does not include mbtiles file) .zip

MasterView.js

map.html

The Offline Map!

Ta-da!  The images are now shown on the Leaflet map imbedded in a Titanium webview.  By turning on airplane mode will show that all the data and code is hosted locally and that no Internet connection is required to use this map.

Next Steps

Now, this is just a proof-of-concept and is not production ready.  The current obstacle is the size of the .mbtiles file.  My simple demonstration map was about 4mb and contained very little visual data.  A more robust raster layer can easily exceed the 50mb limit imposed by the Apple App Store.  A strategy needs to be developed where the end user can pick and choose what data they will need in the field and download it accordingly through the app.

But that’s another blog entry…

Migrating fckeditor 2.6.4 to ColdFusion 10

Written by Perry Woodin on . Posted in App Dev, Gotchas

I moved a site with FCKEditor from ColdFusion 8 to ColdFusion 10. When testing the file browser capability I was seeing the following error:

The server didn’t reply with a proper XML data. Please check your configuration.

The FCKeditor I was using relies on a ColdFusion connector that calls a custom function called FileUpload. This function is located in /editor/filemanager/connectors/cfm/cf_command.cfm. Since FileUpload() is a reserved function in ColdFusion 9+, the server was throwing a 500 error and the FCKeditor was displaying the less than useful error message above.

The fix was pretty easy. Just do a search and replace in /editor/filemanger/~. I replaced FileUpload with fckFileUpload. You will end up changing nine files total. That’s it. I probably should have simply updated the editor, but there were some custom js configurations that I didn’t want to track down. So… there you go.

Need a cheap SMTP host? Try Amazon SES

Written by Perry Woodin on . Posted in App Dev

I recently stood up a couple of ColdFusion servers on Amazon’s EC2. One of the servers is a staging server and I used localhost to send out mail. Turns out Amazon limits the amount of outgoing mail over port 25.

Of course, Amazon offers a solution in the form of Amazon Simple Email Service (SES). http://aws.amazon.com/ses/ From the Amazon SES page:

Amazon Simple Email Service (Amazon SES) is a highly scalable and cost-effective bulk and transactional email-sending service for businesses and developers.

I signed up for SES, and within 24 hours was accepted with an initial outgoing limit of 10,000 emails per 24/hrs. Not bad. And as you prove your worthiness (i.e. no spamming), Amazon ups the limit.

Distracto-boy meets layout=plain

Written by jbriccetti on . Posted in App Dev, Architecture, Misc Ramblings

I’m a huge fan of UI frameworks – particularly Twitter Bootstrap and jQuery UI – and I love making things look great – these frameworks really help me do that. Basically, I’m a wannabe designer. I admit it.

A simple bootstrap-infused login form

a bootstrap styled list view

Some days, i just spend way too much time on getting those buttons, just right, or the right table or grid layout – it can be a time-sucker and I sometimes find myself behind on a deadline because I spent too much time pushing around the UI and not enough time building the “application” code. Enter: layout=plain.

In the CF Wheels framework, a Rails-like approach to CFML development, the base controller class (/controllers/Controller.cfc) has an init method where most folks handle all the pre-processing needed for all requests. We scaffold our CF Wheels apps from our  TroyWeb1 base-build – which includes a “filter” in the base controller to handle  initialization and cleansing of request parameters as well as setting up defaults for the built-in params used by wheels for layout and format.

<cfscript>
	firewall();
	cleanseAndStrip(params);
	param name="params.format" default="html";
	param name="params.layout" default="";
	switch(params.layout) {
		case "plain":
			usesLayout("/plain");
			break;
		default:
			usesLayout("/bootstrap");
	} //end switch
	if(params.format EQ "xml" || params.format EQ "json"){
		get("cfsetting").setEnablecfoutputonly(true);
		get("cfsetting").setShowdebugoutput(false);
		set(showDebugInformation=false);
	}
</cfscript>

Like most app dev frameworks, CF Wheels leverages a front controller design pattern. That means all requests get routed through the same initial channel and that means certain things can easily be managed in that initial routing – like format and layout, which in CF Wheels are parameterized so the request can dictate what format needs to be returned. This is really great in the world of JSON feeds or other syndication streams. Thus, add ?format=json to the url and the plumbing to route your call to a json generating view is all built in. [checkout provides()] Layouts are managed this way too when combined with the usesLayout() controller method.

If you too are mesmerized by the shiny, candy-like buttons, join Distracto-boy in the fight. Create /views/plain.cfm with one line of code:

<cfoutput>#includeContent()#</cfoutput>

and simply change the default for params.layout to “plain”

	param name="params.layout" default="plain";

and there ya go. Badabing! all those distractions are gone and you can focus on creating the app without all that glitter.

layout=plain rendering of the same form

layout=plain on the same list view