Tuesday, May 22, 2018

Changing Chrome Policies for Testing

I recently ran into a situation where I was pretty sure that a group policy was breaking functionality on my intranet app, but I needed a way to test that theory. After some research, I finally figured out a way to do this.

I am working on an Oracle Virtual Box VM of Windows 7. Because it's a VM on my laptop, I have complete control over the operating system. To set the policy, I used the Windows Registry Editor regedit.

Within Computer\HKEY_CURRENT_USER\Software\Policies, I created a new key called Google. Then within Google, I created a new key called Chrome.

From there, I just needed to add policies one by one until I figured out which one was breaking my app. The link at https://www.chromium.org/administrators/policy-list-3 provides a full list of policies. After saving a policy, I would restart Chrome and the new policy would be enabled. Sure enough, I found the culprit. By toggling this policy and restarting Chrome I could verify that the application worked and then broke with each change of the policy.

Example of Chrome policy set in Windows registry

Tuesday, April 24, 2018

Stopping a page redirect to look at JavaScript console

I am currently assisting another developer troubleshoot an issue he's having. In the code, there is a JavaScript function call tied to the onclick event of the HTML link. Because the JavaScript code is failing, the page is redirecting before I have a change to look at the console log to see what the error is. One solution is to use a breakpoint in the code and that's what I'll ultimately do. But I found this great hack.

window.addEventListener("beforeunload", function() { debugger; }, false)

By running this code in the console first, it will pause execution and allow me to see the error in the console.

Wednesday, October 11, 2017

Rollback with CFTRANSACTION

You may be surprised to find out that software documentation is not always clear or complete. Shocking, I know. Even when it is, sometimes I just have to see things in action for myself. This is one of those cases.

A question came up today at work about the <cftransaction> tag. (Yes, we still use ColdFusion. There are dozens of us. Dozens!) The question was if the tag would automatically rollback changes or if you needed to explicitly type <cftransaction action="rollback"> to rollback the changes. I have always assumed the latter.

So here is my test case. First I created 2 test tables in the database for testing each with a test record.
CREATE TABLE test_table_1 (
  tt1_record_id NUMBER(3) NOT NULL,
  tt1_text VARCHAR2(100),
  CONSTRAINT pk_test_table_1 PRIMARY KEY (tt1_record_id)
);

CREATE TABLE test_table_2 (
  tt2_record_id NUMBER(3) NOT NULL,
  tt2_text VARCHAR2(100),
  CONSTRAINT pk_test_table_2 PRIMARY KEY (tt2_record_id)
);

INSERT INTO test_table_1 (
  tt1_record_id,
  tt1_text
)
VALUES (
  1,
  'Blue'
);

INSERT INTO test_table_2 (
  tt2_record_id,
  tt2_text
)
VALUES (
  1,
  'Triangle'
);
And now the ColdFusion code. This block of code first outputs the text from the database. Then it updates the first table while intentionally failing to update the second table. Lastly, it displays the text from the database.
<cfquery name="variables.qryBefore" datasource="#application.dsn#">
SELECT
  tt1_text, tt2_text
FROM
  test_table_1,
  test_table_2
WHERE
  tt1_record_id = tt2_record_id
</cfquery>

<p>
    <cfoutput>
        Before: 
        #variables.qryBefore.tt1_text#
        #variables.qryBefore.tt2_text#
    </cfoutput>
</p>

<cftry>
    <cftransaction>
        <cfquery name="variables.qryUpdate1" datasource="#application.dsn#">
            UPDATE
                test_table_1
            SET
                tt1_text = 'Red'
            WHERE
                tt1_record_id = 1
        </cfquery>

        <cfquery name="variables.qryUpdate2" datasource="#application.dsn#">
            UPDATE
                test_table_2
            SET
                tt2_text = 'Square'
            WHERE
                foo = bar
        </cfquery>
    </cftransaction>
    <cfcatch type="any">
        <p>
            Database update failed.  Changes should have been rolled back.
        </p>
    </cfcatch>
</cftry>

<cfquery name="variables.qryAfter" datasource="#application.dsn#">
SELECT
  tt1_text, tt2_text
FROM
  test_table_1,
  test_table_2
