Slack Privacy Mode

If you ever work in a public space or around snooping people you may want some extra privacy on Slack. Here is a pretty simple solution to enable a blurred overlay when you mouse out of the application.

To add this functionality…

  • Enable Slack Developer Tools – You will only need to do this once
    • Open a Command Prompt and run
    • I am told on a Mac it would be
  • Restart Slack
  • Open Developer Tools
    • From the application menu select View > Developer > Toggle Webapp DevTools
    • Shortcut: Ctrl+Alt+I
  • Paste the following script into the Console tab – You will need to do this each time Slack restarts (unless I find a better way to implement this)

That’s it! Now when you mouse in and out of the window it should show and hide an overlay. If you don’t like it just restart the app.


Real Fake Startup Launched

Today I have officially started the Real Fake Startup project that will allow developers of all skill levels to participate in the creation of a “commercial quality” application, in a mock business setting, in order to gain and strengthen skills necessary to most software development jobs.

There was massive interest with over 400 respondents so in the initial wave I picked the first 25 people to respond as participants.

It will be a massive effort and I am not sure what the outcome will be but everyone seems excited. As the project continues I will post more updates.

Mood: Optimistic


The journey stalled

If anyone is reading this, I am still alive.

It has been quite a gap since my last update and you may think I have been cooking up lots of cool projects but – unfortunately – that is not true.  I have started and stopped dozens of projects, but I can’t find enough time to commit to any of them.  Games, utilities, even trying to go back and fix defects in existing projects.  There just seems to be too little time in the day.

Rather than dwell on my laziness I am going to look forward and start to prepare some articles in 2019, some ServiceNow related and some for other projects I will try.

I won’t guarantee much other than I am sure you will be whelmed.


New YouTube Channel

I know it’s way past due, but I finally created a YouTube channel.  Now in between binge watching Spiderman/Elsa videos and the Gummy Bear song you can watch moderately interesting programming videos.

I don’t think everything can become a video but I will try to create accompanying videos for any code or projects that make sense.

Check out the channel here:  An Errant Programmer

The first post is a walk through of some code that was requested, a custom chart UI Page in ServiceNow using ChartJS.


Recovering Redacted Text From a Document

With the impending release of the final cache of documents related to the JFK assasination I thought it would be interesting to take a look into the topic of information leakage, or the unintentional revealing of information in a secure system. In this case the leaking of information through a redaction in a document.

For a properly redacted document the possibility is almost 0 that you will retrieve any information but according to a paper by Daniel Lopresti and A. Lawrence Spitz of Lehigh University, it may be possible to take an educated guess at a redaction not done properly.

This could be a few cases:

* The redaction method is not sufficient to cover the original text. This can mean that even though the color of the ink (usually black) matches, the original text would still be visible through the redaction.

* The redaction only partially obscures the original text. If you were to just draw a redaction through the center of some text, the tops (ascenders) and bottoms (descenders) of the letters may still be visible. These may give clues as to some of the letters being redacted.

* Analysis of the redaction size combined with knowledge of the font, from the unredacted portions of the document. If you can guess at the amount of letters redacted, even if its not a single word you can start to take a guess as to what the word or phrase is.

If any clues are to be found it may be possible to combine such clues with some Natural Language Processing and a dictionary to reveal possible word combinations for a redaction.

Although this sounded like a very interesting project to me, in the end, I decided I would rather leave the redacted documents to spies. I still felt there were some fun things to learn however and so I decided to create a prank library instead to do some fake analysis of a redacted document instead.

I wanted to learn and refresh myself of the HTML Canvas object and functions and so I decided I’d like my algorithm to scan a Canvas object, automatically finding any redaction and then fill in the redaction with song lyrics while matching the font size.

I started with a very simple HTML page with a canvas object.

<!DOCTYPE html>
<style type="text/css">
border: 1px solid silver;
<h1>Drag a redacted image into the area below.</h1>
<p>Click a redaction to try and recover the text.</p>
<canvas id="canvas" width="600" height="800"></canvas>
<script type="text/javascript" src="deredactyl.js"></script>


I grabbed a redacted document off the internet and then started to create the JavaScript.

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var img = new Image();

img.addEventListener('load', function() {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
}, false);

img.src = "test.png";

This was the first revision, I wanted to make sure I could at the very least get an image loaded onto a Canvas.

From there it was all about scanning the document looking for large areas of redacted text.

I started at the top and worked my way through using ctx.getImageData(x,y,1,1) to get the RGB data for a given pixel.

It was a complete failure, crashing my browser several times. It turns out this method was just too slow. I removed console output, I even started incrementing by 2,3,5,10 at a time and it was still too slow, forcing me to rethink my algorithm.

I ended up opting for a user click even to find a specific area for a redaction. The new algorithm was this:

