CVP Studio Features Dialog

Multiple CVP Studio Versions on the Same Machine

If you’re like me and do a fair bit of CVP work, including development, and you like to run the same version of Studio as the version you’re deploying against, then you’ve struggled with the fact that CVP Studio doesn’t play very nice with other versions of CVP Studio. Hopefully this blog helps you get all versions of CVP Studio running in harmony on your Windows machine. This method has worked well when going from CVP 12.x to 11.x to 10.x. As well as going the other way around.

  • Backup your registry.
  • If you have a 12.x version of CVP Studio installed:
    • DELETE:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{763E1DF9-41BC-4C54-9705-A0C6D1594B26}
  • If you have a 10.x or 11.x version of CVP Studio installed:
    • DELETE: [HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{763E1DF9-41BC-4C54-9705-A0C6D1594B26}]
  • Install the new version of CVP Studio in a different directory. I like to install mine in c:\cisco\CallStudioxxx, where xxx is the version (e.g. 100, 115, etc).
  • Repoint and create new shortcuts for the various versions.

You will have to repoint your shortcuts, but other than that you should be all good.

CVP Studio Features Dialog

CVP 11 and 12 running side by side.

~david

Revisting Saving Host Names in Cisco AnyConnect Client

One of my most popular blog posts is this where I talk about how to set your AnyConnect VPN client to remember the addresses of the various VPN URLs you use. I figured I would be good to revisit it since it’s been 5 years since I last talked about it to ensure things still worked the same way as they did back in 2014.

First, everything still works the same way on Windows 10. You go to C:\ProgramData\Cisco\Cisco AnyConnect Secure Mobility Client\Profile create a new xml file. I call mine Profile.xml and use the following format:

<?xml version=”1.0″ encoding=”UTF-8″?>
<AnyConnectProfile xmlns=”http://schemas.xmlsoap.org/encoding/” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=”http://schemas.xmlsoap.org/encoding/ AnyConnectProfile.xsd”>
<ServerList>
<HostEntry>
<HostName>dcloud-rtp-anyconnect.cisco.com</HostName>
<HostAddress>dcloud-rtp-anyconnect.cisco.com</HostAddress>
</HostEntry>
<HostEntry>
<HostName>2dcloud-rtp-anyconnect.cisco.com</HostName>
<HostAddress>dcloud-rtp-anyconnect.cisco.com</HostAddress>
</HostEntry>
<HostEntry>
<HostName>3dcloud-rtp-anyconnect.cisco.com</HostName>
<HostAddress>dcloud-rtp-anyconnect.cisco.com</HostAddress>
</HostEntry>
</ServerList>
</AnyConnectProfile>
Save it and restart your client and it will look like this:
VPN Client With Multiple URLs Saved
There is another method I’ve found and this involves some additional software. First, from software.cisco.com you have to install the Profile Editor (Windows), you only need to enable the Cisco AnyConnect Profile Editor. Once installed run the program.
Screen Shot 2020-01-14 at 9.38.43 AM
Go to Server List > Add:
Screen Shot 2020-01-14 at 9.44.24 AM
Go to File > Save As and save the XML file to same location C:\ProgramData\Cisco\Cisco AnyConnect Secure Mobility Client\Profile, restart the client and you should be all set.
~david

VMWare Fusion 11.5 Windows 10 VM Black Screen on Catalina

I wanted to do a quick post on this as I had to try multiple things to get my Windows 10 VM up and running. There are two posts which helped. TCC DB Updates and the processor change post 10. To summarize it both links:

Turn Off the Rootless

  1. Reboot your MAC and hold CMD+R to enter the recovery mode.
  2. Open the terminal.
  3. Enter csrutil disable
  4. Restart

From a terminal run:

tccutil reset All com.vmware.fusion   
 
