Showing posts with label web. Show all posts
Showing posts with label web. Show all posts

Monday, July 02, 2012

Sync Sublime Between Multiple Macs

I’ve been using Sublime Text 2 since way, way back when it was just starting to be developed. I’ve used it since and still love it. It’s light, fast and extensible. However, something that I wanted was the ability to have it in sync between my two Macs. I know, first world problem, but something I wanted a solution to nonetheless. I have an iMac at home and a MacBook Air that I use at the office, when I’m not working remotely from my home office. Using Dropbox I was able to easily accomplish this. Please note that this is for Mac OS X, and should also work on Linux, but probably not on Windows (possible solution here)

Install Sublime Text 2

This should be obvious, but if you haven’t installed Sublime Text 2 already, you’ll want to do this first. You can grab your copy here and I’d encourage you to purchase a license to support the developer.

Install Dropbox

I’m using Dropbox to keep my settings, packages and other supporting files in sync between my two Macs. Now I’m sure you have Dropbox already, but if you’re the 1 person left on the planet that doesn’t, then please use this link so that both you and I receive an extra 500MB free for our accounts.

You’ll want to make sure you have Dropbox installed on all of the Mac’s you’ll want to have your settings in sync.

Setup Sync on First System

Here are the steps I took to setup the sync. I did this on my iMac desktop first, then my MacBook Air second (shouldn’t matter which one you do first, just one at a time). Note that this requires you to use the Mac OS X Terminal, or the excellent iTerm2.

  1. Quit Sublime Text 2 if it’s running
  2. Open the Terminal or iTerm2
  3. Change to your Dropbox folder
    cd ~/Dropbox
    
  4. I recommend creating a new folder for Sublime Text 2 to organize everything. I created one for the Application Support folder and one for the Preferences file. This is what I did, but you can use a different path if you want:
    mkdir -p ~/Dropbox/Applications/Sublime\ Text\ 2/Application\ Support
    mkdir -p ~/Dropbox/Applications/Sublime\ Text\ 2/Preferences
    
  5. Now we move your current Preferences file to the new Dropbox folder
    mv ~/Library/Preferences/com.sublimetext.2.plist ~/Dropbox/Applications/Sublime\ Text\ 2/Preferences/
    mv ~/Library/Preferences/com.sublimetext.2.plist.lockfile ~/Dropbox/Applications/Sublime\ Text\ 2/Preferences/
    
  6. Now we need to create a symlink for each of those files. The symlink will be in the ~/Library/Preferences folder where Sublime Text 2 looks for the Preferences file, and will point to the actual copy that’s stored in your Dropbox folder
    ln -s ~/Dropbox/Applications/Sublime\ Text\ 2/Preferences/com.sublimetext.2.plist ~/Library/Preferences/com.sublimetext.2.plist
    ln -s ~/Dropbox/Applications/Sublime\ Text\ 2/Preferences/com.sublimetext.2.plist.lockfile ~/Library/Preferences/com.sublimetext.2.plist.lockfile
    
  7. As you probably guessed, we need to do the same thing with the Application Support folder, move it then symlink it.
    mv ~/Library/Application\ Support/Sublime\ Text\ 2 ~/Dropbox/Applications/Sublime\ Text\ 2/Application\ Support/
    ln -s ~/Dropbox/Applications/Sublime\ Text\ 2/Application\ Support/Sublime\ Text\ 2 ~/Library/Application\ Support/Sublime\ Text\ 2
    

At this point your first computer should be setup to use the Preferences file and Application Support folder (contains your packages, key-bindings, etc) stored in your Dropbox. Go ahead and launch Sublime Text 2, it should open just like before, nothing should be different.

Setup Sync on Second System

Now go to your second system. Install Dropbox if you haven’t already, At this point it’s important to wait for Dropbox to finish it’s sync. If you haven’t already installed Sublime Text 2, go ahead and do that as well, but don’t launch it.

