Moses Wynn

LMPD and Fischer Show No Accountability

Published:

I just got done walking my dog. It is a fairly peaceful morning. A light breeze is blowing and it is in the mid-60s temperaturewise. Birds are chirping. People are eating brunch outside of Gralehaus. There were only a few indicators of the mayhem that occurred just 12 hours before. A stray pepper ball on the sidewalk. An abandoned sign that said "Silence is betrayal." A shelf with milk and water bottles outside of a black-owned business.

Of course, last night was a different scene. A paramilitary police force assisted by the national guard came out in numbers to harrass peaceful protesters who were honoring the memory of Breonna Taylor and demanding the arrest and prosecution of her murderers, 3 LMPD officers, along with other demands. The scenes last night in Louisville were a display that police have no accountability to their elected officials, are now openly hostile toward the media, and are actively inciting violence against peaceful protesters.

Mayor Greg Fischer has no control. Last night, at 10:30 PM Fischer hosted his 3rd address of the day to provide an update on the situation. During that presser, Mayor Fischer did not even mention Breonna Taylor until about 3 minutes into the 4 minute half-hearted address before taking questions.

The first question he received was, "Did you consider addressing protesters on the street before curfew tonight, and why did you decide not to?"

A visibly confused Fischer did not understand that the question was about speaking to the needs of protesters, acknowledging their pain, and hearing their demands for justice. Instead, he thought the question was about ordering protesters to disperse. He responded by thanking people for abiding by the curfew and spoke some sparse details on ordering remaining protesters to disperse. This response contained a clear lack of empathy (so much for #CompassionateLouisville).

The next question was, "Why were police destroying protesters supplies including water and milk earlier this evening?"

Fischer responded with a bold-faced lie, one that was likely fed to him by the police. He claimed that supplies included mason jars with flammable material and that the materials were removed for the safety of everyone. In the video such items are not seen, and if it were true it would not make sense for the police to be smashing it all up creating a hazard.

After telling that lie, another question was asked: "Why did police start pushing protesters back using tear gas, smoke, and holding lines before the curfews began at 9:00?"

Fischer made some excuse that police "used their judgement and that includes teargas being deployed." Basically, his response to the question was because that is what police decided to do. A non-answer.

Later, Fischer was asked why two black members of the Kentucky general assembly, Charles Booker, who is running for Mitch McConnel's senate seat, and Attica Scott, representative of KY house district 41.

He responded stating that they don't want any peaceful protesters to be tear gassed. Despite this claim, police did fire tear gas on peaceful protesters both Friday and Saturday. This displays that police are ignoring orders from elected officials.

That question was followed by one asking why police are using pepper balls and tear gas without warning, which Fischer dodged, then another question was asked about why police are telling press and media that they are illegally breaking curfew, even though it does not apply to them.

Fischer responded that police have been notified and directed to leave the press alone. This not only shows that police have no accountability to our elected officials, but they are also actively targeting the media.

Examples of police targeting the media have been abundant. On Friday night, an LMPD officer pointed his weapon at a WAVE 3 news reporter and her cameraman and fired pepper balls on them. A CNN reporter was arrested live on air in Minneapolis. MSNBC's Ali Velshi recounted police firing on the group of protesters he accompanied with tear gas and rubber bullets, despite no provocation from protesters. When Velshi yelled to police that they were members of the media, they responded, "We don't care." Just after 7:00 PM last night, WFPL reporter Stephanie Wolf reported her and her colleagues having been shoved to the ground by police as they were being shot with pepper balls. Ryan Van Velzer, another WFPL reporter, reported similar actions.

Why are police targeting the media? There could be two reasons. The first one, which seems most apparent, is police do not want to have their violent and illegal use of force recorded or reported on. The second is the growing hostilities against media, largely from the right-wing. Police officers who sympathize with these hostilities let such beliefs seep into their policework. Many of these encounters reported by the media include reporting on police provoking peaceful protesters.

Here is an account one protester posted on reddit of the tactics that police are actively using to box in peaceful protesters and target them with tear gas. This tweet from KY state senator Charles Booker shows police firing tear gas upon the group he was with, as was mentioned in the Fischer press conference. More footage posted on twitter by a protester shows police forming a line trying to herd peaceful protesters away from the area hours before curfew.

The state is mounting a full scale attack on the citizens of Louisville. An outstanding member of the community, Breonna Taylor, was murdered in her sleep, and her murderers walk free. If Fischer and the police truly were concerned about peace, they would arrest the officers involved. Instead, officials have caved to the outsized influence of police and related organizations like the FOP. The closest thing to a legitimate response they have shown is a civilian review board on which police have far too much representation. That was merely an act of theatre. The healing process will not begin until Breonna Taylor's murderers are arrested and charged. That is it.

Please consider donating to the Louisville Community Bail Fund

Read More

Connecting to the UCCX Database Remotely with Python

Published:

Recently at work, I was tasked with a project that required me to access the historical database in Cisco's Unified Communication Center (UCCX). While I am familiar with SQL to the extent of issuing queries and combining data, as is needed in the day-to-day of my work, I am not a DBA and did not have any information beyond the read-only credentials for the server. My goal was to pull data from the database in a Python script, perform manipulations, export the resultant dataset to a .csv file, and push it to Domo with their provided SFTP push connector.

Simply connecting to the server proved to be a nearly impossible task, but after a few hours of digging online, I eventually was able to establish a connection using the pyodbc library. UCCX is used in a lot of enterprise call centers, so I decided to writeup how to connect for anyone else who may have experienced the same issues I did.

Before getting started, I'll let you know that my environment was Ubuntu 18.04 running on WSL in Windows 10.

Installing The Database Drivers

The database in question is an IBM Informix database. Setting up the drivers was difficult as they were hard to find and required some configuration. Here is how you do it.

1) Obtain a copy of the Informix Client SDK from here. You will need an IBM id to login and obtain, but it is free. Be sure to select the appropriate version for your environment.