sudo sqlite3 "/Library/Application Support/com.apple.TCC/TCC.db" 'insert into access values ("kTCCServiceScreenCapture", "com.vmware.fusion", 0, 1, 1, "", "", "", "UNUSED", "", 0,1565595574)'   3, 
sudo sqlite3 "/Library/Application Support/com.apple.TCC/TCC.db" 'insert into access values ("kTCCServiceListenEvent", "com.vmware.fusion", 0, 1, 1, "", "", "", "UNUSED", "", 0,1565595574)'   4, 
sudo sqlite3 "/Library/Application Support/com.apple.TCC/TCC.db" 'insert into access values ("kTCCServicePostEvent", "com.vmware.fusion", 0, 1, 1, "", "", "", "UNUSED", "", 0,1565595574)'

Turn On the Rootless

  1. Reboot your MAC and hold CMD+R to enter the recovery mode.
  2. Open the terminal.
  3. Enter csrutil enable
  4. Restart

Launch Fusion and ensure that under your Mac’s Security and Privacy:

Accessibility > VMWare Fusion is checked
Screen Recording > Vmware Fusion is checked

With your VM shutdown go to settings > Processor and Memory and check these two settings:

VMProcessor&Memory

Hope this helps another poor soul.

~david

Connect Squirrel SQL to UCCX DB

I found a good bit of information on this, but none of it was in a single post. Figured it might help to see all the steps in a single spot. This assumes 11.x UCCX from a Windows machine.

  • Download Squirrel SQL https://sourceforge.net/projects/squirrel-sql/.
  • Open a command prompt with Administrator privileges.
  • Move to were the Squirrel jar file is found.
  • Run “java -jar squirrel-sql.XXX.jar”.
  • Besides the standard options add the Informix drivers.
  • Download the latest Informix JDBC driver from https://mvnrepository.com/artifact/com.ibm.informix/jdbc/
  • Place JDBC drive in the Squirrel SQL lib folder. You shoul be able to click on Drivers and scroll down and see a check mark next to Informix.
  • Go to UCCX Administrator > Tools > Password Managenet reset the password for uccxhruser. If you do this and you have a HA setup, make sure that you click on “Check Consistency” to validate that both nodes have the latest password. If they don’t, login to both nodes and do the previous step on each.
  • Connection URL format is: jdbc:informix-sqli://<fqdn or ip>:1504/db_cra:INFORMIXSERVER=<hostname>_uccx
  • Connect and to validate that you get some data go to SQL and run a query like “select contactType, applicationName from ContactCallDetail where ContactCallDetail.startDateTime >= ‘2019-07-01 00:00:00′”

~david

Release Nuance ASR License in Cisco Contact Center Enterprise & Virtual Voice Browser (VVB)

This topic seems to come up everytime I’m on an ASR project. I finally got a definetive answer out of Cisco on the “right” way to do this. The most popular approach to release the Nuance license is to have a dummy label in your ICM script. You can read all the details in this post. However, a much cleaner way of doing it involves adding a CVP collection/capture element, I like to use Digits, set the Input Mode to dtmf, all collection timers to 1, and play a very short silent prompt. Additionaly, add the following VXML property com.cisco.asr-server = Default.

CVP Studio Digits Elements for Nuance Release

How to confirm this actually works? Start Wireshark from one of your Nuance servers and and use the following filter:

(!sip.CSeq.method == "OPTIONS")&&(sip)&&frame.len in {874 504}

The above filter will only show the Invites and Byes to the Nuance service. Which will yield the following output:

"No.","Time","Source","Destination","Protocol","Length","Info"
"100","8.769243","10.10.10.16","10.10.10.17","SIP/SDP","874","Request: INVITE sip:asr@nuancesvr:5060;transport=tcp | "
"3699","95.355613","10.10.10.16","10.10.10.17","SIP","504","Request: BYE sip:mrcpserver@nuancesvr:5060;transport=TCP | "

You should confirm that the IPs in the capture are those of your VVB and Nuance box.

~david

Cisco Finesse Workflows Troubleshooting