Now let’s setup this second computer to point to the Dropbox versions of the Preference file and Application Support folder.

  1. Quit Sublime Text 2 if it’s running
  2. Open the Terminal or iTerm2
  3. Change to your Dropbox folder
    cd ~/Dropbox
    
  4. If you’ve run Sublime Text 2 on this second computer before, we’ll rename the current Preference file and Application Support folder so that these are saved, but not used. If you’ve never run Sublime Text 2 on this second computer, skip to the numbered step
    mv ~/Library/Preferences/com.sublimetext.2.plist ~/Library/Preferences/old-com.sublimetext.2.plist
    mv ~/Library/Preferences/com.sublimetext.2.plist.lockfile ~/Library/Preferences/old-com.sublimetext.2.plist.lockfile
    mv ~/Library/Application\ Support/Sublime\ Text\ 2 ~/Library/Application\ Support/Old\ Sublime\ Text\ 2
    
  5. Now let’s setup the symlink for the Preference file
    ln -s ~/Dropbox/Applications/Sublime\ Text\ 2/Preferences/com.sublimetext.2.plist ~/Library/Preferences/com.sublimetext.2.plist
    ln -s ~/Dropbox/Applications/Sublime\ Text\ 2/Preferences/com.sublimetext.2.plist.lockfile ~/Library/Preferences/com.sublimetext.2.plist.lockfile
    
  6. Then the Application Support folder
    ln -s ~/Dropbox/Applications/Sublime\ Text\ 2/Application\ Support/Sublime\ Text\ 2 ~/Library/Application\ Support/Sublime\ Text\ 2
    

At this point you should be able to launch Sublime Text 2 on the second computer and have all of your same Preferences, packages and key-bindings setup and installed. Note that I haven’t run Sublime Text 2 on both computers at the same time, so I can’t comment on what this may or may not do.

Displaying PDF Form Fields Using iText and ColdFusion

One of my most recently developed web application is a new health care system for a number of laborites that perform various testing. The initial workflow has the central office receiving the lab test order and sample, entering it into the system, and then sending the sample and five or six (depending on the test ordered) worksheets along to the lab techs. Currently the worksheets that have to be completed are a variety of MS Excel, MS Word and an Adobe PDF file. This can take anywhere between 3 to 8 minutes to complete, depending on which forms are needed and what information is available on the test order. They asked for an easier way to do this.

I decided to explore generating a single PDF file that would be generated after the test order is entered in the system. The fields on the various documents that normally the administrative staff have to fill in would be populated by the web application. Normally this would be easy to do using cfpdfform, however for this project we’re using Railo instead of Adobe ColdFusion and the cfpdfform tag isn’t available. I was hoping that Railo 4 would include this tag as a feature, but there was no mention of it being included at cf.Objective() 2012 by the Railo team when I asked. I’ve asked on the Railo list twice, initially they said yes but most recently they haven’t responded. Therefore I needed to find an alternative solution, which I did, and here’s what I ended up doing.

Create a single Adobe Acrobat PDF Form

The first step was to use Adobe Acrobat Professional to combine the MS Excel, MS Word and Adobe PDF files into a single PDF file. The next step was to create the form fields within the PDF for the web application to populate from the database. Since every page had a “name” field, we just made that field name the same on each page.

Get iText

iText is a Java component that is designed to work with PDF files. It can create, read and update PDF files. The technical documentation on the website is pretty thin, they really encourage you to buy a copy of their “iText in Action” book. I’d have no problem with this, but they don’t currently offer a Kindle version yet so I’m holding off on that. I did find the API documentation is available online that you can use, and they do have the samples from the book available for download that may help.

Download the iText PDF community version from here. I decompressed these files and placed them in the same directory as I had my Railo JAR files, then I restarted Apache Tomcat. I’m pretty sure I could put these in my ColdFusion on Wheels application directory /lib directory and load them using the javaLoader for CFWheels, but I haven’t tried it yet.

CFDump the form fields

The next thing I wanted to do was to dump the form fields from the PDF file to make sure I was able to read the file correctly. I placed the single PDF file that we had created with all of the form fields with my ColdFusion on Wheels application directory. I then created a CFML page and used the following code to dump the form fields that are found within the entire file.


