Generating a Cybersource Flex Key using ColdFusion

Cybersource is a payment provider with poor examples and poor documentation. I struggled through this for about 25 hours before I found the right combination of settings.

First you need to include the cybersource-rest-client-java and AuthenticationSDK jars on your classpath. You can do this by adding the following to your Application.cfc or by dropping them into the \cfusion\lib folder

this.javaSettings = {LoadPaths = [".\libs\cybersource-rest-client-java-0.0.35.jar", ".\libs\AuthenticationSdk-0.0.17.jar"], loadColdFusionClassPath = true, reloadOnChange = false};

I’ve created a struct to house the default Cybersource credentials as the sample environment. You’ll want to replace test and production with your credentials, ideally pulling them from secrets and not hardcoded and placed into source control. The second parameter is your target origin, which varies by environment and potentially by user workstation as well.

writeDump(retrieveFlexKey('sample', 'http://localhost:8500'));

public String function retrieveFlexKey(String environment, String targetOrigin) throws Exception {

  var flexPublicKey = "NoKeyReturned";

  var environmentDetails = {
    sample: {
      merchantID: "testrest",
      runEnvironment: "",
      merchantKeyId: "08c94330-f618-42a3-b09d-e1e43be5efda",
      merchantsecretKey: "yBJxy6LjM2TmcPGu+GaJrHtkke25fPpUX+UY6/L/1tE="
    test: {
      merchantID: "testrest",
      runEnvironment: "",
      merchantKeyId: "08c94330-f618-42a3-b09d-e1e43be5efda",
      merchantsecretKey: "yBJxy6LjM2TmcPGu+GaJrHtkke25fPpUX+UY6/L/1tE="
    production: {
      merchantID: "testrest",
      runEnvironment: "",
      merchantKeyId: "08c94330-f618-42a3-b09d-e1e43be5efda",
      merchantsecretKey: "yBJxy6LjM2TmcPGu+GaJrHtkke25fPpUX+UY6/L/1tE="

  try {
    var details = structKeyExists(environmentDetails, environment) ? environmentDetails[environment] : environmentDetails['sample'];
    props = createObject('java', 'java.util.Properties');
    props.setProperty("authenticationType", "http_signature");
    props.setProperty("merchantID", details['merchantID']);
    props.setProperty("runEnvironment", details['runEnvironment']);
    props.setProperty("merchantKeyId", details['merchantKeyId']);
    props.setProperty("merchantsecretKey", details['merchantsecretKey']);

    requestInfo = createObject('java', 'Model.GeneratePublicKeyRequest');

    merchantConfig = createObject('java', 'com.cybersource.authsdk.core.MerchantConfig').init(props);
    apiClient = createObject('java', 'Invokers.ApiClient');
    apiClient.merchantConfig = merchantConfig;

    keyGenerationApi = createObject('java', 'Api.KeyGenerationApi').init(apiClient);
    response = keyGenerationApi.generatePublicKey("JWT", requestInfo);

    responseCode = apiClient.responseCode;
    status = apiClient.status;
    if (responseCode == '200' && status == 'OK') {
      return response.getKeyId();
  } catch (Exception e) {
    // you'll want to login any errors somewhere

  return flexPublicKey;

read more

Cypress - Failed to deserialize the snapshot blob

Trying to run npx cypress open and I received an error of

It looks like this is your first time using Cypress: 8.2.0

Cypress failed to start.

# Fatal error in , line 0
# Failed to deserialize the V8 snapshot blob. This can mean that the snapshot blob file is corrupted or missing.

Deleting node_modules and running npm install had no effect, but I was able to get it working again running npx cypress install --force.

If that doesn’t work you can also rename the Cypress cache folder. On windows it’s \AppData\Local\Cypress\Cache\<version>

read more

Converting a Roth IRA to a Traditional IRA at Vanguard

I mistakenly put money into my Traditional IRA at Vanguard this year instead of my Roth IRA. I couldn’t for the life me find directions on how to change this, so I called Vanguard. It’s actually very simple.

  1. Login to your account
  2. Click on FORMS in the header
  3. Click Add or remove money, trade within your account
  4. Click Remove excess distributions or contributions, convert from a traditional to a Roth IRA, or recharacterize contributions Click Remove excess contributions, convert assets, or recharacterize contributions
  5. Fill out the rest of form

Disclaimer: I’m not a tax professional, just a dude who messed up his contributions.

read more

Concourse build angular app on pull request with cache

  - name: pull-request
    type: registry-image
      repository: teliaoss/github-pr-resource

  - name: pull-request
    type: pull-request
    icon: source-pull
    check_every: 8760h
    webhook_token: ((webhook-token))
    public: true
      repository: ((your-repository))
      access_token: ((access-token.git-access-token))

  - name: test-pull-request
      - get: pull-request
        trigger: true
        version: every
      - put: pull-request
          path: pull-request
          status: pending
      - task: unit-test
          platform: linux
            type: registry-image
              repository: node
              tag: alpine # you can use any node image, alpine is the smallest
            - name: pull-request
            path: /bin/sh
              - -exc
              - |
                npm config set cache $(pwd)/.npm --global
                cd pull-request
                export NG_CLI_ANALYTICS=false
                # execute whatever commands you need here
                npm install --quiet
                npm run build:test
            - path: .npm
            - path: pull-request/node_modules
          put: pull-request
            path: pull-request
            status: failure
      - put: pull-request
          path: pull-request
          status: success

Github webhook URL - https://${concourse-url}/api/v1/teams/${concourse-team-name}/pipelines/{pipeline-name}/resources/pull-request/check/webhook?webhook_token=((webhook-token)) ((webhook-token)) can be anything you want it to be as long as it’s used consistently in your webhook URL and in your pipeline

read more

Concourse rename job and retain history

To rename a Concourse job and retain history, you can use the old_name attribute.

  - name: build-8-jdk-centos
    old_name: 8-jdk-centos

Once you’ve fly’d the pipeline with the new and old_name attributes you can remove old_name and fly it again, it’s no longer needed.

A good reason to rename a job would be because of recent concourse deprecations with valid identifiers. Our existing job started with a number, which will stop being allowed in a future Concourse version.


jobs.8-jdk-centos: '8-jdk-centos' is not a valid identifier: must start with a lowercase letter

read more

Using Kubernetes Secrets with Spring Boot

First, create a secret, for this example we’ll be storing a username and password

kubectl create secret generic mssqldbcreds --from-literal=spring.db.username=mrbusche --from-literal=spring.db.password=hunter2

Second, add a reference to deployment.yml for each key

        - env:
            - name: USERNAME
                  name: mssqldbcreds
                  key: spring.db.username
            - name: PASSWORD
                  name: mssqldbcreds
                  key: spring.db.password

Finally, reference the value in your application.yml

    username: ${USERNAME}
    password: ${PASSWORD}

read more

iOS in app browser basic authentication

If you’re having issues not getting a basic auth prompt when using the iOS in app browser you can pass the username and password in the url. This obviously isn’t a solution if this is a production issue, but works great for test environments.

read more

Testing Node AWS Lambda handler function locally

Add a script to your package.json file

"scripts": {
    "local": "node -e \"console.log(require('./index').handler({}));\""

where index is the name of your js file with the code you want to execute

You can execute this script by running

npm run local

read more

Moving repositories from Azure DevOps to Github

To do this you’ll need an Azure Devops Personal Access Token and a Github Personal Access Token

Thanks to CoderDave for the great starting point.

Here’s a shell script you can use that’ll copy a repository, including tags, branches and full commit history.

It’s important to note that the local copy of the repository will be left in an unusable state. That’s why the shell script checks out a fresh copy of the repository and deletes it.


# start in the correct directory
cd c:/AppDev/code/azuretogithub/
# checkout your azure repository, --mirror is important
git clone --mirror https://${azurepat}
# change directory to repository just cloned
cd test-app.git/
# add new origin
git remote add GHorigin "https://${ghpat}"
# push the new origin
git push --mirror GHorigin
# delete the old origin
git remote rm origin
# rename new origin
git remote rename GHorigin origin
# delete git repo from local file system
rm -rf ../test-app.git

read more

Creating a downloadable csv file from an HTML table via java

If you have a <table> on your website and you’d like users to be able to download the content of that table to a csv file via java, I’ve got you covered. We’ll need HTML, JavaScript, Java, and the jsoup Java HTML parser.

Add a button on your page

<button id="download">Download</button>

Add an empty form to your page that posts to your controller action

<form id="myForm" method="post" action="/csvExport">
  <input id="reportData" type="hidden" name="policyDetails" />

JavaScript to grab the HTML

document.getElementById('download').onclick = function () {
  let theData = document.getElementById('reportData');
  // this gets the first table on the screen and pulls the HTML, but you can target by id, class, etc
  theData.value = document.getElementsByClassName('table')[0].outerHTML;

Add jsoup to your build file. Use the latest version.

compile 'org.jsoup:jsoup:1.13.1'

Create a java controller

@PostMapping(value = "/csvExport", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public ResponseEntity<ByteArrayResource> export(@RequestParam("policyDetails") String policyDetails) {
    try {
        String csvText = generateExcel(policyDetails);
        ByteArrayInputStream bais = new ByteArrayInputStream(csvText.getBytes());
        byte[] byteArray = IOUtils.toByteArray(bais);
        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=cat.csv");
        return ResponseEntity.ok()
                             .body(new ByteArrayResource(byteArray));
    } catch (Exception e) {
        // log and redirect user to an error page
public String generateExcel(String policyDetails) {
    StringBuilder sb = new StringBuilder();
    try {
        Document doc = Jsoup.parseBodyFragment(policyDetails);
        Elements rows = doc.getElementsByTag("tr");
        // loop through all the tr
        for (Element row : rows) {
            // loop through all the td
            Elements cells = row.getElementsByTag("td");
            for (Element cell : cells) {
            // add a line separator
    } catch (Exception e) {
    return sb.toString();

read more