I ran into this problem today and I had never really thought about how you could troubleshoot issues where a workflow wasn’t working. It had always been, if it worked it worked. Took a bit of time to figure out how to dig in to the right Finesse logs to see why exactly my workflow was not firing. In my particular case I have a screen pop workflow which is supposed to pop if a call variable contains a specific word. We’re going to figure out why the workflow never worked.

First, you should go to the URL below enable persistent logging and sign in to Finesse as your agent. To be safe you might want to clear the local storage, but that’s not really necessary.

https://fqdn/desktop/locallog

Second, send in a new call which is supposed to trigger the workflow.

Thrid, in a new tab open the locallog URL and let’s walk through what we see.

One of the first things you’ll see is that Finesse pulls all the workflows associated with your team:

2019-02-19T15:46:46.901 -05:00: BF8760: FQDN: Feb 19 2019 12:46:47.214 -0800: Header : [ClientServices] Workflows: requestId='undefined', Making REST request: method=GET, url='https://FQDN:/finesse/api/User/9056/Workflows?nocache=1550609206901'
2019-02-19T15:46:47.227 -05:00: BF8760: FQDN: Feb 19 2019 12:46:47.540 -0800: Header : [ClientServices] Workflows: requestId='undefined', Returned with status=200, content='&lt;Workflows&gt;&lt;Workflow&gt;&lt;name&gt;PARTICIPANT OVERVIEW WORKFLOW&lt;/name&gt;&lt;description&gt;PARTICIPANT OVERVIEW&lt;/description&gt;&lt;uri&gt;/finesse/api/Workflow/1&lt;/uri&gt;&lt;TriggerSet&gt;&lt;name&gt;CALL_ARRIVES&lt;/name&gt;&lt;type&gt;SYSTEM&lt;/type&gt;&lt;triggers&gt;&lt;Trigger&gt;&lt;comparator&gt;IS_EQUAL&lt;/comparator&gt;&lt;value&gt;Voice&lt;/value&gt;&lt;Variable&gt;&lt;name&gt;mediaType&lt;/name&gt;&lt;node&gt;//Dialog/mediaType&lt;/node&gt;&lt;type&gt;CUSTOM&lt;/type&gt;&lt;/Variable&gt;&lt;/Trigger&gt;&lt;Trigger&gt;..

Next you’ll see that Finesse will see if there’s a workflow to run if the agent has logged in or gone ready. So it will evaluate the workflow conditions based on this trigger. This happens always even if you don’t have a workflow with these trigger conditions.

2019-02-19T15:46:47.237 -05:00: BF8760: FQDN: Feb 19 2019 12:46:47.550 -0800: Header : [WorkflowEngine] Entering 'Busy' state, from: 'loggingIn'. Triggering start of queued event processing.
...
2019-02-19T15:46:47.412 -05:00: BF8760: FQDN: Feb 19 2019 12:46:47.725 -0800: Header : [WorkflowEngine] "" IS_EQUAL "Voice" evaluates to FALSE

So far so good, but we’ve not gotten to our workflow which is supposed to launch on call arrival.

2019-02-19T15:48:14.103 -05:00: BF8760: FQDN: Feb 19 2019 12:48:14.419 -0800: Header : [WorkflowEngine] Entering 'Busy' state, from: 'idle'. Triggering start of queued event processing.
...
2019-02-19T15:48:14.191 -05:00: BF8760: FQDN: Feb 19 2019 12:48:14.507 -0800: Header : [WorkflowEngine] Evaluating conditions for workflow: {"workflowName":"CASE SEARCH","eventType":"Dialog","eventUri":"/finesse/api/Dialog/33558863"}
2019-02-19T15:48:14.191 -05:00: BF8760: FQDN: Feb 19 2019 12:48:14.507 -0800: Header : [WorkflowEngine] "ATTORNEY" CONTAINS ""ATTORNEY"" evaluates to FALSE

