It took an unexpectedly long time to find the censored word list in Discourse. I finally resorted to searching the PRs until I located one where the censored word list was replaced with ‘watched words’ … although there wasn’t any readily apparent watched word list in the configuration either. I was able to locate the meta post regarding the watched word implemented under that PR. It’s hiding under logs?! Under each action (block, censor, require approval, flag), there is a “show words” checkbox that displays the configured words.
Category: Technology
ADO Notifications
I’ve been underwhelmed with the notifications I get from Azure DevOps – there are a lot of build-centric notifications, but I don’t use ADO for builds or deployment apart from playing around. And I really don’t care if the silly test project I set up to build and deploy a website worked, failed, or whatever. I was thinking about hooking whatever they’re calling Flow this week up to ADO and building notification workflows.
Fortunately, a coworker mentioned that you can customize notifications in ADO … which, I’d spent a few seconds poking around and didn’t see anything. But I spent more than a few seconds this time and happened across this little ellipsis on the card that pops up when I click the circle with my initials in it. More options!
A new menu flies out; and, look, there’s “Notifications”
Exactly as I’ve observed, there are a lot of build-centric alerts. So I created a new subscription.
Here’s a subscription that I hope will notify me when items assigned to me have updates to activity or comments.
Discourse in Docker on Fedora 32
I had to make a few tweaks in order to run the Discourse base Docker image. First, I got the following very clear error:
discourse docker this version of runc doesn't work on cgroups v2: unknown
I had to switch from cgroupv2 to cgroup
grubby --update-kernel=ALL --args="systemd.unified_cgroup_hierarchy=0"
At which point I was at least able to run through the configuration. This yielded an access denied error attempting to create /shared/postgres:
Configuration file at updated successfully! Updates successful. Rebuilding in 5 seconds. Building app Ensuring launcher is up to date Fetching origin Launcher is up-to-date cd /pups && git pull && /pups/bin/pups --stdin Already up to date. I, [2020-08-11T18:15:03.664400 #1] INFO -- : Loading --stdin I, [2020-08-11T18:15:03.672609 #1] INFO -- : > locale-gen $LANG && update-locale I, [2020-08-11T18:15:03.746912 #1] INFO -- : Generating locales (this might take a while)... Generation complete. I, [2020-08-11T18:15:03.747838 #1] INFO -- : > mkdir -p /shared/postgres_run mkdir: cannot create directory ‘/shared/postgres_run’: Permission denied I, [2020-08-11T18:15:03.754890 #1] INFO -- : FAILED -------------------- Pups::ExecError: mkdir -p /shared/postgres_run failed with return #<Process::Status: pid 21 exit 1> Location of failure: /pups/lib/pups/exec_command.rb:112:in `spawn' exec failed with the params "mkdir -p /shared/postgres_run" d98ee8471413ad77ab27ed3506f12c5c94a2b6902622faf4d88d5dbb51a10f63 ** FAILED TO BOOTSTRAP ** please scroll up and look for earlier error messages, there may be more than one. ./discourse-doctor may help diagnose the problem.
Gut was that I encountered an SELinux problem. Turns out I was right. There’s a lot of reading you can do about SELinux and Docker — this, for one — but the quick and simple solution is to run the docker container in privileged mode (note: this may not be a good idea in your specific scenario. understand what privileged mode is and the risks it entails). To do so, edit the launcher script (/var/discourse/launcher in my case) and add “–privileged” to user_args:
And finally (and this may well be a RTFM thing) — you’ve got to have your public DNS set up & whatever firewall rules to get traffic to the http:// website you are trying to build in order to use the LetsEncrypt SSL cert and configure HTTPS. It uses the file-based verification (i.e. create a file named xyz in /path/to/xyz.whatever on your web server, lets encrypt grabs the file and verifies it exists) which fails quite spectacularly when the Internet at large cannot access your about-to-be-a-discourse-server.
Exporting Microsoft Stream Transcript
Microsoft has changed the interface on Stream slightly, so my code to export the Stream transcript needed an update. since copy/paste doesn’t seem to work for everyone, the script is also available as a text file.
var objTranscriptionLines = window.angular.element(window.document.querySelectorAll('.transcript-list')).scope().$ctrl.transcriptLines;
var strRunningText = "";
for(var i = 0; i < objTranscriptionLines.length; i++){
if( objTranscriptionLines[i] ){
var strLineText = objTranscriptionLines[i].eventData.text;
strRunningText = strRunningText + "\n" + strLineText;
}
}
console.log(strRunningText);
Building LIB_MYSQLUDF_SYS On Fedora 31
I moved my MariaDB server to a new host and could not follow my previously working instructions to build lib_mysqludf_sys. The error indicated that my_atomic.h was not found.
[lisa@server03 lib_mysqludf_sys]# make gcc -fPIC -Wall -I/usr/include/mysql/server -I. -shared lib_mysqludf_sys.c -o /usr/lib64/mariadb/plugin//lib_mysqludf_sys.so In file included from /usr/include/mysql/server/my_sys.h:34, from lib_mysqludf_sys.c:41: /usr/include/mysql/server/my_pthread.h:26:10: fatal error: my_atomic.h: No such file or directory 26 | #include <my_atomic.h> | ^~~~~~~~~~~~~ compilation terminated. make: *** [Makefile:4: install] Error 1
The missing file is located in /usr/include/mysql/server/private … so I had to include that file in the gcc command as well. My new Makefile reads as follows:
[lisa@server03 lib_mysqludf_sys]# cat Makefile LIBDIR=/usr/lib64/mariadb/plugin/ install: gcc -fPIC -Wall -I/usr/include/mysql/server -I/usr/include/mysql/server/private -I. -shared lib_mysqludf_sys.c -o $(LIBDIR)/lib_mysqludf_sys.so
I was then able to make and use install.sh to load it into MariaDB.
HTML Checkbox Adding and Removing Table Row
Here’s the JavaScript code I ended up using to add and remove rows from a table based on a checkbox selection (and only allowing one checkbox per group to be selected). The biggest change is that I added a name and ID to my TR for easier identification.
$(document).on("change", "input[type='checkbox']", function () {
var $objCheckbox = $(this);
if ($objCheckbox.is(":checked")) { // When checked, deactivate other checkboxes and add to sets to create table
var objCheckboxGroup = "input:checkbox[tableselector='" + $objCheckbox.attr("tableselector") + "']";
$(objCheckboxGroup).prop("disabled", true);
$objCheckbox.prop("disabled", false); // Allow checked box to be unchecked
addSetToCreatingTable($objCheckbox.attr("setname"), $objCheckbox.attr("settype"), $objCheckbox.attr("goodcircuits") + "|" + $objCheckbox.attr("value"), $objCheckbox.attr("tableselector"));
}
else { // When unchecked, active checkboxes and remove from sets to create table
var objCheckboxGroup = "input:checkbox[name='" + $objCheckbox.attr("name") + "']";
$(objCheckboxGroup).prop("disabled", false);
$("#" + $objCheckbox.attr('tableselector')).each(function(){ $(this).remove();})
}
});
What Can I sudo?
Some 90% of my Linux experience is on servers where I have root or root-equivalent access (i.e. I can sudo anything). In those cases, ‘what can I run under sudo’ was never a question. And I’d use something like “sudo less /etc/sudoers” to inspect what someone else was able to run when they questioned their access. In my new position, we have a lot of servers that we own too — the Engineering IT support group lets us spin up our own VMs, do whatever we want (within reason). But we have a few IT-managed servers with very restricted rights. And the commands I would use to perform functions (think systemctl restart httpd) aren’t in my sudoers access list. Luckily you can list out what you can run under sudo:
$ sudo -l [sudo] password for useraccount: Matching Defaults entries for useraccount on this host: syslog=auth, loglinelen=0, syslog_goodpri=info, syslog_badpri=err, logfile=/var/log/sudo.log User useraccount may run the following commands on this host: (ALL) /opt/lampp/lampp start, (ALL) /opt/lampp/lampp stop, (ALL) /opt/lampp/lampp restart, (ALL) /usr/sbin/apachectl
And that is how I know to use apachectl instead of systemctl.
HTML Checkboxes To Add and Remove Values from Table
I am creating a web form where the user input sometimes cannot be resolved to a unique value. In those cases, I present the user a set of checkboxes with the options (yes, a radio button makes more sense because you can only select one. But I hate that radio buttons change selection when you hit an arrow key.).
When a selection is made, I need to (1) deactivate the checkboxes for the other options when a checkbox in the group is selected and (2) add information to a data table that is used in subsequent activities.
When a selection is cleared, I need to (1) activate the checkboxes within the group and (2) remove the right row from the data table.
Below is the HTML code that achieves this. Now I just need to map this test page into the actual web code. There’s a post with the actual code I ended up using in production too.
<html>
<head><title>Adding And Removing From Table</title></head>
<body>
<div name="divCircuitClarifications" id="divCircuitClarifications">
<h3>My-Sample-Circuit-A</h3>
<input type="checkbox" value="123" tableselector="SampleCircuitA" name="SampleCircuitA[]" /><label>123</label>
<input type="checkbox" value="234" tableselector="SampleCircuitA" name="SampleCircuitA[]" /><label>234</label>
<input type="checkbox" value="345" tableselector="SampleCircuitA" name="SampleCircuitA[]" /><label>345</label>
<P>
<h3>My-Sample-Circuit-B</h3>
<input type="checkbox" value="abc" tableselector="SampleCircuitB" name="SampleCircuitB[]" /><label>abc</label>
<input type="checkbox" value="bcd" tableselector="SampleCircuitB" name="SampleCircuitB[]" /><label>bcd</label>
<input type="checkbox" value="cde" tableselector="SampleCircuitB" name="SampleCircuitB[]" /><label>cde</label>
<P>
<h3>My-Sample-Circuit-C</h3>
<input type="checkbox" value="Cabc" tableselector="SampleCircuitC" name="SampleCircuitC[]" /><label>abc</label>
<input type="checkbox" value="Cbcd" tableselector="SampleCircuitC" name="SampleCircuitC[]" /><label>bcd</label>
<input type="checkbox" value="Ccde" tableselector="SampleCircuitC" name="SampleCircuitC[]" /><label>cde</label>
<P>
</div>
<div id="divResultTable" name="divResultTable">
<table border="1" padding="1" name="tableSetsToCreate" id="tableSetsToCreate">
<thead><tr><th>ECCKT</th><th>Circuit ID</th></tr></thead>
<tbody></tbody>
</table>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
$("input:checkbox").on('click', function() {
var $objCheckbox = $(this);
if ($objCheckbox.is(":checked")) { // When checked, deactivate other checkboxes and add to sets to create table
var objCheckboxGroup = "input:checkbox[tableselector='" + $objCheckbox.attr("tableselector") + "']";
$(objCheckboxGroup).prop("disabled", true);
$objCheckbox.prop("disabled", false); // Allow checked box to be unchecked
var strTableRowString = '<tr><td>' + $objCheckbox.attr("tableselector") + '</td><td>' + $objCheckbox.val() + '</td>\n';
$('#tableSetsToCreate tbody').append(strTableRowString);
}
else { // When unchecked, active checkboxes and remove from sets to create table
var objCheckboxGroup = "input:checkbox[name='" + $objCheckbox.attr("name") + "']";
$(objCheckboxGroup).prop("disabled", false);
$("tr:contains('" + $objCheckbox.attr('tableselector') + "')").each(function(){ $(this).remove();})
}
});
</script>
</body>
Web Stats
Since my website has a lot of information about Microsoft Teams, I can see when a lot of new Teams users came online during the lockdown. Now that people are returning to offices (and, I expect, are more familiar with the platform), I’m starting to see fewer search engine referrals. But I’m still 3-4x the numbers I’d seen pre-lockdown.
Oracle – LISTAGG
I needed to collapse multiple rows into a single row — the circuits within a diversity set are stored within the ds_dvrsty_set_circuit table as individual rows & the ds_dvrsty_set_id links the multiple rows. What I wanted was a set ID, set name, and the list of circuits within the set.
To accomplish this, I found LISTAGG which is a little bit like STUFF in MSSQL. This query produces a single row for each diversity set that contains the set ID, the set name, and a comma delimited list of set members.
SELECT ds_dvrsty_set_circuit.ds_dvrsty_set_id, (select ds_dvrsty_set.ds_dvrsty_set_nm from ds_dvrsty_set where ds_dvrsty_set_id = ds_dvrsty_set_circuit.ds_dvrsty_set_id) as set_name, LISTAGG(ds_dvrsty_set_circuit.circuit_design_id, ',') WITHIN GROUP(ORDER BY ds_dvrsty_set_circuit.ds_dvrsty_set_id) AS member_circuits FROM ds_dvrsty_set_circuit left outer join ds_dvrsty_set on ds_dvrsty_set.ds_dvrsty_set_id = ds_dvrsty_set_circuit.DS_DVRSTY_SET_ID WHERE ds_dvrsty_set_circuit.ds_dvrsty_set_id in (select distinct ds_dvrsty_set_id from ds_dvrsty_set_circuit where circuit_design_id in (14445678, 5078901) ) AND ds_dvrsty_set.ds_dvrsty_set_nm like '43%' GROUP BY ds_dvrsty_set_circuit.ds_dvrsty_set_id ORDER BY ds_dvrsty_set_circuit.ds_dvrsty_set_id;
Voila — exactly what I needed. If the searched circuit design IDs appear in more than one set, there is a new row for each set ID.