2) Start up a root shell with sudo -s and run the following commands to prepare the environment for installation.

- Create the installation directory: cd /opt && mkdir IBM && mkdir IBM/informix
- Create an informix user and group: useradd -g informix informix
- Set the $INFORMIXDIR environment variable: export INFORMIXDIR=/opt/IBM/informix

3) While still in the root shell, install the application.
- Copy the tar file you downloaded to /opt/IBM/informix and run tar -xvf <filename>.tar
- This will extract the files needed for installation. Once extracted, run ./installclientsdk and follow the prompts. The installation took some time for me.

4) Now that the client SDK is installed, you can setup the drivers! Do not leave the root shell yet.
- Ensure unixODBC is installed by running apt install unixodbc unixodbc-dev
- Once installed run unixodbc -j to determine where drivers and system data sources are configured. By default drivers should be in the /etc/odbcinst.ini file and system data sources should be in the /etc/odbc.ini
- First we will edit the /etc/odbc.ini file and add the following:

[ODBC Data Sources]
uccx

[uccx]
DRIVER={IBM INFORMIX ODBC DRIVER (64-bit)}
UID=uccxhruser
PWD=yourpassword
DATABASE=db_cra
HOST=uccx
SERVER=uccx_uccx
SERVICE=1504
PROTOCOL=onsoctcp
CLIENT_LOCALE=en_US.UTF8
DB_LOCALE=en_US.UTF8

In the above configuration uccxhruser is the default user for UCCX on all instances. PWD should be set to that user's password, whatever you set it to. HOST should be set to the hostname for the remote server. SERVER should be the name of the database server.

- Next we will update the odbcinst.ini file and add the following:

[IBM INFORMIX ODBC DRIVER (64-bit)]
Driver=/opt/IBM/informix/lib/cli/iclis09b.so
Description=IBM INFORMIX ODBC DRIVER
UID=uccxhruser
PWD=yourpassword
DATABASE=db_cra
HOST=uccx
SERVER=uccx_uccx
SERVICE=1504
PROTOCOL=onsoctcp
CLIENT_LOCALE=en_US.UTF8
DB_LOCALE=en_US.UTF8

Again, make sure that PWD, HOST, and SERVER are set to the correct values for your instance.

- Finally, you will need to create a file at /opt/IBM/informix/etc/sqlhosts and populate it with this line:

uccx_uccx onsoctcp uccx 1504

uccx_uccx should be replaced with the server name and uccx should be replaced with the hostname of the machine the server is running on.

Connecting with PyODBC

5) You are now ready to test the connection! You can go ahead and leave your root shell now.

- First we are going to create a project directory and install our dependencies.

$ cd ~
$ mkdir uccx
$ cd uccx
$ python3 -m venv .venv
$ source .venv/bin/activate
$ pip install pyodbc python-dotenv
$ touch .env

This will setup a new virtual environment, activate it, install pyodbc and python-dotenv, and create an empty .env file.

- Next, we are going to set our connection string in an environment variable defined in the .env file. You will want to add this line:

CSTRING=SERVICE=1504;PROTOCOL=onsoctcp;CLIENT_LOCAL=en_US.UTF8;DB_LOCALE=en_US.UTF8;DRIVER={IBM INFORMIX ODBC DRIVER (64-Bit)};UID=uccxhruser;PWD=yourpassword;DATABASE=dbc_cra;HOST=yourhostname;SERVER=yourservername

One thing to note is that the SERVER parameter in the connectionstring cannot contain dashes. If you change them to underscores it should connect without issue. Also, make sure that you have set PWD, HOST, and SERVER to the correct values for your instance.

- You will need to set the appropriate environment variables for the driver to work properly in the shell rather than the .env file.

$ export INFORMIXDIR=/opt/IBM/informix
$ export LD_LIBRARY_PATH=$INFORMIXDIR/lib:$INFORMIXDIR/lib/cli:$INFORMIXDIR/lib/esql
$ export INFORMIXSQLHOSTS=$INFORMIXDIR/etc/sqlhosts

- We are finally ready to write some Python code. Let's test our configuration in the REPL:

$ python3
Python 3.6.9 (default)
[GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os, pyodbc
>>> from dotenv import load_dotenv
>>> load_dotenv()
True
>>> cnxn = pyodbc.connect(os.getenv('CSTRING'))
>>> cnxn.setdecoding(pyodbc.SQL_WCHAR, encoding='UTF-8')
>>> cnxn.setdecoding(pyodbc.SQL_CHAR, encoding='UTF-8')
>>> cnxn.setencoding(encoding='UTF-8')

Here we are importing os to access environment variables, pyodbc to connect, and load_dotenv to load the variables from the .env file. Next we store a pyodbc connection in the cnxn variable. os.getenv('CSTRING') loads the connectionstring from the environment variable. The cnxn.setdecoding() and cnxn.setencoding() methods are going to make sure that the client and the server can understand each other.

Now that we are connected, we can make some queries!

>>> crsr = pyodbc.cursor()
>>> crsr.execute('SELECT * FROM AgentConnectionDetail LIMIT 5')
>>> rows = crsr.fetchall()
>>> cnxn.close()

Here, we are creating a cursor object from which we will query the database. The crsr.execute() method takes a string containing your SQL query and executes the query. To get the results of the query we call crsr.fetch_all() which will return a list of tuples for each row returned by the query. Finally, we call cnxn.close() to close the database connection.

Acknowledgements

And there we have it. A connection to the UCCX historical database. If someone ends up reading this, I hope you found it helpful. Here is a list of additional resources that you may find useful:

UCCX Database Schema

Pyodbc Documentation

And here are the sources I used when trying to figure out how to put this all together:

UCCX Stats ODBC Guide

StackOverflow post on UCCX connectionstring

Read More

Hello World!

Published:

I've been pushing this off for a long time, but with the 'rona granting me some additional time, I finally built a version of my website that has a blog! If you click that link it will take you to the code on my gitea site.

It isn't the prettiest thing, and I plan to make some improvements in the future, but it is functional and I can make blog posts!

I plan on using this blog to write about the three things that I have the most to say about: cooking, politics, and code!

There are no comments right now, but I plan on adding that functionality in the future. If you have something to add, shoot me an email with the email link (at the side or below) or tweet me: @seaparter.

Oh, fun! After posting this, I see that the links within are inheriting some styles to make them look like buttons on the post preview. I guess I'll have to edit that stylesheet soon.

Edit: The styles are fixed now.

Read More