As you can see in the last line our workflow is supposed to launch if ATTORNEY contains ATTORNEY, but we have “” arround the string which is causing it to not match. By going to Finesse adming and changing your workflow to not contain the quotes fixed the issue right up.

~david

Deploy to Firebase hosting using Bitbucket Pipeline

On and off I’ve played around with Firebase and one thing I had never tried out was the hosting part of Google’s offering. I spent a bit of time a few nights ago getting familiar with it and didn’t like the fact that I had to deploy from the command line as I generally like to do my deployments via git.

This excellent blog post showed me what I needed to do and everything seemed easy enough. Here is my original pipeline.yml

image: node:8.4.0
pipelines:
branches:
master:
- step:
deployment: production
caches:
- node
script:
- npm install -g firebase-tools
- firebase deploy --token=$FIREBASE_TOKEN --project mySite --non-interactive

When my pipeline ran I received the following error.

Error: Authorization failed. This account is missing the following required permissions on project &lt;project&gt;:
firebase.projects.get
firebasehosting.sites.update

The issue was resolved when I looked at the –project parameter. Everything I read said project name, but in reality it needs to be the project ID, which you can get from Firebase project console. Once this was rectified the pipeline ran succesfully.

~david

Amazon Connect CCP (Agent Desktop) Walkthrough

I was talking to a few people about Connect and we were focusing on the agent desktop. For someone who is coming from Cisco Finesse, CCP is a big departure and I couldn’t find a good resource which showed all the out of the box functionality in a concise way. So, here it is. Everything you need to know about straight out of the box CCP.

CCP Highlights

  • 100% web-based.
  • Uses WebRTC and Opus audio codec.

Login Screen

  • Can be integrated to SSO.
  • Allows for password self-service.

image

Initial Screen

  • Will set you to whatever state you last had before you logged off or killed the client.
  • Transfer buttons are semi context aware (more on this later).
  • Agent status/state menu.
  • Log out is not a state, but a separate button.
  • Ability to get calls via a hard phone/PSTN instead of over the web.
  • Ability to download agent side logs (JSON format) from first login to right now.
  • Multi-lingual support 8 languages.

imageimageimageimageimage

Call Screen

  • Agent whisper of queue name.
  • ANI of caller.
  • Transfer numbers based on queue name.
  • Can transfer to another queue, another agent, or external. Can even transfer to yourself which makes no sense.
  • Multi line support.
  • Can make outbound calls manually.

12

image3image

~david

Continuous deployment to Amazon Lambda using Bitbucket Pipeline

I’m not a developer (more of a hack) so I’m always looking for way to figure out efficiencies in my process when playing around with code as I’m a very slow coder. One of those efficiencies found is around deploying my code to Amazon Lambda.

First, let’s talk about your options when deploying code to Lambda. The easiest way is to just do your development using Amazon’s IDE. The benefit here is that you can manually run some tests to validate what you’re writing, however if you’re using any dependencies the IDE has a size restriction and at some point it’s no longer available to you.

image

The next method is doing local development and creating a zip file of all your code and dependencies. Then manually upload your code. You can then run the same manual tests as before on your code, but the process of zipping and uploading the file is tedious specially when working on large code bases.

image

Next process involves the very good Amazon CLI. Using the CLI you’ll be able to save the manual process of uploading the zip file. Below you’ll find the Windows scripts I use one for small code bases (without dependencies) and one for larger ones.


echo on

del index.zip

echo Deleted index.zip

"c:\Program Files\7-Zip\7z.exe" a index.zip index.js

aws lambda update-function-code --function-name mySmallLambdaFunction --zip-file fileb://index.zip

echo done

[/sourcode]</blockquote>
<blockquote>

echo on

del myZip.zip

echo Deleted myZip.zip

"c:\Program Files\7-Zip\7z.exe" a myZip.zip index.js node_modules

echo Zipped myZip.zip