readPDF = expandpath("the_file_name_here.pdf");
writePDF = expandpath("#createUUID()#.pdf");
fileIO = createObject("java","java.io.FileOutputStream").init(writePDF);
reader = createObject("java","com.itextpdf.text.pdf.PdfReader").init(readPDF);
stamper = createObject("java","com.itextpdf.text.pdf.PdfStamper").init(reader, fileIO);
pdfForm = stamper.getAcroFields();


This dumped out a list of all of the form fields within the PDF so I can make sure that iText was able to read them, and that I spelled them correctly.

Populate the Form Fields

The next step was to populate these fields with data from my database. I also wanted to display this PDF in the users browser. I was able to to this pretty much as I did above, but just with a minor changes.


readPDF = expandpath("the_file_name_here.pdf");
writePDF = expandpath("#createUUID()#.pdf");
fileIO = createObject("java","java.io.FileOutputStream").init(writePDF);
reader = createObject("java","com.itextpdf.text.pdf.PdfReader").init(readPDF);
stamper = createObject("java","com.itextpdf.text.pdf.PdfStamper").init(reader, fileIO);
pdfForm.setField("date_sample_collected", "#date_sample_collected#");
pdfForm.setField("patient_name", "#patient_name#");
pdfForm.setField("date_of_birth", "#date_of_birth#");
pdfForm.setField("order_number", "#order_number#");
stamper.setFormFlattening(true);
stamper.close();
reader.close();
fileIO.close();


Summary

Using this code I was able to satisfy the initial request that the administrative staff, to save them from creating these additional forms manually with the data they had just entered into the web application.

I know I can make this better though, since not every page of that PDF is needed, it depends on the test selected. I plan to re-factor this application code in the future to to determine which test was selected, then only grab those worksheets. This means I’ll need to separate each of the worksheets out into a separate PDF file, then stitch them together, depending on what the user has entered for the order, into a single file.

Thanks To

Thanks to this cfSearching blog post that helped, as well as rip747’s Stackoverflow posting that helped me complete this task.

Sunday, May 13, 2012

Using Legacy MS SQL Server 2008 tables with Ruby on Rails Application

On my first Rails application I’m developing against a legacy MS SQL Server database running on MSSQL R2. When I developed this database back in 2001 I didn’t follow any of the Rails “opinions” in terms of column naming. This makes working with the database somewhat difficult.
I found a presentation from the 2009 Rails Conference entitled “Rails + Legacy Databases” which provided some great tips. One of the suggestions for working with a MSSQL database and tables that don’t match the Rails convention is to use a database view to simulate the table with the Rails naming.
I thought this was pretty slick, but I wasn’t able to get it to work at the outset. I contacted the presentation author Brian Hogan a few times via Twitter and he advised meto make sure of two things to make this work: 1.) Make sure the view is updatable, which is a permission you have to make sure the SQL login account that your Rails app is using to connect has. Here’s the SQL code that I used to create the view with the permissions my Rails login needed:
use [hla]
GO
GRANT DELETE ON [dbo].[States] TO [hlaapprailsuser]
GO
use [hla]
GO
GRANT INSERT ON [dbo].[States] TO [hlaapprailsuser]
GO
use [hla]
GO
GRANT SELECT ON [dbo].[States] TO [hlaapprailsuser]
GO
use [hla]
GO
GRANT UPDATE ON [dbo].[States] TO [hlaapprailsuser]
GO
2.) Make use of the
:foreign_key => "state_id"
parameter on your associations.
This ended up working out really nice and saved me time and headache so I thought I would share in case anyone else finds themselves in a similar circumstance.

Wednesday, April 11, 2012

Installing activerecord-sqlserver-adapter on Mac OS X Lion

I’m on Mac OS X 10.7.3 “Lion” and want to develop a Ruby on Rails 3.2.2 application using a MS SQL Server 2008 database. To do this I needed to install the activerecord-sqlserver-adapter which requires TinyTDS. While the gem install activerecord-sqlserver-adapter worked fine, the gem install tiny_tds failed to compile. It required a freetds component.

