Wednesday, August 10, 2022

Crystal Reports Custom Report Function: Superscript Text generator.

 A simple custom report function for Crystal Reports that will take a numeric value and generate a string of UTF8 superscripts of the digits.

//font must be Arial Unicode MS or other font with Unicode support
//1 2 3 4 5 6 7 8 9 0
// 2071 00B2 00B3 2074 2075 2076 2077 2078 2079 2070
// 0185 0178 0179 8308 8309 8310 8311 8312 8313 8304
Function (numberVar SuperScriptNumber)
//If 1 thru 9 and then zero since we're not a zero based array
Local NumberVar Array subs := [0185,0178,0179,8308,8309,8310,8311,8312,8313,8304];
Local NumberVar x;
Local NumberVar DecValue;
Local StringVar NumString := ToText(SuperScriptNumber,0,"","");
Local StringVar SuperString := "";
For x:= 1 to Len(NumString) Do
	DecValue:= ToNumber(Mid(NumString,x,1));
	if DecValue = 0 then SuperString := SuperString + chrw(subs[10])
	SuperString := SuperString + chrw(subs[decValue]);

Tuesday, May 24, 2022

Google Voice Chome Extension, React Development, and Incognito (Solved)

 After trying to play around with the open package which is a dependency of react-dev-utils, I added the bopen package and changed the open call on line 131 in openBrowser.js to bopen and added incognito:true