aws lambda update-function-code --function-name myLargeLambdaFunction --zip-file fileb://myZip.zip

echo done

Finally, the process I’ve come to enjoy the most is deploying from git. The main reason being that it forces you have a bit of a process around using git which is pretty much the standard when collaborating with multiple developers. So if you’re dragging your feet around using git take the plunge it’s worth the learning. My favorite, mainly because they have a very generous free offering is Bitbucket. Besides having private repositories they also give you 50 free build minutes which is where our deployment to Lambda from Bitbucket comes in. To get started you first need to setup a few environmental variables. Go to your repository > settings > environment variables. You’ll need these named exactly this way.

image

The next step can be done in two ways. You can commit a bitbucket-pipelines.yml file to your repository or you can go to your repository > pipelines to have Bitbucket commit one for you. What the original yml file looks like doesn’t matter we’re going to change it specifically for Lambda deployment. Here’s what my file looks like with inline comments.


#I like to use the same version of Node as the Lambda function I’m using.

image: node:6.10

pipelines:

default:

- step:

script: # Modify the commands below to build your repository.

- apt-get update

- apt-get install -y zip

- python –version #From here to there is all to enable the AWS CLI installation

- apt-get install -y python-dev

- apt-get install -y python-pip

- pip install awscli #there

- zip index.zip index.js #this is for a Lambda with a small code base. For something large you can use “zip myZip.zip index.js privatekey.json -r node_modules” notice the –r parameter to zip up folders.

- aws lambda update-function-code --function-name botValidationScheduleMeeting --zip-file fileb://index.zip

Assuming you’ve done everything right you should see something like this under Pipelines.

imageThe last 3 commits were successfully built (sent to Lambda). You can click on the commit and see detailed information on the results of every command in your yml file. You’re done, you’ve developed some code locally, committed to git, and pushed it to Lambda all with a few clicks.

~david

Bringing Amazon Lex into your Amazon Connect flows

In this blog we’ll continue our discussion around Amazon Lex. Talk about a few things to keep in mind when integrating your Amazon Lex bot with your Amazon Connect flow. In my particular use case I wanted to use Amazon Lex to look at my Gmail calendar and book a meeting if I’m available. If you want to skip to the very end you can see the end result via video. You’ll see one video of the voice interaction and one of the Facebook Messenger interaction.

First, you might want to reference my previous post around Lex validation. Now let’s talk about our use case:

  • Lex easily allows you to build a bot which understand both voice and text, so our bot needs to handle calls into our call center as well as Facebook Messenger interactions.
  • Bot needs to to ask a few question in order to find out what time the user would like to meet.
  • Bot should only schedule calls between Monday-Friday and 10 AM – 4 PM Easter Time
  • Bot (using Lambda) should schedule a meeting and if slot already taken then suggest an alternate time to meet.

Second, let’s take a quick look at the Lex screen. The bot I created is very simple and it follows closely the Flowers example provided by Amazon. These are the slots I’m requiring my bot to confirm.

image

I used two different Lambda functions. One for validation and one for fulfillment. While most examples seem to focus on using the same function for both, for me it was easier to have different code bases for each with the added benefit of keeping the code manageable. As it is both validation and fulfillment both came in at around 250 lines of code, but fulfillment had around 9 megabytes of dependencies.

image

Finally, here are sample utterances I used for the main intent.

image

What this gets us is the following. The first video is the voice interaction. I went about it the long way to show some of the validation rules being set by the bot, such as no weekend meetings and no meetings too early in the day. At the end of the video you see I refresh the Gmail calendar to show the new appointment has been saved.

In the second video I go through the same Lex bot using Facebook Messenger and then show the calendar to prove that the appointment was saved.

Ultimately, Amazon makes it extremely easy to create a mutli channel bot, however the integration to back end systems is the tricky part. This bot needs a lot of tuning to make it more natural, but for just a few hours of work there’s very little out there that can get your call center to have some bot integration for self service.

~david