* A user clicks a coordinate in a canvas (hopefully in a redaction)
* Determine the left and right bounds by searching in either direction starting from the point of the click until the edge of the document is found or a pixel is found that is lighter than our threshold.
* Determine the upper and lower bounds with the same technique
* Calcuate the width and height of the area
* If the width is greater than 10 pixels and the height greater than 3, fill in the redaction. (This was just actually an arbitrary guess, I could have improved this by seeing if the size met the minimum ratio for a monospace font letter – about 1/1.7)

Here is some of the relevant code.

canvas.addEventListener('mousedown', selectRedaction);

function selectRedaction(event) {
var x = event.layerX;
var y = event.layerY;
var bounds = getRedactionBoundaries(x, y);

if (bounds.width > 10 && bounds.height > 3) {
clearTextAnalysisCalled = false;
for (var q = 0; q < (bounds.width / bounds.height); q++) { analyzeText(bounds); } } } function getRedactionBoundaries(x, y) { var bounds = { left: findLeft(x, y), right: findRight(x, y), top: findTop(x, y), bottom: findBottom(x, y), } bounds.height = bounds.bottom -; bounds.width = bounds.right - bounds.left; return bounds } function findLeft(x, y) { for (var search = x; search > 0; search--) {
var pixel = ctx.getImageData(search, y, 1, 1);
var isDark =[0] +[1] +[2] <= sensitivity;
if (!isDark)
return search

function findRight(x, y) {
for (var search = x; search < img.width; search++) {
var pixel = ctx.getImageData(search, y, 1, 1);
var isDark =[0] +[1] +[2] <= sensitivity; if (!isDark) return search } } function findTop(x, y) { for (var search = y; search > 0; search--) {
var pixel = ctx.getImageData(x, search, 1, 1);
var isDark =[0] +[1] +[2] <= sensitivity;
if (!isDark)
return search

function findBottom(x, y) {
for (var search = y; search < img.height; search++) {
var pixel = ctx.getImageData(x, search, 1, 1);
var isDark =[0] +[1] +[2] <= sensitivity;
if (!isDark)
return search

After determining the space I decided I wanted to add some visual effects to make it seem like the code was actually doing some analysis. I really wanted to create a ‘snow like’ effect so again I looped over the height and width of the redaction and again it was way too slow.

I tried just randomly putting up dots on the redaction but this was actually too fast. Of course there was no easy way to slow this down, so I ended up adding a setTimeout calling the function again and again until a limit was reached. This again was too slow.

Finally, after much annoyance with what should be a trivial feature, I decided to spawn several instances of the function each of which would continue for a pre-determined amount of time before calling the next function, a wipe effect.

Of course, I created a race condition in the process. To fix this condition I created a global flag that would be set by the first function to finish, thereby collapsing the x amount of threads into a single one.

The wipe function was comparatively easy, just going from left to right, filling the redaction with white.

Finally, with the smoke and mirrors portion done, I could fill in the text.

I needed a couple pieces of information, one was the size of the font, which I determined by the height of the redaction. The second was the length of text that could fit in the space. For this I took the raw width and divided it by the rough width of a font that would fit in the space given the height

var fontSize = bounds.height;
var textLength = Math.floor((bounds.width / fontSize) * 1.7);

Now with this length I could start to populate words. I am nothing if not a sucker for the classics so I chose the lyrics to Rick Astley’s Never Gonna Give You Up.

To determine which words to use I iterated over the lyrics pulling words whose length would fit into the remaining space. I’d repeat this for one loop and finally give up if I couldn’t fill the space exactly.

function scrapeText(length) {
var words = "";
var attempts = 0;

while (words.length < length && attempts < sourceWords.length) {
var randomWord = sourceWords[wordCounter];

if (wordCounter == sourceWords.length)
wordCounter = 0;

if ((words.length + randomWord.length) < length) { words = words + " " + randomWord; attempts = 0; } else { attempts++ } } return words; } 

Once I was certain this was all working I added one last feature – which was more of a re-learning exercise – and that was to drag and drop files on to the canvas. It turned out to be much easier than I had remembered.

 canvas.addEventListener("dragover", function(evt) { evt.preventDefault(); }, false); canvas.addEventListener("drop", function(evt) { var files = evt.dataTransfer.files; if (files.length > 0) {
var file = files[0];

if (typeof FileReader !== "undefined" && file.type.indexOf("image") != -1) {
var reader = new FileReader();

reader.onload = function(evt) {
img.src =;


}, false);

Finally, not wanting to ruin the joke I took the plain text of the lyrics and fed that portion through a JavaScript obfuscator, nothing someone couldn’t reverse if they really wanted, but just enough to fool people on the first glance.

All in all it took roughly an hour to get everything working and to my surprise I was even able to Rick Roll a couple friends although I am sure they were shaking their heads.



All source code from this article available at:

* Daniel Lopresti and A. Lawrence Spitz – Information Leakage Through Document Redaction: Attacks and Countermeasures (


Site Rebranding

So this has been a long time coming.  I have been spending less & less time in ServiceNow over the past year.  I still use SNOW quite a bit but professionally and personally I am using other technologies and tools and would like my blog to reflect what I am actually doing.

As I find interesting bits in ServiceNow I will write about them but I will also open the scope of the blog to include other areas as well.

I hope everyone continues read and enjoy.


Getting the Current URL

Recently ran into this wall which stumped me for a few.  Had to get the full URL including the path from a UI Page on the server.  Using my book as a reference (shameless plug) I found RP.getReferringURL(), but this only returns the page name I found out and RP is not a usable object everywhere.

The solution was to find the actual Request object through the Transaction.

var tr = new GlideTransaction.get();

So what is happening here? GlideTransaction.get() returns the current transaction. It has a scriptable method ‘getRequest()’ which returns the underlying request for this transaction which an HTTPServletRequest. Not every method is going to be available since SN has whitelisted/blacklisted many but getRequestURL().

There you have it the full URL with the path! What other methods have you found to get the URL?

Coding Uncategorized

YouTube Like Loader

Just a simple script to add a YouTube like loading bar to the top of the page for AJAX Requests. Many users said they wanted a way to know when the system was “thinking”. There actually is a loading GIF in the top right (I noticed it in Fuji) but it’s a bit hard to see. This adds a very obvious loader to every page, even popups and CMS page.

This should go in a Global UI Script. Tweak as necessary!

if(self == top){
var loadingDiv = document.createElement("div");
var loadingInterval = false;
var loadingIntervalWidth = 0;
var stopLoading = false; = "100%"; = "fixed"; = "2px" = "0"; = "0"; = "2000"; = "#29d"; = "none";

document.addEventListener("DOMContentLoaded", function(event) {

function startProgress(){

if(loadingInterval == false){
stopLoading = false; = "block"; = "0%";
loadingIntervalWidth = 0;
loadingInterval = setTimeout(incrementProgress, 50);


function incrementProgress(){

loadingIntervalWidth++; = loadingIntervalWidth.toString() + "%";
if(loadingIntervalWidth < 100 && stopLoading == false){ loadingInterval =setTimeout(incrementProgress, 50); } else { loadingDiv.display = "none"; stopProgress() } } function stopProgress(){ stopLoading = true; = "100%"; loadingInterval = setTimeout(hideProgress, 100); } function hideProgress(){ loadingInterval = false; loadingIntervalWidth = 0; loadingDiv.display = "none"; = "0%"; clearTimeout(loadingInterval); } CustomEvent.observe('ajax.loading.start', function() { startProgress() }); CustomEvent.observe('ajax.loading.end', function() { stopProgress(); }); }


Using Jelly In ServiceNow Release Candidate Shipping

I am happy to announce I have started sending out the first Release Candidate for Using Jelly In ServiceNow.  I decided to keep the pricing as is at $25 USD for now until the final version comes out.

To purchase you can use the following form and I will send as soon as PayPal alerts me.  I try to do it immediately but sometimes it takes up to a day.

Update: I have started using Gumroad to distribute the book now instead of manually sending copies out via email.

Get the book now!

Table of Contents

0 Introduction
1 Jelly
1.1 Key Concepts
2 Jelly and ServiceNow
2.1 UI Pages
2.1.1 Page Template
2.2 UI Macros
2.2.1 Formatters
2.3 Other Jelly Scriptable Areas
3 Jelly Scripting
3.1 Jelly Tag Library
3.1.1 Variables
3.1.2 Output
3.1.3 JEXL Expressions
3.1.4 Conditions
3.1.5 Looping
3.1.6 Undocumented Jelly Tags
3.2 Glide Tag Library
3.2.1 Using References
3.2.2 Scripting Tags Running JavaScript Scripting Helpers Using Functions and Macros Miscellaneous Functions
3.2.3 UI Tags HTML Elements Form Elements List Elements Choice Lists Content Management Components Knowledge Base Components Chart Components Extended UI Components Other ServiceNow Components
3.2.4 Undocumented Tags
3.3 Debugging
3.3.1 Debugging Tags
4 Advanced Usage
4.1 Glide and Jelly JavaScript Objects
4.1.1 Executing Jelly
4.1.2 Render Properties
4.1.3 Jelly Contexts
4.1.4 Evaluating Expressions
4.2 Creating UI Extensions
4.3 Decorators
4.4 Overriding Default Templates
4.5 System Properties
5 Jelly Examples
5.1 Core Concepts
5.1.1 Multiple Phases
5.1.2 Fizz Buzz
5.1.3 Fibonacci Numbers
5.1.4 Bubble Sort
5.1.5 Calling Functions
5.1.6 Towers of Hanoi
5.2 Static Page
5.2.1 Hello World
5.2.2 Simple Calculator
5.2.3 Output A List
5.2.4 Simple Form
5.2.5 Form Using Macros
5.3 Dynamic Page
5.3.1 Dynamic Calculator
5.4 Multi-Page Application
5.4.1 Simple Portal
5.4.2 Advanced Form
5.5 AJAX Application
5.5.1 AJAX Form
5.5.3 AJAX Form Widget
5.6 Custom Formatter
5.6.1 Custom Element
5.6.2 Form Widgets
5.7 Mobile Page
5.7.1 Mobile Only Page
5.7.2 Responsive Page
5.8 Frameworks and Libraries
5.8.1 Datatables List
5.8.2 Twitter Bootstrap
6 Index
6.1 Jelly Language Reference
6.2 JavaScript Objects Reference
6.3 LIcenses and Copyrights

Jelly Uncategorized

Two Big Announcements

One, I am at Knowledge15!  Please come say “Hi” at the Cerna Solutions booth.

Second, and this is the reason I have not been blogging much lately, I am nearly done writing my first – and I am pretty sure the world’s only -and I am certain the world’s LAST – book on Jelly in ServiceNow!

Here is a quick summary of what the book “Using Jelly in ServiceNow” contains:

  • Start to end walkthrough of every function with examples
  • Full page examples with walkthroughs
    • Everything from simple pages to portals and AJAX pages
    • Examples showing how to use Frameworks
  • Documentation on all Glide API Interfaces for Jelly
  • Full language reference
  • Full JavaScript Object reference
  • Over 200 Pages of content

During the conference I am offering pre-orders at a special price of $25.  As soon as the book is ready (~Mid April or earlier) it will be delivered by email.

Any questions feel free to stop by the booth or leave a comment here!  Thanks.

Get the book now!

Update: Some folks were asking for more details so here is the Table of Contents for Using Jelly In ServiceNow.

  • 0. Introduction
  • 1. Jelly
  • 1.1. Key Concepts
  • 1.2. Jelly and ServiceNow
  • 1.2.1. UI Pages
  • 1.2.2. UI Macros
  • Formatters
  • 1.2.3. Other Scriptable Areas
  • 2. Jelly Scripting
  • 2.1. Jelly Tag Library
  • 2.1.1. Variables
  • 2.1.2. Output
  • 2.1.3. JEXL Expressions
  • 2.1.4. Conditions
  • 2.1.5. Looping
  • 2.1.6. Unused Jelly Tags
  • 2.2. Glide Tag Library
  • 2.2.1. Setting Up A Reference
  • 2.2.2. Scripting Tags
  • Running JavaScript
  • Scripting Helpers
  • Using Functions and Macros
  • Debugging Tags
  • Miscellaneous Functions
  • 2.2.3. UI Tags
  • Basic HTML Elements
  • HTML Elements
  • Form Elements
  • Choice Lists
  • ServiceNow Elements
  • Miscellaneous Tags
  • Undocumented Tags
  • 2.3. Debugging
  • 3. Advanced Usage
  • 3.1. Glide and Jelly JavaScript Objects
  • 3.1.1. Executing Jelly
  • 3.1.2. Render Properties
  • 3.1.3. Jelly Contexts
  • 3.1.4. Evaluating Expressions
  • 3.2. Overriding Default Templates
  • 3.3. System Properties
  • 3.4. UI Element Tags
  • 3.5. Creating Custom UI Tags
  • 4. Jelly Examples
  • 4.1. Core Concepts
  • 4.1.1. Multiple Phases
  • 4.1.2. Fibonacci Numbers
  • 4.1.3. Bubble Sort
  • 4.2. Static Page
  • 4.2.1. Hello World
  • 4.2.2. Simple Calculator
  • 4.2.3. Output A List
  • 4.2.4. Simple Form
  • 4.2.5. Form Using Macros
  • 4.3. Dynamic Page
  • 4.3.1. Dynamic Calculator
  • 4.4. Multi-Page Application
  • 4.4.1. Simple Portal
  • 4.4.2. Advanced Form
  • 4.5. AJAX Application
  • 4.5.1. AJAX Form
  • 4.5.3. AJAX Form Widget
  • 4.6. Custom Formatter
  • 4.6.1. Custom Element
  • 4.6.2. Form Widgets
  • 4.7. Mobile Page
  • 4.7.1. Mobile Only Page
  • 4.7.2. Responsive Page
  • 4.8. Frameworks and Libraries
  • 4.8.1. Datatables List
  • 4.8.2. Twitter Bootstrap
  • 5. Jelly XML Language Reference
  • 6. JavaScript Objects Reference