This is currently hack status.  but does solve the issue of using my chrome with all my extensions and launching the dev server in incognito mode.

  try {
    var options = { app: browser, wait: false, url: true , incognito: true};
    bopen(url, options).catch(() => {}); // Prevent `unhandledRejection` error.

    return true;
  } catch (err) {
    return false;

Google Voice Chome Extension and React Development

Google Voice is a fantastic free service for VOIP via the browser, however the extension isn't compatible with local React development and returns an "Uncaught (in promise) Error: Could not establish connection.  Receiving end does not exist".   

Solutions are to use incognito sessions, disable the extension during development, or a different browser.  I set Chrome as my default over other browsers for the various google app integrations.  So for now, it's a minor annoyance to have to perform the manual switching or configuration each time I want to launch a development session.

There is one possibility of diving into the node packages such as react-dev-utils that's using html-webpack-plugin  and trying to provide a  method for launching the browser incognito when using the command npm start.

Thursday, May 19, 2022

Greenscreens: Revisting ManyCam

I used to use ManyCam a few years ago but wasn't happy with their chroma keying at the time and had switched to SparkoCam.  I decided to try Manycam's newer version and they have significantly improved their chroma keying performance.  I prefer chroma key background detection as you don't get as many artifacts in the output.    Lighting still has to be adjusted for any product for best image.  But this does fairly well with just ambient lighting.

Wednesday, May 18, 2022

VBA: Outlook Macro for saving selected emails as PDF's.

 This VBA Macro for Outlook will take a selected emails and save it to c:\Temp folder as PDF's

'Outlook Macro for taking selected emails and exporting them to a folder as PDF's.
'Assumes you have Word installed and are an Exchange user.

Function CleanFileName(strText As String) As String
  Dim strStripChars As String
  Dim intLen As Integer
  Dim i As Integer
  strStripChars = "/\[]:=," & Chr(34)
  intLen = Len(strStripChars)
  strText = Trim(strText)
  For i = 1 To intLen
    strText = Replace(strText, Mid(strStripChars, i, 1), "")
  CleanFileName = strText
End Function

Sub SaveSelectedMailAsPDFFile()
  Const OLTXT = 0
  Dim currentExplorer As Explorer
  Dim Selection As Selection
  Dim oMail As Outlook.MailItem
  Dim obj As Object
  Dim sPath As String
  Dim dtDate As Date
  Dim sName As String

  Set currentExplorer = Application.ActiveExplorer
    Set Selection = currentExplorer.Selection

  For Each obj In Selection
    Set oMail = obj
    SaveAsPDF oMail
  MsgBox "Selected Emails saved as PDF to C:\Temp folder"
End Sub

Function ResolveDisplayNameToSMTP(sFromName)
  Dim oRecip As Outlook.Recipient
  Dim oEU As Outlook.ExchangeUser
  Dim oEDL As Outlook.ExchangeDistributionList
  Set oRecip = Application.Session.CreateRecipient(sFromName)
  If oRecip.Resolved Then
    Select Case oRecip.AddressEntry.AddressEntryUserType
      Case OlAddressEntryUserType.olExchangeUserAddressEntry
        Set oEU = oRecip.AddressEntry.GetExchangeUser
        If Not (oEU Is Nothing) Then
          ResolveDisplayNameToSMTP = oEU.PrimarySmtpAddress + vbCrLf + oEU.BusinessTelephoneNumber
        End If
      Case OlAddressEntryUserType.olOutlookContactAddressEntry
        Set oEU = oRecip.AddressEntry.GetExchangeUser
        If Not (oEU Is Nothing) Then
          ResolveDisplayNameToSMTP = oEU.PrimarySmtpAddress + vbCrLf + oEU.BusinessTelephoneNumber
        End If
      Case OlAddressEntryUserType.olExchangeDistributionListAddressEntry
        Set oEDL = oRecip.AddressEntry.GetExchangeDistributionList
        If Not (oEDL Is Nothing) Then
          ResolveDisplayNameToSMTP = oEU.PrimarySmtpAddress + vbCrLf + oEU.BusinessTelephoneNumber
        End If
    End Select
  End If
End Function  ' ResolveDisplayNameToSMTP

Sub SaveAsPDF(MyMail As MailItem)
  ' ### Requires reference to Microsoft Scripting Runtime ###
  ' ### Requires reference to Microsoft Word Object Library ###
  ' --- In VBE click TOOLS > REFERENCES and check the boxes for both of the above ---
  Dim fso As FileSystemObject
  Dim strSubject As String
  Dim sFromName As String
  Dim strSaveName As String
  Dim sSMTPAddress As String
  Dim blnOverwrite As Boolean
  Dim strFolderPath As String
  Dim sendEmailAddr As String
  Dim senderName As String
  Dim looper As Integer
  Dim plooper As Integer
  Dim strID As String
  Dim olNS As Outlook.NameSpace
  Dim oMail As Outlook.MailItem

  strID = MyMail.EntryID
  Set olNS = Application.GetNamespace("MAPI")
  Set oMail = olNS.GetItemFromID(strID)

  ' ### Get username portion of sender email address ###
  senderName = oMail.senderName
  sendEmailAddr = ResolveDisplayNameToSMTP(senderName)  ' use internal internal Exchange domain address if available
  If sendEmailAddr = Empty Then  ' , otherwise use external smtp address
    sendEmailAddr = oMail.SenderEmailAddress
  End If

  ' ### USER OPTIONS ###
  blnOverwrite = False ' False = don't overwrite, True = do overwrite

  ' ### Path to save directory ###
  bPath = "C:\Temp\"

  ' ### Create Directory if it doesnt exist ###
  If Dir(bPath, vbDirectory) = vbNullString Then
      MkDir bPath
  End If

  ' ### Get Email subject & set name to be saved as ###
  emailSubject = CleanFileName(oMail.Subject)
  saveName = Format(oMail.ReceivedTime, "yyyy-mm-dd-hhmm") & "_" & emailSubject & ".mht"
  Set fso = CreateObject("Scripting.FileSystemObject")

  ' ### Increment filename if it already exists ###
  If blnOverwrite = False Then
      looper = 0
      Do While fso.FileExists(bPath & saveName)
          looper = looper + 1
          saveName = Format(oMail.ReceivedTime, "yyyy-mm-dd-hhmm") & "_" & senderName & "_" & emailSubject & "_" & looper & ".mht"
  End If

  ' ### Save .mht file to create pdf from Word ###
  oMail.SaveAs bPath & saveName, olMHTML
  pdfSave = bPath & Format(oMail.ReceivedTime, "yyyy-mm-dd-hhmm") & "_" & senderName & "_" & emailSubject & ".pdf"

  If fso.FileExists(pdfSave) Then
      plooper = 0
      Do While fso.FileExists(pdfSave)
      plooper = plooper + 1
      pdfSave = bPath & Format(oMail.ReceivedTime, "yyyy-mm-dd-hhmm") & "_" & senderName & "_" & emailSubject & "_" & plooper & ".pdf"
  End If

  ' ### Open Word to convert .mht file to PDF ###
  Dim wrdApp As Word.Application
  Dim wrdDoc As Word.Document
  Set wrdApp = CreateObject("Word.Application")

  ' ### Open .mht file we just saved and export as PDF ###
  ' ActiveDocument.PrintOut PrintZoomPaperWidth:= 72 * 8.5, PrintZoomPaperHeight:= 72 * 11
  Set wrdDoc = wrdApp.Documents.Open(FileName:=bPath & saveName, Visible:=True)

  PicturesFitPageWidth wrdApp.ActiveDocument

  wrdApp.ActiveDocument.ExportAsFixedFormat OutputFileName:= _
              pdfSave, ExportFormat:= _
              wdExportFormatPDF, OpenAfterExport:=False, OptimizeFor:= _
              wdExportOptimizeForPrint, Range:=wdExportAllDocument, from:=0, To:=0, _
              Item:=wdExportDocumentContent, IncludeDocProps:=True, KeepIRM:=True, _
              CreateBookmarks:=wdExportCreateNoBookmarks, DocStructureTags:=True, _
              BitmapMissingFonts:=True, UseISO19005_1:=False


  ' ### Delete .mht file ###
  'mht file is good if tables are used, preserves the full file, so keep them both for now.
  'Kill bPath & saveName

  ' ### Uncomment this section to save attachments ###
  'If oMail.Attachments.Count > 0 Then
  '    For Each atmt In oMail.Attachments
  '        atmtName = CleanFileName(atmt.FileName)
  '        atmtSave = bPath & Format(oMail.ReceivedTime, "yyyy-mm-dd-hhmm") & "_" & atmtName
  '        atmt.SaveAsFile atmtSave
  '    Next
  'End If

  Set oMail = Nothing
  Set olNS = Nothing
  Set fso = Nothing
End Sub

Sub PicturesFitPageWidth(ActiveDocument As Variant)
  ' ResizePic Macro
  ' Resizes an image

  Shapes = ActiveDocument.Shapes.count
  InLines = ActiveDocument.InlineShapes.count
  oTables = ActiveDocument.Tables.count
  'Sets the variables to loop through all shapes in the document, one for shapes and one for inline shapes.

  'Calculate usable width of page

  With ActiveDocument.PageSetup
      WidthAvail = .PageWidth - .LeftMargin - .RightMargin
  End With

  'Loop through all shapes and lines in the document.  Checks to see if they're too wide, and if they are, resizes them.

  For ShapeLoop = 1 To Shapes
      'MsgBox Prompt:="Shape " & ShapeLoop & " width: " & ActiveDocument.Shapes(ShapeLoop).Width
      If ActiveDocument.Shapes(ShapeLoop).Width > WidthAvail Then
          ActiveDocument.Shapes(ShapeLoop).Width = WidthAvail
      End If
  Next ShapeLoop 

  For InLineLoop = 1 To InLines
      'MsgBox Prompt:="Inline " & InLineLoop & " width: " & ActiveDocument.InlineShapes(InLineLoop).Width
      If ActiveDocument.InlineShapes(InLineLoop).Width > WidthAvail Then
          ActiveDocument.InlineShapes(InLineLoop).Width = WidthAvail
      End If
  Next InLineLoop

End Sub

Tuesday, May 17, 2022

JavaScript Grids: Handsontable


I've always been a fan of the original jQuery DataTables which has been a very tight grid.  A worthy competitor that has a very appealing look and more support for the more recent JavaScript frameworks is Handsontable.  It's a little pricey on the commercial license as opposed to DataTables, but there is a free version you can use to check out the functionality.  

Wednesday, May 11, 2022

openCSV in ColdFusion and Lucee

 The opencsv project at  is a nice overall java based csv parser library that can automatically support qualified strings that contain comma's.  The below code works in ColdFusion 2021 as is with the opencsv.jar file but needs an additional jar with Lucee 5.3.9.

ColdFusion and Lucee: 

Grab the source from and run mvn to produce the jar.  I used version 5.6.


Download the apache commons lang3 source from and compile with maven.


Put the jar(s) in the lib folder of the server or use a jar loader.  start up the server and run the following test (adjust the path to your sample csv data file). which should produce the data below (excluding the other dumps)


    csvFile ="#expandPath('.')#/csv_data/addresses.csv";
    csvData = [];

    fileReader = createobject("java","").init(csvFile);


    csvReader = createObject("java","com.opencsv.CSVReader").init(fileReader);
    csvData = csvReader.readAll();