WHERE
  tt1_record_id = tt2_record_id
</cfquery>

<p>
    <cfoutput>
        After: 
        #variables.qryAfter.tt1_text#
        #variables.qryAfter.tt2_text#
    </cfoutput>
</p>
The database values remained the same. The first table was updated but when the second table failed to update, the changes were rolled back. I could have added <cftransaction action="rollback"> to the <cfcatch> block and gotten the same result.

So why use the rollback command then? You may only want to rollback to a certain savepoint. Another use case I have found for it is unit testing. In my test, I want to execute the entire method even the database code. However, before I leave the <cftransaction> block, I rollback my changes:
<cfif this.testing>
 <cftransaction action="rollback" />
</cfif>

Wednesday, April 5, 2017

Clipboard Managers

I do a lot of copying and pasting. A lot. One of the things that often happens is that I copy a piece of information, paste it, copy something else, paste it, then need to go back to that previous information I copied. Or maybe I need to copy two (or more) pieces of information from one source before switching to the other source. The best way to handle this is with a clipboard manager. These tools allow you to keep a history of everything you have copied (up to a limit) and the refer back to them. Here are a couple that I have used in my job:

ClipMenu for MacOX (Updated 12/06/18 with new link)
Ditto for Windows

Thursday, March 9, 2017

ColdFusion 2016 Broke My API (And How I Fixed It)

