- When I finished coding the “notes” app 2 years ago, I wasn’t really sure I’d ever touch the site again.
- It’s still very BETA, broken, unfinished. I have a lot of work to do if I want to get serious.
- It has potential, especially if I were 20 years younger and could crank out the mad code.
- Now feels right, and I’ve been talking to Justin (iykyk).
- Let’s see what happens …
SWI PROLOG: interfacing as a process singleton
Link to SWI page: https://www.swi-prolog.org/contrib/DotNetInterface.md
RUBY SCRIPT:
#!/usr/bin/env ruby
$prologRef = nil
$prologTempDir = "/Users/daniel/Desktop/Temp/"
$prologExe = "/opt/local/bin/swipl"
$isHalted = false
def StartProlog
$prologRef = IO.popen($prologExe,"w")
$isHalted = false
end
def StopProlog
$prologRef.close_write
$isHalted = true
end
def CallProlog(statement)
$prologRef.puts "call((" + statement + "))."
end
def IsTrueProlog(statement)
t = Time.now
srand(t.to_i)
randNum = rand(10000)
$prologRef.puts "tell('" + $prologTempDir + "TEST" + randNum.to_s + "')."
$prologRef.puts "(" + statement + ") -> write('true') ; write('false')."
$prologRef.puts "told."
accumulate = ""
isRead = false
while not isRead
if $isHalted == true
return false
end
begin
File.open($prologTempDir + "TEST" + randNum.to_s) do |query_result|
query_result.each do |line|
accumulate += line
end
isRead = true
end
rescue
end
end
File.delete($prologTempDir + "TEST" + randNum.to_s)
if accumulate != "true"
return false
else
return true
end
end
def QueryProlog(variablelist,query)
t = Time.now
srand(t.to_i)
randNum = rand(10000)
$prologRef.puts "tell('" + $prologTempDir + "QUERY" + randNum.to_s + "')."
$prologRef.puts "findall((" + variablelist + "),(" + query + "),Z),write(Z),fail."
$prologRef.puts "told."
accumulate = ""
isRead = false
while not isRead
if $isHalted == true
return ""
end
begin
File.open($prologTempDir + "QUERY" + randNum.to_s) do |query_result|
query_result.each do |line|
accumulate += line
end
isRead = true
end
rescue
puts "error"
end
end
File.delete($prologTempDir + "QUERY" + randNum.to_s)
return accumulate
end
StartProlog()
CallProlog("assert(dog(dan))")
CallProlog("assert(dog(jim))")
CallProlog("assert(dog(pete))")
for i in 0 ... 100
CallProlog("assert(person(fname(dan" + i.to_s + "),lname(sull" + i.to_s + ")))")
end
f = File.open("/Users/daniel/Desktop/Temp/results.md","w")
f.puts QueryProlog("X,Y","person(X,Y)")
f.puts QueryProlog("X","dog(X)")
f.puts IsTrueProlog("dog(ddddddan)")
f.close_write
StopProlog()
C# wrapper:
using System;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
namespace LogicEngineLib
{
public class LogicEXE
{
public Process p = null;
public int PID = -999;
private string _dumpDir;
private string _plcon;
private int _timeOut;
public LogicEXE(string dumpDir, string plCon, int timeoutMilliseconds)
{
this._timeOut = timeoutMilliseconds;
this.p = new Process();
this.p.StartInfo.FileName = plCon;
this.p.StartInfo.RedirectStandardInput = true;
this.p.StartInfo.UseShellExecute = false;
this.p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
this.p.StartInfo.CreateNoWindow = true;
this._dumpDir = dumpDir;
this._plcon = plCon;
this.p.Start();
this.PID = this.p.Id;
}
public string ReStart()
{
this.p = new Process();
this.p.StartInfo.FileName = this._plcon;
this.p.StartInfo.RedirectStandardInput = true;
this.p.StartInfo.UseShellExecute = false;
this.p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
this.p.StartInfo.CreateNoWindow = true;
this.p.Start();
this.PID = this.p.Id;
return "Restarted service.";
}
public void Write(string statement)
{
this.p.StandardInput.WriteLine(statement);
}
public string Stop()
{
this.p.Close();
return "Process Stopped.";
}
public string Assert(string query)
{
this.Write("assert(" + query + ").");
return "Assert performed.";
}
public string Call(string execString)
{
execString = execString.Replace('.',' ');
string sres = Guid.NewGuid().ToString();
Write("tell('" + this._dumpDir.Replace('\\', '/') + sres + "').");
this.Write("call(" + execString + ") -> write('Call Succeeded') ; write('Call Failed').");
Write("told.");
string rstr = string.Empty;
rstr = SpinAndWaitRead(this._dumpDir + sres);
return rstr;
}
public void Consult(string file)
{
this.Write("consult('" + file.Replace('\\', '/') + "').");
}
public string Save(string fileNamePath)
{
Write("tell('" + fileNamePath.Replace("\\","/") + "').");
Write("listing.");
Write("told.");
return "Save Accomplished";
}
public bool IsTrue(string query)
{
query = query.Replace('.', ' ');
StringBuilder sb = new StringBuilder();
Hashtable ht = new Hashtable(20);
bool hasVariables = false;
string[] vars = GetTokens(query);
foreach (string s in vars)
{
if (s.Trim().Length > 0)
{
char[] carr = s.ToCharArray();
if (Char.IsUpper(carr[0]))
{
string tmp = s.Trim();
if (!ht.Contains(tmp))
{
ht[tmp] = tmp;
sb.Append(" " + s);
}
hasVariables = true;
}
}
}
if (hasVariables) return false;
string sres = Guid.NewGuid().ToString();
Write("tell('" + this._dumpDir.Replace('\\', '/') + sres + "').");
Write("(" + query + ") -> write('True') ; write('False').");
Write("told.");
string rstr = string.Empty;
rstr = SpinAndWaitRead(this._dumpDir + sres);
if (rstr.Trim().Length < 4) return false;
bool result = false;
try
{
result = bool.Parse(rstr);
return result;
}
catch
{
return false;
}
}
public string Query(string query, bool distinctResults)
{
query = query.Replace('.',' ');
StringBuilder sb = new StringBuilder();
Hashtable ht = new Hashtable(20);
bool hasVariables = false;
string[] vars = GetTokens(query);
foreach (string s in vars)
{
if (s.Trim().Length > 0)
{
string tmp1 = s.Trim();
char[] carr = tmp1.ToCharArray();
if (Char.IsUpper(carr[0]))
{
string tmp = s.Trim();
if (!ht.Contains(tmp))
{
ht[tmp] = tmp;
sb.Append(" " + s);
}
hasVariables = true;
}
}
}
string sres = Guid.NewGuid().ToString();
Write("tell('" + this._dumpDir.Replace('\\', '/') + sres + "').");
if (hasVariables)
{
if (distinctResults)
{
Write("setof((" + sb.ToString().Trim().Replace(" ", ",") + ") ,(" + query + "),Z),write(Z),fail.");
}
else
{
string tres = "findall((" + sb.ToString().Trim().Replace(" ", ",") + ") ,(" + query + "),Z),write(Z),fail.";
Write(tres);
}
}
else
{
Write(query + ".");
}
Write("told.");
string rstr = string.Empty;
rstr = SpinAndWaitRead(this._dumpDir + sres);
return rstr;
}
public string Listing()
{
string sres = Guid.NewGuid().ToString();
Write("tell('" + this._dumpDir.Replace('\\', '/') + sres + "').");
Write("listing.");
Write("told.");
string rstr = string.Empty;
rstr = SpinAndWaitRead(this._dumpDir + sres);
return rstr;
}
private string SpinAndWaitRead(string fileName)
{
StreamReader sr = null;
string rstr = string.Empty;
int counter = 0;
bool done = false;
while (!done)
{
try
{
if (File.Exists(fileName))
{
sr = new StreamReader(fileName);
rstr = sr.ReadToEnd();
sr.Close();
done = true;
}
}
catch
{
continue;
}
counter++;
System.Threading.Thread.Sleep(1);
if (counter == this._timeOut) break;
}
try
{
File.Delete(fileName);
}
catch { }
return rstr;
}
private string[] GetTokens(string prologStatement)
{
string[] vars = Regex.Split(prologStatement, @"[,)(=;+:%$@~^/\-><@&*!]");
return vars;
}
}
}
Your own daily dose … (of the news)