This took me a while and I ended up having to install Homebrew to get it to work. Here are the steps I took to get this working, hopefully it’ll save others the hour or so I spent trying to get it working.

  1. Install Homebrew Package Manager by using these instructions
  2. Install the FreeTDS component
    brew install freetds
  3. Install the TinyTDS gem
    gem install tiny_tds -- --with-freetds-include=/usr/local/include --with-freetds-lib=/usr/local/lib --with-iconv-include=/usr/local/Cellar/libiconv/1.14/include --with-iconv-lib=/usr/local/Cellar/libiconv/1.14/lib
  4. Now install the SQL Server ActiveRecord gem
    gem install activerecord-sqlserver-adapter

You’ll need to then setup your database.yml file accordingly:

development:
  adapter: sqlserver
  host: 10.1.1.100
  database: mydb
  usernane: user
  password: s3cr3t
  

Tuesday, March 13, 2012

Incorrect string value: ‘\xCE\x94F508…’ for column ‘value’ at row 1

Problem

Last week I was working on importing data from a vendors database into our database and for, what seemed like, random records I’d receive the error message above. Upon further inspection it turned out that the records that weren’t able to be inserted had special characters, like 'Diagnostic, ΔF508 and R117H with 5T/9T'. I knew I had set our MySQL database to use UTF-8 for the collation of the server by default, I’d even posted about it here.

I was able to resolve this, but first just a little background.

Solution

After researching this and even exporting and importing my database, I found that my tables were being created specifically using the latin1 character set. I was able to determine this when I did MySQL dump of my database and examined the CREATE TABLE syntax, as shown below:

DROP TABLE IF EXISTS `addresstypes`; 
CREATE TABLE `addresstypes` 
( `id` int(11) NOT NULL AUTO_INCREMENT, 
`text` varchar(255) DEFAULT '', 
`createdat` datetime DEFAULT NULL, 
`updatedat` datetime DEFAULT NULL, 
`deletedat` datetime DEFAULT NULL, 
`createdby` varchar(25) DEFAULT NULL, 
`updatedby` varchar(25) DEFAULT NULL, 
`deletedby` varchar(25) DEFAULT NULL, 
`rixid` varchar(255) DEFAULT NULL, 
PRIMARY KEY (`id`) 
) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=latin1;

I found three ways to correct this. Here are the first two ways as I found at this blog post.

Single Table

Use the following SQL code block and replace the “database_name” and “table_name” values with your actual database name and table name:

ALTER TABLE `database_name`.`table_name` 
CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;

Multiple Tables

Use the following SQL code block and replace the “database_name” with your actual database name:

SELECT CONCAT('ALTER TABLE `', t.`TABLE_SCHEMA`, '`.`', t.`TABLE_NAME`, '` 
CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;') as stmt 
FROM `information_schema`.`TABLES` t 
WHERE 1 AND t.`TABLE_SCHEMA` = 'database_name' ORDER BY 1

I also found that if I performed a MySQL dump of the database, then replaced the latin1 character set command with utf8, deleted the database and then re-imported it this resolved the issue as well.

Use the following code block and replace the “database_name” with your actual database name. You’ll also need to DROP or DELETE the database after you do the MySQL dump in the first step:

mysqldump -u root -p database_name > database_name.sql 
sed 's/utf8_bin/utf8_unicode_ci/' database_name.sql > database_name_fix.sql 
sed 's/CHARSET=latin1;/CHARSET=utf8;/' database_name_fix.sql > database_name.sql 
mysql -u root -p database_name < database_name.sql

Interesting Note

Interestingly if I copied and pasted the SQL INSERT syntax into the MySQL command-line, before I changed the tables to be UTF-8, the command was successful at inserting the data.

Update: MySQL 5.5.3+ Server Options

These options have changed in MySQL 5.5.3 and newer, in particular the "default-collation" and "default-character-set" server options have been deprecated. Instead, the following server options replace these "collation-server" and "character-set-server"

Thursday, January 05, 2012

Updated Twitter Bootstrap OmniGraffle Stencil

I updated my Twitter Bootstrap CSS ToolKit OmniGraffle stencil with a number of changes.

  • Complete replaced the tables
  • Added helper text below form fields
  • Added a stacked-form section
  • Added a radio button control
  • Made sure all form labels are right-aligned
  • Set all stacked-form labels are left-aligned
  • Added a date range control
  • Increased the size of the textarea
  • Resized the navigation bar to be 940px wide
  • Grouped the pagination control

You can grab the stencil now from my GitHub repo, along with directions on how to update to the latest stencil if you're using the previous version.

Friday, December 16, 2011

Twitter Bootstrap Omnigraffle Stencil

I often use the Twitter Bootstrap CSS ToolKit for my web applications.  While this toolkit helps to make things quickly look great, I wanted to be able to use it in OmniGraffle.  I found a few Photoshop files that had the elements, but none for OmniGraffle, so I decided to try creating one.  This is my first OmniGraffle stencil, but I'm pretty proud of how well it came out.  Thanks to the OmniGroup for such a great product.

You can grab the stencil now from my GitHub repo.

I've submitted the stencil to Graffletopia, but still waiting for their review and approval.

Semantic Versioning

I really like this suggestion on software version formatting and incrementing taken from http://semver.org/
Consider a version format of X.Y.Z (Major.Minor.Patch). Bug fixes not affecting the API increment the patch version, backwards compatible API additions/changes increment the minor version, and backwards incompatible API changes increment the major version.

Sunday, December 11, 2011

Beating the Flying Spaghetti Code Monster with CFWheels - Part 2

Beating the Spaghetti Code Monster

Recap

As I mentioned in part 1 of this post, when I started writing web applications with ColdFusion I quickly amassed a large collection of autonomous files that would often break if I changed a variable or parameter that should be passed into the next. Adding or removing a column to a form / database table could take 25 minutes to update all of the SQL files. I had become enslaved to the “Flying Spaghetti Code Monster”, as I like to call it, and knew there was a better way and wanted to find it.

The Application

As I also mentioned in part 1, I had been re-hired to maintain and update a web application I wrote 7 years prior. This application had well over 350 individual files and the folder size was near 80MB. Although I had started to use the Fusebox framework, which helped start to organize my files, I didn’t follow-through on converting everything to Fusebox. This meant that my directory structure looked something like this
Spaghetti Code Directories

Conversion

As also mentioned in part 1 of this post that I decided to slowly convert the application to the Coldfusion on Wheels framework. I decided to do this cutting off one “tenticle” at a time, or one section/feature at a time.
First I identified a small section of the application that I could replace with the CFWheels framework. I selected one of the “system options” that allows users to add new values to a drop-down list of patient types. The code for this was located off the root of my application in a /system folder along 15 other similiar system options that were almost identifcal. I also needed a place to put my CFWheels core files.
I decided to put the CFWheels framework files in a directory named “hla”, which is the web application name as referred to by the staff, under the /system folder, so /system/hla/
CFWheels framework location
I setup my database connection info in the /conf/settings.cfm file so that my database connection would be the same as the spaghetti code portion. Next, I didn’t want to have two sets of Javascript, CSS or other asset files like images, so I had to modify my CFWheels layout.cfm file to reference the ones that the spaghetti code files were using.
layout.cfm
At this point I could browse to the CFWheels portion, by manually entering the URL, and receive the default CFWheels welcome page. I then added a new entry on my system options menu to point to the new CFWheels location where the system option I was going to convert would live.
At this point I created a model file, Patiettype.cfc, and in the init function I added code to specify my database table names that didn’t follow the Wheels convention, but were used by the Spaghetti Code application
<cfset table("tbl_authors")>
Next I followed with each database table column as a property, using the current database column name for the column attribute but a CFWheels convention name for the name attribute, as outlined in the CFWheels documentation.
<cfset property(name="firstName", column="tbl_auth_f_name")>
These system options required that I setup some associations, and this was a great place to learn about that as I’d need it for every other part of the application.
At this point I could follow the CFWheels conventions and develop the CRUD for the Patienttype just like I would a brand new CFWheels app. After I have the CRUD working for this system option, I’d then remove the link to the old files and leave just the new one. Then I’d have the users work with that section for about a week. Once we were sure everything worked correctly, I’d slowly remove the old files (that I now had in Git version control).
Using this same method I slowly worked through all of the 16 system options, as if cutting off one “tenticle” of the Spaghetti Monster at a time. After I finished with those small, simple CRUD actions, I moved onto more complicated sections. The whole Contacts portion, then Hospitals portion, etc.

Progress

I found the Coldfusion on Wheels framework in February 2011, then started implementing it in March 2011, working part-time and slowly through each of the tenticles I mentioned. If new features were requested, or something needed to be changed, I fought the urge to do a “quick and easy” one or two file solution and forced myself to do it the CFWheels way. At first this was challenging, but once I got use to it, the changes happened faster.
At this point, December 2011, I’ve removed at least 23 of these “tenticles” with two medium sized tenticles and one large tenticle left to remove from the monster. I’m excited to finish these sections off and sever the head of this monster once and for all. In hindsight I’m glad I started with smaller tenticles as it allowed me to learn CFWheels with smaller sections of code, but also to find “gotchas” early on.

Gotchas

One of the things I didn’t expect was the Spaghetti Monsters session scope being overwritten when I moved went to a CFWheels framework page. This made it a little tricky because I’d use the session scope to retain the currently logged in user ID and if they were a valid user or not (to prevent unauthorized access). After I’d leave a CFWheels page and go back to the Spaghetti Monster code I’d be kicked out of my application. My “fix” for this, at least for the time being, was to use client variables for the Spaghetti code portion of the application and session variables for the CFWheels portion of the application.
The next thing I ran into, since my session scope was being overwritten, was once I moved to a CFWheels portion of the application I’d didn’t have my session variable with the user ID from the Spaghetti Monster code. To fix this I added an obtuse URL variable on the menu links in the Spaghetti Monster code that CFWheels would then use to identify the user and create the session scope variables I wanted.

Summary

I feel converting this application to the CFWheels framework has helped with the following:
  1. Brought some sanity back to how this application is structured and maintained (huge benefit)
  2. Saved gobs of time not having to maintain query files with endless CFIF statements and cfqueryparam tags (CFWheels ORM does that all for me, huge benefit)
  3. Made the application run faster, I mean noticably faster to my users
  4. Decreased the code folder from 80MB to 33MB
  5. Allows me to add new features or make changes in less time then before because things break less when changes are made
  6. Allows anyone that knows about the MVC pattern to help or take over this application
  7. Made Coldfusion programming fun again (most important of course)
While converting this application from the Spaghetti code to the CFWheels framework from “the inside out” has been a slow process (because of my, not the framework), I don’t regret doing it at all for the reasons stated above. It’s been a great way to learn CFWheels and to work with the CFWheels community. At this point I can’t imagine developing Coldfusion applications without using the CFWheels framework.

Tuesday, October 04, 2011

Force Internet Explorer 8 Not To use “Quirks” Mode

I’ve been using the excellent BluePrint CSS framework for a new web application I’m developing. It does a great job and making the site look very good, and consistent, on almost all browsers except Internet Explorer (I know, huge surprise).

In my particular case I have users that are forced to use Internet Explorer 8.0 as their browser. With the configuration that’s set by default for them, Compatibility View is enabled because the University Enterprise Business software doesn’t display correclty on modern browsers or recent versions, meaning anything newer then Firefox 3.6 or Internet Explorer 6.0.

To compound the annoyance, Internet Explorer Compatibility View can’t be set for one particular site only, it assumes that all pages under the domain also need it and forces this as well with no option to only use or exclude a subdomain.

When Internet Explorer 8.0 uses Compatiblity View, it renders the webpage as Internet Explorer 7.0 and earlier would, also called “quirks” mode, which doesn’t display correctly with BluePrint CSS or other web-standard layouts. I found that I can add HTML code to force Internet Explorer not to use Compatibility View on my web application. Not using Compatibility View uses the newer rendering engine that does a slightly better job with the newer HTML standards.

To do this, add the following to your HTML header:

<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE8">