Posts

Tracking Events and Properties Naming Conventions and Best Practice

Tracking has 2 parts, the event and the properties of the event and captured together will tell you what users are doing. Data Step 1 Event Naming Best Practice: Object & Action in past tense with "Title Casing" and spacing, eg "Product Added" where Product is the Object and Added is the Action Data Step 2 Event Property: Be consistency, use nouns and use snake_case (just stay that way), and do not nest properties, most downstream providers can use nested properties. This is what tells us what people are doing on the event.  Data Step 3 As a further clarity and to avoid having hundreds of events, the event names should be generalized and then the properties should be used for specificity, else you could end up with lets say  Product Added from Contact Page Product Added from List Page Product Added from Recommendation Or  just "Product Added", with a property of say "source" Think an example like this:  Event Name "Product Added" Pr...

Lucee vs Adobe ColdFusion columnList vs getColumnList vs getmetadata

I have a general section which dynamically displays reports, which are preconfigured in a certain way.  There are some totals and data rows which are not part of the metrics so net result is I had some CF code looking at the column lists and displaying appropriately.  Turns out there are very different results between Lucee and Adobe Coldfusion, for this example, it's important to create a sample table like so:  CREATE TABLE testtable( [Col1] [varchar](50) NULL, [ACol2] [varchar](50) NULL ) so that ACol2 is actually alphabetically before Col1.  Then run this <cfquery datasource="aTestDSN" name="qry"> select * from testtable </cfquery> <cfset columns = ""> <cfloop array="#getmetadata(qry)#" item="aryItem"> <cfset columns = listappend(columns, aryItem.Name)> </cfloop> <table> <tr><td>getmetadata</td><td><cfoutput>#columns#</cfoutput></td></tr...

Hold on, did I say you could email me? Subscriptions, abandon carts

Card Abandonment processes and the law We've all been on a website, added something to cart, maybe even started the checkout where you (gasp) put your email or cellphone and are about to pay when ... life gets in the way. Now, what happens next... the busy marketer on the website has been in contact / went to lunch with a cool start up which has learnt how to capture keystrokes on the web page and has unknowingly to you saved your details to a 3rd party system in possibly another country with different laws, and different protection. The plan... hit you up with a marketing email phrased as an cart abandonment, even may through in a 10% discount code. What does GDPR have to say about this? Who knows, probably something - but it's a long document. What does the busy marketer have to say? Nothing, wasn't aware it was a problem, that guy I met lunch said it was good and it only costs me $1500 a month and he said I could get 10 times my investment back. Let's loo...

Email lists, bulk emailing, the SPF, DKIM, DMARC, SNDS or JMRP who knows

Is it the SPF? Is it DKIM, SNDS or JMRP, its DMARC right, no wait.. damn, just who knows.  So your trying to send an emails a lot, or an bulk email and whoops, it's not right. Anyway, here's the 10 point plan that can help Step 1 SPF Make sure your SPF only lets who you say can send email on your behalf. Step 2 DKIM DKIM (Domain Keys Identified Mail) - bit tricky and hard to handle the responses, but if there google will love you especially at the their postmaster tools area  https://postmaster.google.com/ . Step 3 SNDS and JMRP SNDS (Smart Network Data Services) & JMRP Junk Mail Reporting Program- this is sort of the same thing now. Step 4 DMARC Yep, that too - Domain-based Message Authentication, Reporting & Conformance Step 5 Static IP If you can, get your own IP, take it slow and warm it up and don't let anyone else use it. Step 6 Wait, where did I get these emails? Your going to ensure that as you build your list that it grows properl...

All star rich snippets review for a listing vs a review page

The question Suppose you have a listing page/ search results screen. Suppose you have dozens of reviews for your products. Should you pop those said reviews on the listing page? After all the listing page is even more dull and less likely to change than the product, so wouldn't reviews be great in there? The desired result At the end of the day, the main reason for reviews and rich snippets on Google SERP is .... to get people to click through. Facts: The most important factor for organic traffic is SERP ranking CTR on paid search DOES NOT impact SERP rankings. Stars/ price rich snippets will impact CTR So mainly if a listing page may not have rich snippets, then you won't get data structure (outside of things like site links) Unknown Facts It's a general hypothesis that bounce rates, time on site and conversion rates impact the best user experience. So, if users click onto a site because of compelling rich snippets and then awe sucks that's crap, b...

Bulk checking of URLs for status codes with headmasterseo

I'm always after bulk checking of URL status and what should/ shouldn't be happening on a site, given all the redirects/ logic/ status of products etc. headmasterseo.com/  is a great tool that can quickly check URLs in bulk for status code, redirect details, response time, response headers and HTTP header fields. Free for 500 urls and really not that expensive for bigger plans. Bear in mind, it can crash servers due to the way it seems to run in parallel, so if your server has unknow exposure to this, your boss won't be happy as you'll have just DOSd the live site!

Social Media Logins and Account based systems