While on ColdFusion 9, I built a REST API for our an application at work. Everything was working fine until we upgraded to ColdFusion 2016. When I went to test the API, I got an HTTP 500 error. The Apache log gave me no clues to what was happening, so my next stop was the ColdFusion logs. In the exception log, I found this:
Error","ajp-nio-8015-exec-9","03/09/17","07:22:12",,"Application  could not be found. The specific sequence of files included or processed is: '''' "
javax.servlet.ServletException: Application  could not be found.
        at coldfusion.rest.servlet.CFRestServlet.invoke(CFRestServlet.java:512)
        at coldfusion.rest.servlet.RestFilter.invoke(RestFilter.java:60)
        at coldfusion.filter.ExceptionFilter.invoke(ExceptionFilter.java:94)
        ...
A quick Google search did not reveal much. However, the fact that it was calling the CFResetServlet gave me an idea. What if the /api directory now had special meaning? So I renamed the /api directory to /API-TEST and sure enough my code was working again.
I found the solution in the web.xml file:
    <servlet-mapping id="coldfusion_mapping_16">
        <servlet-name>CFRestServlet</servlet-name>
        <url-pattern>/api/*</url-pattern>
    </servlet-mapping>
This mapping is forcing everything in the /api directory to be processed by the ColdFusion REST service. To fix this, I simply commented out this section of the configuration and restarted the ColdFusion service.
    <--
    <servlet-mapping id="coldfusion_mapping_16">
        <servlet-name>CFRestServlet</servlet-name>
        <url-pattern>/api/*</url-pattern>
    </servlet-mapping>
    -->

Friday, October 28, 2016

Chicken and Sausage Gumbo Recipe

Today I take a break from my usual tech blog posts to post a recipe. However, this is still tech-related as I am exploring the recipe schema to post this. If my code works, then the recipe should be formatted better for Pinterest, search engines, and recipe applications.

Chicken and Sausage Gumbo

Ingredients

  • 1/2 Cup Cooking Oil
  • 1/2 Cup Flour
  • 1 White Onion
  • 1 Bell Pepper
  • 4 Stalks Celery
  • 2 32-oz Cartons of Chicken Stock
  • Tony Chachere's Creole Seasoning (To taste)
  • 2 Bay Leaves
  • 1 Package Chicken Breasts
  • 1 Package Andouille Sausage*
  • Cooked Rice

Cook Time

Instructions

  1. Cut up chicken breasts into chunks and place into a bowl. Season with creole season, cover bowl, and put in refrigerator.
  2. Chop onion, bell pepper, and celery. Set aside.
  3. In a heavy 4-quart pot or Dutch oven, warm cooking oil over medium to medium-low heat.
  4. Add flour to oil and stir continuously until roux becomes a dark brown color. Do not burn. If black flecks appears, you will need to start over. It will take approximately 30 minutes to get a nice brown color.
  5. Add vegetables and cook in roux until onions begin to wilt.
  6. While stirring the mixture, slowy pour in chicken stock. Bring to a boil and then reduce to a simmer.
  7. Stir in seasoning and bay leaves. Adjust to taste.
  8. Carefully add meat to gumbo.
  9. Cut up sausage and add to gumbo
  10. Simmer gumbo for 1-2 hours or until chicken is tender
  11. Serve over cooked rice. Goes well with French bread and deviled eggs

* I prefer a real smoky sausage from a local smokehouse for the rich flavor but I usually do not have time to get that. So I like to buy Holmes Andouille sausage at the grocery store because it has a nice flavor and it is not greasy at all.

Thursday, October 6, 2016

Format JSON String in ColdFusion

I am sure this has probably already been done but I couldn't find it quickly with a Google search. So I wrote my own. This function takes a JSON string and indents it to make it more readable.
<cffunction name="indentJSON" hint="Indents JSON to make it more readable">
    <cfargument name="JSONString" default="" hint="JSON string to be formatted">
    <cfargument name="indentCharacters" default="#Chr(9)#" hint="Character(s) to use for indention">

    <cfset local.inQuotes = false>
    <cfset local.indent = 0>
    <cfset local.returnString = "">
    <cfset local.stringLength = Len(arguments.JSONString)>
    <cfloop index="i" from="1" to="#local.stringLength#">
        <cfset local.currChar = Mid(arguments.JSONString, i, 1)>
        <cfif i lt local.stringLength - 1>
            <cfset local.nextChar = Mid(arguments.JSONString, i + 1, 1)>
        <cfelse>
            <cfset local.nextChar = "">
        </cfif>
        <cfif local.currChar eq '"'>
            <cfset local.inQuotes = !local.inQuotes>
        </cfif>
        <cfif local.inQuotes>
            <cfset local.returnString = local.returnString & local.currChar>
        <cfelse>
            <cfswitch expression="#local.currChar#">
                <cfcase value="{">
                    <cfset local.indent = local.indent + 1>
                    <cfset local.returnString = local.returnString & "{" & Chr(10) & RepeatString(arguments.indentCharacters, local.indent)>
                </cfcase>
                <cfcase value="}">
                    <cfset local.indent = local.indent - 1>
                    <cfset local.returnString = local.returnString & Chr(10) & RepeatString(arguments.indentCharacters, local.indent) & "}">
                    <cfif local.nextChar neq ",">
                        <cfset local.returnString = local.returnString & Chr(10)>
                    </cfif>
                </cfcase>
                <cfcase value="," delimiters="Chr(0)">
                    <cfset local.returnString = local.returnString & "," & Chr(10) & RepeatString(arguments.indentCharacters, local.indent)>
                </cfcase>
                <cfcase value=":">
                    <cfif local.nextChar neq " ">
                        <cfset local.returnString = local.returnString & ": ">
                    </cfif>
                </cfcase>
                <cfdefaultcase>
                    <cfset local.returnString = local.returnString & local.currChar>
                </cfdefaultcase>
            </cfswitch>
        </cfif>
    </cfloop>

    <cfreturn trim(local.returnString)>
</cffunction>
And here's an example:
<cfset variables.testObject = {}>
<cfset variables.testObject.name.first = "Chad">
<cfset variables.testObject.name.last = "Armond">
<cfset variables.testObject.title = "Software Developer">

<cfset variables.testString = SerializeJSON(variables.testObject)>

<cfoutput>
    <h1>With Tabs (Default)</h1>
    <cfset variables.json1 = indentJSON(variables.testString)>
    <pre>#variables.json1#</pre>

    <h1>With Spaces</h1>
    <cfset variables.json2 = indentJSON(variables.testString, "    ")>
    <pre>#variables.json2#</pre>
</cfoutput>
And the results:

With Tabs (Default)

{
 "NAME": {
  "LAST": "Armond",
  "FIRST": "Chad"
 },
 "TITLE": "Software Developer"
}

With Spaces

{
    "NAME": {
        "LAST": "Armond",
        "FIRST": "Chad"
    },
    "TITLE": "Software Developer"
}
 
Blogger Templates