- Below is a general recipe for experimenting with RSS feeds AND speech synthesizers.
- For the speech synthesis there are two scripts, very similar, one will work with ESPEAK (free open source), the other works with Microsoft SAPI.
- In order to run these scripts you will need MYSQL installed. You will need a minimum level of understanding of how MYSQL works. You can easily translate the database piece to ODBC, and the rest to PowerShell or whatever. That’s your business, not mine.
- Once you’ve installed MYSQL and the server is running, create a database called “NEWS”: create database NEWS;
- After you’ve created the NEWS database, using the CLI (command line interface) as above, type command: use NEWS;
- Once you are in the NEWS database, copy and paste the entire script below into the CLI or save as text file and consult from the CLI using the command: source rss.sql (assuming you stored the create table text below in that file)
- In the example I’m using the ROOT database, why? – because IDGAF. But best practice is to create special database users with limited permissions. If you’ve installed your MYSQL database without granting permission to external (port) connections? – then it’s not a concern.
- Running the aggregator might trigger a site to block you or even your own network. This behavior, which was innocuous 20 years ago, is now attacked and classified as an aggressive network behavior. Just be careful.
- After you’ve run the aggregation script (and the script can be run by CRON or Task Manager daily or hourly if you like), then you can run one of the speech synthesis apps, reading headlines.
- If you have a compatible shortwave radio, with upper and lower side band, and a LINUX computer running JS8 Call with appropriate libraries for CAT control? – then look into this and you can set up a headline service over shortwave: https://planetarystatusreport.com/?p=7432
Have fun getting your daily dose of the fucking news.
Create Table Script for RSS Database
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET AUTOCOMMIT = 0;
START TRANSACTION;
SET time_zone = "+00:00";
CREATE TABLE `RSS` (
`ID` bigint(20) NOT NULL,
`SOURCE` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`LINK` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`TITLE` varchar(400) COLLATE utf8_unicode_ci NOT NULL,
`PUBLISHED` datetime NOT NULL,
`ARTICLE` text COLLATE utf8_unicode_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
ALTER TABLE `RSS`
ADD PRIMARY KEY (`ID`),
ADD UNIQUE KEY `unique_link` (`LINK`);
ALTER TABLE `RSS`
MODIFY `ID` bigint(20) NOT NULL AUTO_INCREMENT;
COMMIT;
Python Script for Aggregating RSS Feeds and storing stories locally
from __future__ import print_function
import os
import feedparser
import os.path, time
import json
import math
import time
import urllib.parse as pr
import xml.etree.ElementTree as ET
from bs4 import BeautifulSoup as BS
from requests import get
from os.path import exists
from socket import socket, AF_INET, SOCK_STREAM
from decimal import Decimal
from datetime import datetime, date, timedelta
from anyascii import anyascii
import mysql.connector
usern = "root"
passw = "password"
dbn = "NEWS"
servern = "localhost"
portn = 3306
newsServiceM3 = "ZEROHEDGE"
retHeadlines = 4
newsMode = 3
bigSleep = 90
def GetArt(number):
# Connect with the MySQL Server
cnx = mysql.connector.connect(user=usern, database=dbn, password=passw, host=servern, port=portn)
qry = "select ARTICLE, SOURCE, LINK from RSS where ID = %s" % (number)
cur = cnx.cursor(buffered=True)
cur.execute(qry)
retRes = cur.fetchall()
cnx.close()
return retRes[0]
def GetTopHourly(source):
# Connect with the MySQL Server
cnx = mysql.connector.connect(user=usern, database=dbn, password=passw, host=servern, port=portn)
qry = "select ID, TITLE, PUBLISHED, SOURCE, length(ARTICLE) as LOF from RSS where SOURCE = '%s' order by PUBLISHED desc limit 1" % source
cur = cnx.cursor(buffered=True)
cur.execute(qry)
retRes = cur.fetchall()
cnx.close()
return retRes
def GetTop(source, number):
# Connect with the MySQL Server
cnx = mysql.connector.connect(user=usern, database=dbn, password=passw, host=servern, port=portn)
qry = "select ID, TITLE, PUBLISHED, SOURCE, length(ARTICLE) as LOF from RSS where SOURCE = '%s' order by PUBLISHED desc limit %s" % (source, number)
cur = cnx.cursor(buffered=True)
cur.execute(qry)
retRes = cur.fetchall()
cnx.close()
return retRes
def AlreadySaved(link):
# Connect with the MySQL Server
cnx = mysql.connector.connect(user=usern, database=dbn, password=passw, host=servern, port=portn)
qry = "select ID from RSS where LINK = '" + link + "'"
cur = cnx.cursor(buffered=True)
cur.execute(qry)
cur.fetchall()
rc = cur.rowcount
cnx.close()
if rc > 0:
return True
else:
return False
def SaveRSS(source, title, link, published, article):
tit = title.replace("'", "''")
clean_text = anyascii(article)
art = str(clean_text)
art = art.replace("'", "''")
if len(art) > 5000:
art = art[0:5000]
cnx = mysql.connector.connect(user=usern, database=dbn, password=passw, host=servern, port=portn)
cur = cnx.cursor()
qry = """
INSERT INTO RSS
(SOURCE,
LINK,
TITLE,
PUBLISHED,
ARTICLE)
VALUES
(%s,%s,%s,%s,%s)
"""
val = (source, link, tit, published, art)
cur.execute(qry, val)
cnx.commit()
cnx.close()
def GrabRSS(RssURL, SourceName):
hdrs = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'}
NewsFeed = feedparser.parse(RssURL)
for na in NewsFeed.entries:
try:
print(na.title)
print(na.link)
print(na.published)
print(na.published_parsed)
except:
continue
if AlreadySaved(na.link):
continue
print("*************************")
response = get(na.link, None, headers=hdrs)
print(na.keys())
soup = BS(response.content, 'html.parser')
txtChunk = ""
for data in soup.find_all("p"):
txtval = data.get_text()
txtval = txtval.strip()
txtarr = txtval.split()
if len(txtarr) == 1:
continue
if "posted" in txtval and ("hours" in txtval or "days" in txtval) and len(txtarr) == 4:
continue
if txtval == "No Search Results Found":
continue
if txtval == "Terms of Service":
continue
if txtval == "Advertise with us":
continue
if txtval == "Media Inquiries":
continue
txtChunk += " " + txtval + "\n"
tyr = na.published_parsed[0]
tmn = na.published_parsed[1]
tdy = na.published_parsed[2]
thr = na.published_parsed[3]
tmi = na.published_parsed[4]
tsc = na.published_parsed[5]
ptms = "%s-%s-%s %s:%s:%s" % (tyr, tmn, tdy, thr, tmi, tsc)
SaveRSS(SourceName, na.title, na.link, ptms, txtChunk.strip())
print(txtChunk.strip())
def debugHere():
input("Press enter to continue ...")
def clearConsole():
command = 'clear'
if os.name in ('nt', 'dos'): # If Machine is running on Windows, use cls
command = 'cls'
os.system(command)
def CycleFeeds():
infowars = "https://www.infowars.com/rss.xml"
zh = "https://feeds.feedburner.com/zerohedge/feed"
yahoo = "https://news.yahoo.com/rss/"
cnn = "http://rss.cnn.com/rss/cnn_topstories.rss"
bbc = "http://feeds.bbci.co.uk/news/world/us_and_canada/rss.xml"
nyt = "https://rss.nytimes.com/services/xml/rss/nyt/HomePage.xml"
onion = "https://www.theonion.com/rss"
bb = "https://babylonbee.com/feed"
print("Grabbing Babylon Bee ...")
GrabRSS(bb, "BB")
print("Grabbing ONION ...")
GrabRSS(onion, "ONION")
print("Grabbing INFOWARS ...")
GrabRSS(infowars, "INFOWARS")
print("Grabbing ZEROHEDGE ...")
GrabRSS(zh, "ZEROHEDGE")
#print("Grabbing YAHOO ...")
#GrabRSS(yahoo, "YAHOO")
print("Grabbing CNN ...")
GrabRSS(cnn, "CNN")
print("Grabbing BBC ...")
GrabRSS(bbc, "BBC")
print("Grabbing NYT ...")
GrabRSS(nyt, "NYT")
# FEEDS:
# 1. INFOWARS: https://www.infowars.com/rss.xml
# 2. ZEROHEDGE: https://feeds.feedburner.com/zerohedge/feed
# 3. YAHOO: https://news.yahoo.com/rss/
# 4. CNN: http://rss.cnn.com/rss/cnn_topstories.rss
time.sleep(1)
CycleFeeds()
Python Speech Synthesis Scripts
A: Windows – SAPI
#this script reads headlines from the RSS news feed
#database.
import win32com.client
speaker = win32com.client.Dispatch("SAPI.SpVoice")
import os
import time
import mysql.connector
usern = "root"
passw = "password"
dbn = "NEWS"
servern = "localhost"
portn = 3306
def TOS(text):
os.system(f"espeak -s 130 -v en+m1 '{text}'")
def GetSql(qry):
# Connect with the MySQL Server
cnx = mysql.connector.connect(user=usern, database=dbn, password=passw, host=servern, port=portn)
cur = cnx.cursor(buffered=True)
cur.execute(qry)
retRes = cur.fetchall()
cnx.close()
return retRes
#+-----------+--------------+------+-----+---------+----------------+
#| Field | Type | Null | Key | Default | Extra |
#+-----------+--------------+------+-----+---------+----------------+
#| ID | bigint(20) | NO | PRI | NULL | auto_increment |
#| SOURCE | varchar(100) | NO | | NULL | |
#| LINK | varchar(255) | NO | UNI | NULL | |
#| TITLE | varchar(400) | NO | | NULL | |
#| PUBLISHED | datetime | NO | | NULL | |
#| ARTICLE | text | NO | | NULL | |
#+-----------+--------------+------+-----+---------+----------------+
qry1 = "select SOURCE, TITLE from RSS where PUBLISHED > curdate()-1 order by PUBLISHED desc;"
res = GetSql(qry1)
for rec in res:
src = rec[0]
tit = rec[1].replace("''", "")
print(src + ": " + tit)
phrase = "From " + src + ", HEAD LINE, " + tit
speaker.Speak(phrase)
time.sleep(2)
B: Linux – ESPEAK
import os
import time
import mysql.connector
usern = "root"
passw = "password"
dbn = "NEWS"
servern = "localhost"
portn = 3306
def TOS(text):
os.system(f"espeak -s 130 -v en+m1 '{text}'")
def GetSql(qry):
# Connect with the MySQL Server
cnx = mysql.connector.connect(user=usern, database=dbn, password=passw, host=servern, port=portn)
cur = cnx.cursor(buffered=True)
cur.execute(qry)
retRes = cur.fetchall()
cnx.close()
return retRes
#+-----------+--------------+------+-----+---------+----------------+
#| Field | Type | Null | Key | Default | Extra |
#+-----------+--------------+------+-----+---------+----------------+
#| ID | bigint(20) | NO | PRI | NULL | auto_increment |
#| SOURCE | varchar(100) | NO | | NULL | |
#| LINK | varchar(255) | NO | UNI | NULL | |
#| TITLE | varchar(400) | NO | | NULL | |
#| PUBLISHED | datetime | NO | | NULL | |
#| ARTICLE | text | NO | | NULL | |
#+-----------+--------------+------+-----+---------+----------------+
qry1 = "select SOURCE, TITLE from RSS where PUBLISHED > curdate()-1 order by PUBLISHED desc;"
res = GetSql(qry1)
for rec in res:
src = rec[0]
tit = rec[1].replace("''", "")
print(src + ": " + tit)
phrase = "From " + src + ", HEAD LINE, " + tit
TOS(phrase)
time.sleep(0.5)
I’m beginning to think …
I’m beginning to think the approach I’ve been taking with JS8 call is a bridge too far – and that I would be better off learning to compile the code, and just create my own branch. Make the changes I want in C++ to include interop with websites that are accessible on some given network using standard REST calls. Also, allow it a scripted response model so that any given JS8Call app can act as a “radio service” taking messages, and replying. Also, add in flexible topology and multi-app running instances on the same computer. Who knows, add in a built in connector for MYSQL for data logging and event logging for outside of process coding and scripting by other consumers … so I don’t know if I can, I’m 53 and burnt out and believe the world could explode, figuratively, in a few months.
But is it the end of the world? – no, not by a long shot …
So maybe I try.
Will it be easy? – don’t know … I think
And here’s the other thing …
JS8Call, RIGHT NOW, AS IS would allow you to build an organic twitter style decentralized relationship with other people using CB radio and this network WORKS even if the WWW is down … is it good for secrets, as is? – no … is it good enough for the public square? – yes.
You could sell eggs, right now, using JS8Call on CB Radio – just need to expand the network, more users, bigger world.
And I would think a lot of real anarchists and libertarians would be into this …
CB RADIO – NO HAM LICENSE …
(and then we go from there)
And this is all in JS8CALL.COM right now.
With some work? – who the fuck knows what’s possible.
I feel like the world of shortwave radio, and CB, needs a revolution – and this could be the beginning.
Making fire, breaking free …
How you do CB, how we do CB … RADENGINEERING.TECH
“YOU CAN’T DO THAT!” (from REDDIT)



Is JS8 only for low power?
RAD ENGINEERING: at the gun show … (Vernal, UT, 2/12/22)
RAD-TERMINAL: HOW TO HAVE FREE OFF GRID INTERNET 4-LIFE!
Where: https://www.preppershowsusa.com/prepper-show/be-prepared-expo-2022/
When: 4/23/2022, 11 AM MST (Utah Time)
Room: Classroom B
What: Class/Presentation “RAD ENGINEERING: FIFL”
Presenters: Justin Land and Dan Sullivan
Outline:
- Introduction: How we got into this, the story of RAD ENGINEERING. WHAT IS THE RAD TERMINAL? (5 minutes)
- Hardware: a) radio, b) computer, c) linkages and wiring … history of the radio tech and how it’s being used. JS8 (20 minutes)
- Software: history of WWW, what happened to TECH in the 70’s … why couldn’t we hook up TRS-80 / C64 computers to a CB in 1983 … what are bulletin boards? – how is radio LIKE a bulletin board … encryption strategies … encoding … ARS: Amateur Radio Services … what is an ARS? – remote procedure calls over CB radio, hitting python-agent receivers, hooking into actions … >sendto: >email: >payment: … command tags … EDI for radio? – small compact messaging AND payment services using voice recognition (20 minutes)
- Q/A (15 minutes)