So you want a sign in account based thingo for your Acme website with the old social logins and maybe even a roll your own one for those who don't trust your linking to any of these social companies. Seems simple enough, but there are some interesting side things that can happen. Suppose you are on Facebook, Google and Hotmail (whatever it's called) even Twitter and Linkedin. If you are one of those types who has a different email for each service, then thanks and good luck that's your problem, every time you sign up/in, you'll be given a new account by our Acme company. If you do have an email address that follows you round, then shouldn't you not care about who is validates that it's you? Sure, you shouldn't care, so said user then doesn't need to remember whether they signed on with Facebook / Google/ Linkedin or whatever. So how do we achieve that? well at some point, you have to have 1 metric which you deem to be the identifier. Not nece...

ArraySum in Lucee for Query Total and ValueList

Over at Lucess's Atlassian bug board is a reported which I come across all the time in cross compatibility between ACF and Lucee  https://luceeserver.atlassian.net/browse/LDEV-544 I'm not a fan of proprietary functions like queryColumnData, so the easiest equivalent for both to work is : arraysum(listtoarray(valuelist(qryObject.columnname))) Not as neat as the old ArraySum(qryObject["columnname"]), but who cares, I only seem to use it for table totals anyway!

Oh dear, a dodgy old piece of code in ColdFusion 8 style with local scopes!

A seldom used piece of code fell victim to the "new" ColdFusion "Local scope" from CF 9 (Centaur) With an Application.cfc; naturally everything inside it is local'ish when the onRequest exists: <cfcomponent displayname="Application" output="true" hint="Handle the application.">     <cffunction name="OnRequestStart" access="public" returntype="boolean" output="false">         <cfargument name="TargetPage" type="string" required="true"    />         <cfreturn true />     </cffunction>     <cffunction name="OnRequest" access="public" returntype="void" output="true">         <cfargument    name="TargetPage" type="string" required="true" />         <cfinclude template="#arguments.TargetPage#" />         <cfret...

Lucee 4.5.2 cfhttp inconsistent timeout response with Adobe Coldfusion

Trying to catch a timeout is alwas a problem, particularly on those jumpy sites that are normally ok, but can be offline for an hour or 2 when the owners is asleep! There is a bug here https://luceeserver.atlassian.net/browse/LDEV-80 but it is not quite the same and I do get a correct response if in the example below sleep(4000) was replaced by a=1/0; Suppose a file like so: <cfif structkeyexists(url, "test")>     <cfscript>sleep(4000);</cfscript> <cfelse> <cftry>     <cfhttp timeout="2" url="http://#cgi.http_host##cgi.script_name#?test" throwonerror="true" result="x" />     <cfcatch type="any">        <cfdump var="#x#" />         <cfdump var="#cfcatch#" />     </cfcatch> </cftry> </cfif> Lucee 4.5.2 produces Struct errordetail string while the cfcatch adds in this s...

Lucee 4.5.2 cfparam null value error with full null support

With cfparam and the full null support (non default behaviour) there is a dodgy impact: Suppose qryDB has a null valued column, and you set a variable to that null value <cfparam name="myVar" default="#qryDB.nullValueColumn#"> This throws an error, same as would happen in this instance; <cfparam name="myVar"> Though the later appears to be inconsistently present in Adobe ColdFusion also; http://blog.adamcameron.me/2013/04/coldfusion-bugs-id-like-to-see-dealt.html

Lucee 4.5.2 cfpdfparam difference with Adobe ColdFusion

Suppose the following on Lucee 4.5.2: <cfset x = 1> <cfdocument format="pdf" pagetype="A4" name="myVar#x#"> <cfdocumentsection> Hi there </cfdocumentsection> </cfdocument> <cfpdf action="merge" destination="RAM:///myPDF.pdf" overwrite="yes">     <cfpdfparam source="#evaluate("myVar#x#")#" /> </cfpdf> <cfcontent file="RAM:///myPDF.pdf" type="application/pdf"> then to check it also runs on Adobe Cf; you'd actually end up with: "ByteArray objects cannot be converted to strings."   The original code for Adobe CF ran with the paramater like so:  <cfpdfparam source="myVar#x#" /> Both sets of documentation list source defined as follows: "Source PDF file to merge. You can specify a PDF variable, a cfdocument variable, or the pathname to a file." This would indicate it is just...

Global SQL Procedure, System Objects and sp_ms_marksystemobject

You may come across a need to have a database of utils full of generic procedures which work on indvidual databases (say client databases). You can't pass the database name into the procedure as a parameter and say "use @dbname" in the procedure and dynamic sql sucks. One workaround is to create the procedure in the master database and then mark it as a system object. eg use [master] create procedure sp_doThis // note the sp_ prefix is required begin // etc etc end go exec sp_ms_marksystemobject 'sp_doThis' // second note, this procedure is undocumented, so I wouldn't be relying on this for life or death. use [myotherdb] exec sp_doThis go All done!

Design best practice for an image library

If the library holds data in a raw format (ie a big sized image), then can then make all sorts of algorithms out of that to produce images. Generate different sizes, eg 100x100, 200x400 or what ever is required from the original Generate different types of images, either by conversion (png etc) or type, maybe base 64 for CSS and separate style sheet images for non base64 supporting CSS (like IE8 etc) Overlay another graphic on top (like a sash or otherwise) to generate only 1 image that needs to be retrieved All of this requires the smarts that you allow the original image to have coordinates stored against it as to where the center is or maybe use something like  https://github.com/tapmodo/Jcrop to create and store these coordinates of the box sizes. I've found it quite useful when uploading images through custom application to write the files as (for example) full_raw.png (usually stored in a database somewhere) full100x100.png (resized, re scaled depending how ...

Nice Table sorter (Jquery)

Ok so there are quite a few out there, but I've never seen one which I've had to do absolutely no customization at all; well done https://editor.datatables.net/ . Very nice exporting to CSV, great sorting, great custom display and filtering (allowing tables to be summed up depending on what you filtered on). Honorable mention http://tablesorter.com/docs/ I used this for quite a while, but the datatables has the exports and filtering which I had to write an extension of for tablesorter.

Diffie-Hellman limit issues with java 1.7 and Connection Failure

Suppose calling a https url. Error is was returning: ErrorDetail    I/O Exception: peer not authenticated Filecontent    Connection Failure Mimetype    Unable to determine MIME type of file. Statuscode    Connection Failure. Status code unavailable. Debugging this ended up with with an error like so: javax.net.ssl.SSLException: java.lang.RuntimeException: Could not generate DH keypair Added certificate of the URL to the cacerts file with keytool No luck Changed to unlimited strength like so http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html No luck Added this to JVM 1.7 config (not sure this is even supported) -Djdk.tls.ephemeralDHKeySize=2048 No luck Tried switching to JVM 1.8 config; -Djdk.tls.ephemeralDHKeySize=2048 No luck Added DH to in java.security disabledAlgorithms jdk.certpath.disabledAlgorithms=MD2 ,DH Bingo Given that Diffle-Hellman key exchange of 1024 can be possibly broken, this...

JVM 1.7 and Coldfusion and Connection Failure

A lot of connection failures were showing up due to servers upgrading their certificates to the latest and greatest versions (256 bit) which (by the looks of things) weren't really working on Java 1.6 (128bit). Anyway, to upgrade CF 9 to 1.7 (1.8 not supported and the server monitor stopped working if this was done); installed Java 1.7, opened up the jvm.config for ColdFusion and changed the path for java.home. Copy of msvcr100.dll from JDK\bin in JRun4\bin Restarted the service and all went well. Then it fell over! Then I restarted the service. Then it fell over... Turns out, need to remove -XX:MaxPermSize=192m  from the jvm params, else preapre for some see sawing! Also, good idea to use the  -Duser.country= &  -Duser.language= parameters if required, as I ended up constantly getting US set up (despite the OS saying otherwise) Any other Connection Failure issues with these new certificates were resolved by importing missing chains using keytool . ...

keytool & importing new certificates / missing chains for Java

Everyonce in a  while new root certificates come out that ain't trusted by your server. JRun4\jre\bin\keytool -import -keystore \JRun4\jre\lib\security\cacerts -file \somenewcertificate.crt See these links also for the issues these caused with ColdFusion  https://docs.google.com/document/d/12Ef1SwddMh0oO11TS3lt5E8VGiVCsdI8WmYn8qQLW4c/edit# https://bugbase.adobe.com/index.cfm?event=bug&id=3041494    Remember also if using Coldfusion with a different JVM version, the cacerts is in the JVM version!

RDP SSL Causes PCI Compliance to fail

Found another issue crop up with a firewall rule change that opened up and RDP availability RDP should be configured using strong encryption methods or use SSL as the privacy and integrity provider. To configure RDP encryption methods, launched in mmc.exe to run the  'Terminal Services Configuration' or 'Remote Desktop Session Host Configuration' snap-in. The 'Terminal Services Configuration' or 'Remote Desktop Session Host Configuration' properties dialog box General tab for the Encryption Level 'High' should be selected. See more here for Windows 2008 R2 basically Start> Administrative Tools> Remote Desktop Services> Remote Desktop Session Host Configuration Click on Connection Click General Tab Change Security FROM Negotiate to SSL(TLS 1.0) Click Encryption Level to “High” A restart may be required (hopefully you won't get kicked out)

cf_sql_timestamp vs cf_sql_date vs getdate()

If there's one thing I don't like it is people confusing a date with a timestamp, and how a lazy bit of development can ruin a load of data. Here is a simple query inserting data to a timestamp I found in a system where all the created dates were truncated because of the incorrect syntax. Bad one which was in use: insert into testdate values (<cfqueryparam cfsqltype="cf_sql_date" value="#createodbcdatetime(now())#">); Result :  2015-09-29 00:00:00.000 Best One (easiest to read) insert into testdate values(getdate() ); Result : 2015-09-29 10:10:09.880 Not great (no binding) insert into testdate values(#createodbcdatetime(now())#); Result :  2015-09-29 10:14:44.000 What the bad one should have been insert into testdate values(<cfqueryparam cfsqltype=" cf_sql_timestamp " value="#createodbcdatetime(now())#">)