first
commit
198b5dc62b
@ -0,0 +1,68 @@
|
|||||||
|
import socket, select, string, sys
|
||||||
|
|
||||||
|
username = raw_input("Enter a username: ") # type: str
|
||||||
|
|
||||||
|
def prompt() :
|
||||||
|
sys.stdout.write('[' + username + '] ');
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
#main function
|
||||||
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
if(len(sys.argv) < 3) :
|
||||||
|
print 'Usage: python telnet.py hostname port'
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
host = sys.argv[1]
|
||||||
|
port = int(sys.argv[2])
|
||||||
|
|
||||||
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
s.settimeout(2)
|
||||||
|
|
||||||
|
# connect to remote host
|
||||||
|
try :
|
||||||
|
s.connect((host, port))
|
||||||
|
except :
|
||||||
|
print 'Unable to connect'
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
print """
|
||||||
|
/$$ /$$ /$$$$$$$ /$$ /$$ /$$$$$$$ /$$ /$$
|
||||||
|
| $$ / $$| $$__ $$| $$ | $$| $$__ $$ | $$ | $$
|
||||||
|
| $$/ $$/| $$ \ $$| $$ | $$| $$ \ $$ /$$$$$$$| $$$$$$$ /$$$$$$ /$$$$$$
|
||||||
|
\ $$$$/ | $$$$$$$/| $$ | $$| $$$$$$$ /$$_____/| $$__ $$ |____ $$|_ $$_/
|
||||||
|
>$$ $$ | $$____/ | $$ | $$| $$__ $$ | $$ | $$ \ $$ /$$$$$$$ | $$
|
||||||
|
/$$/\ $$| $$ | $$ | $$| $$ \ $$ | $$ | $$ | $$ /$$__ $$ | $$ /$$
|
||||||
|
| $$ \ $$| $$ | $$$$$$/| $$$$$$$/ | $$$$$$$| $$ | $$| $$$$$$$ | $$$$/
|
||||||
|
|__/ |__/|__/ \______/ |_______/ \_______/|__/ |__/ \_______/ \___/
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
print 'Connected to remote host. Start sending messages'
|
||||||
|
prompt()
|
||||||
|
|
||||||
|
s.send(username);
|
||||||
|
|
||||||
|
while 1:
|
||||||
|
socket_list = [sys.stdin, s]
|
||||||
|
|
||||||
|
# Get the list sockets which are readable
|
||||||
|
read_sockets, write_sockets, error_sockets = select.select(socket_list , [], [])
|
||||||
|
|
||||||
|
for sock in read_sockets:
|
||||||
|
#incoming message from remote server
|
||||||
|
if sock == s:
|
||||||
|
data = sock.recv(4096)
|
||||||
|
if not data :
|
||||||
|
print '\nDisconnected from chat server'
|
||||||
|
sys.exit()
|
||||||
|
else :
|
||||||
|
#print data
|
||||||
|
sys.stdout.write(data)
|
||||||
|
prompt()
|
||||||
|
|
||||||
|
#user entered a message
|
||||||
|
else :
|
||||||
|
msg = sys.stdin.readline()
|
||||||
|
s.send(msg)
|
||||||
|
prompt()
|
@ -0,0 +1,84 @@
|
|||||||
|
import socket, select
|
||||||
|
|
||||||
|
#Function to broadcast chat messages to all connected clients
|
||||||
|
def broadcast (server_socket, sock, message):
|
||||||
|
for socket in CONNECTION_LIST:
|
||||||
|
if socket != server_socket and socket != sock : #Do not send the message to master socket and the client who has send us the message
|
||||||
|
try :
|
||||||
|
socket.send(message)
|
||||||
|
except :
|
||||||
|
# broken socket connection may be, chat client pressed ctrl+c for example
|
||||||
|
socket.close()
|
||||||
|
CONNECTION_LIST.remove(socket)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
# List to keep track of socket descriptors
|
||||||
|
CONNECTION_LIST = []
|
||||||
|
RECV_BUFFER = 4096 # Advisable to keep it as an exponent of 2
|
||||||
|
PORT = 5000 # you can change the port if you want
|
||||||
|
USERNAMES = {} #new data structure
|
||||||
|
|
||||||
|
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
# this has no effect, why ?
|
||||||
|
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
server_socket.bind(("0.0.0.0", PORT))
|
||||||
|
server_socket.listen(10)
|
||||||
|
|
||||||
|
# Add server socket to the list of readable connections
|
||||||
|
CONNECTION_LIST.append(server_socket)
|
||||||
|
|
||||||
|
print "Your chat server started on port " + str(PORT)
|
||||||
|
print """
|
||||||
|
/$$
|
||||||
|
|__/
|
||||||
|
/$$$$$$$ /$$$$$$ /$$$$$$ /$$ /$$ /$$ /$$$$$$$ /$$$$$$
|
||||||
|
/$$_____/ /$$__ $$ /$$__ $$| $$ /$$/| $$| $$__ $$ /$$__ $$
|
||||||
|
| $$$$$$ | $$$$$$$$| $$ \__/ \ $$/$$/ | $$| $$ \ $$| $$ \ $$
|
||||||
|
\____ $$| $$_____/| $$ \ $$$/ | $$| $$ | $$| $$ | $$
|
||||||
|
/$$$$$$$/| $$$$$$$| $$ \ $/ | $$| $$ | $$| $$$$$$$
|
||||||
|
|_______/ \_______/|__/ \_/ |__/|__/ |__/ \____ $$
|
||||||
|
/$$ \ $$
|
||||||
|
| $$$$$$/
|
||||||
|
\______/
|
||||||
|
"""
|
||||||
|
|
||||||
|
while 1:
|
||||||
|
# Get the list sockets which are ready to be read through select
|
||||||
|
read_sockets,write_sockets,error_sockets = select.select(CONNECTION_LIST,[],[])
|
||||||
|
|
||||||
|
for sock in read_sockets:
|
||||||
|
#New connection
|
||||||
|
if sock == server_socket:
|
||||||
|
# Handle the case in which there is a new connection recieved through server_socket
|
||||||
|
sockfd, addr = server_socket.accept()
|
||||||
|
CONNECTION_LIST.append(sockfd)
|
||||||
|
username = sockfd.recv(1024)
|
||||||
|
print "Client (%s, %s) connected" % addr
|
||||||
|
# add a key - value pair to be able to map a connection to a username
|
||||||
|
USERNAMES[sockfd.getpeername()] = username
|
||||||
|
broadcast(server_socket, sockfd, "%s entered the room\n" % username)
|
||||||
|
|
||||||
|
|
||||||
|
#Some incoming message from a client
|
||||||
|
else:
|
||||||
|
# Data recieved from client, process it
|
||||||
|
try:
|
||||||
|
#In Windows, sometimes when a TCP program closes abruptly,
|
||||||
|
# a "Connection reset by peer" exception will be thrown
|
||||||
|
data = sock.recv(RECV_BUFFER)
|
||||||
|
if data:
|
||||||
|
broadcast(server_socket, sock, "\r" + '[' + str(USERNAMES[sock.getpeername()]) + '] ' + data) #use the data structure previously defined to send the correct usernames
|
||||||
|
else:
|
||||||
|
# remove the socket that's broken
|
||||||
|
if sock in SOCKET_LIST:
|
||||||
|
SOCKET_LIST.remove(sock)
|
||||||
|
|
||||||
|
except:
|
||||||
|
broadcast(server_socket, sock, "Client (%s, %s) is offline\n" % addr)
|
||||||
|
print "Client (%s, %s) is offline" % addr
|
||||||
|
sock.close()
|
||||||
|
CONNECTION_LIST.remove(sock)
|
||||||
|
continue
|
||||||
|
|
||||||
|
server_socket.close()
|
@ -0,0 +1,24 @@
|
|||||||
|
#this script is from the server side, to listen.
|
||||||
|
|
||||||
|
import socket
|
||||||
|
|
||||||
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
|
||||||
|
s.bind(('localhost', 3333))
|
||||||
|
|
||||||
|
s.listen(5)
|
||||||
|
flag = 0
|
||||||
|
while True:
|
||||||
|
connect, addr = s.accept()
|
||||||
|
print("Connection Address:" + str(addr))
|
||||||
|
|
||||||
|
str_return = "I am listening. Waiting for command."
|
||||||
|
connect.sendto(bytes(str_return, 'utf-8'), addr)
|
||||||
|
|
||||||
|
str_recv, temp = connect.recvfrom(1024)
|
||||||
|
print(str_recv)
|
||||||
|
|
||||||
|
str_return = "I got your command, it is " + str(str_recv)
|
||||||
|
connect.sendto(bytes(str_return, 'utf-8'), addr)
|
||||||
|
|
||||||
|
connect.close()
|
@ -0,0 +1,20 @@
|
|||||||
|
#this script is for the client side
|
||||||
|
|
||||||
|
import socket
|
||||||
|
|
||||||
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
|
||||||
|
s.connect(("localhost", 3333))
|
||||||
|
|
||||||
|
str_recv = s.recv(1024)
|
||||||
|
|
||||||
|
print(str(str_recv))
|
||||||
|
|
||||||
|
str_send = "I am here!"
|
||||||
|
|
||||||
|
s.send(bytes(str_send, 'utf-8'))
|
||||||
|
|
||||||
|
str_recv = s.recv(1024)
|
||||||
|
|
||||||
|
print(str(str_recv))
|
||||||
|
s.close()
|
Binary file not shown.
After Width: | Height: | Size: 1.1 MiB |
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
Binary file not shown.
After Width: | Height: | Size: 132 KiB |
@ -0,0 +1,94 @@
|
|||||||
|
{
|
||||||
|
"pre": [
|
||||||
|
"dont don't",
|
||||||
|
"cant can't",
|
||||||
|
"wont won't",
|
||||||
|
"recollect remember",
|
||||||
|
"dreamt dreamed",
|
||||||
|
"dreams dream",
|
||||||
|
"maybe perhaps",
|
||||||
|
"how what",
|
||||||
|
"when what",
|
||||||
|
"certainly yes",
|
||||||
|
"machine computer",
|
||||||
|
"computers computer",
|
||||||
|
"were was",
|
||||||
|
"you're you are",
|
||||||
|
"i'm i am",
|
||||||
|
"same alike"
|
||||||
|
],
|
||||||
|
"post": [
|
||||||
|
"am are",
|
||||||
|
"your my",
|
||||||
|
"me you",
|
||||||
|
"myself yourself",
|
||||||
|
"yourself myself",
|
||||||
|
"i you",
|
||||||
|
"you I",
|
||||||
|
"my your",
|
||||||
|
"i'm you are"
|
||||||
|
],
|
||||||
|
"synon": [
|
||||||
|
"belief feel think believe wish",
|
||||||
|
"sad unhappy depressed sick",
|
||||||
|
"sorry apologise"
|
||||||
|
],
|
||||||
|
"quit": [],
|
||||||
|
"keywords": [
|
||||||
|
{
|
||||||
|
"token": "xnone",
|
||||||
|
"weight": 0,
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"decomp": "*",
|
||||||
|
"reasmb": [
|
||||||
|
"You won't believe (1) *scandal*",
|
||||||
|
"(1) IT\u2019S OFFICIAL.",
|
||||||
|
"(1) WEIRD!!!!"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"token": "?",
|
||||||
|
"weight": 0,
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"decomp": "* ?",
|
||||||
|
"reasmb": [
|
||||||
|
"(1) ????????? SHOCKED!",
|
||||||
|
"(1) ????????? (DRASTIC)",
|
||||||
|
"(1) ????????? (no clickbait)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"token": "sorry",
|
||||||
|
"weight": 0,
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"decomp": "*",
|
||||||
|
"reasmb": [
|
||||||
|
"You won't believe who is sorry! *EMOTIONAL*",
|
||||||
|
"He apologised! *EMOTIONAL*"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"token": "dreamed",
|
||||||
|
"weight": 0,
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"decomp": "*",
|
||||||
|
"reasmb": [
|
||||||
|
"MY CRAZY DREAMS!!!! You won\u2019t believe this."
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"initial": "Tell me your post title.",
|
||||||
|
"final": "Goodluck. Go get coins."
|
||||||
|
}
|
@ -0,0 +1,202 @@
|
|||||||
|
/*
|
||||||
|
Michael Murtaugh
|
||||||
|
Following Charles Hayden's 1990's interpretation implemented in Java
|
||||||
|
(C) 2018 and released under the Free Art License 1.3
|
||||||
|
See LICENSE.txt and http://artlibre.org/licence/lal/en/
|
||||||
|
|
||||||
|
Use the accompanying eliza_script_to_json.py to prepare the rules in JSON format
|
||||||
|
|
||||||
|
*/
|
||||||
|
function chatbot (rules, debug) {
|
||||||
|
var saved_statements = [];
|
||||||
|
|
||||||
|
function process_rules (rules) {
|
||||||
|
// transfrom / pre-process the rules
|
||||||
|
function looping_iterator (l) {
|
||||||
|
var next = function () {
|
||||||
|
var ret = l[next.i];
|
||||||
|
if (++next.i >= l.length) { next.i = 0 };
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
next.length = l.length;
|
||||||
|
next.i = 0;
|
||||||
|
next.items = l;
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
// index pre + post and tokenize results
|
||||||
|
function _index (name) {
|
||||||
|
var new_value = {};
|
||||||
|
rules[name].forEach(function (x) {
|
||||||
|
var words = tokenize(x),
|
||||||
|
word = words.shift();
|
||||||
|
new_value[word] = words;
|
||||||
|
})
|
||||||
|
rules[name] = new_value;
|
||||||
|
}
|
||||||
|
_index("pre");
|
||||||
|
_index("post");
|
||||||
|
// index synonmys by first word
|
||||||
|
var new_synon = {};
|
||||||
|
rules.synon.forEach(function (x) {
|
||||||
|
var words = tokenize(x);
|
||||||
|
new_synon[words[0]] = words;
|
||||||
|
})
|
||||||
|
rules.synon = new_synon;
|
||||||
|
// index keywords by name
|
||||||
|
rules.keywords_by_token = {};
|
||||||
|
rules.keywords.forEach(function (x) {
|
||||||
|
rules.keywords_by_token[x.token] = x;
|
||||||
|
x.rules.forEach(function (r) {
|
||||||
|
// ensure list
|
||||||
|
if (!Array.isArray(r.reasmb)) { r.reasmb = [r.reasmb]; }
|
||||||
|
// wrap the reasmb list in a looping iterator that perserves its state
|
||||||
|
r.reasmb = looping_iterator(r.reasmb);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// function trim (text) { return text.replace(/\s+$/, "").replace(/\s+/, ""); }
|
||||||
|
function trimword (text) {
|
||||||
|
return text
|
||||||
|
.replace(/[^a-zA-Zéèàöùç]+$/, "")
|
||||||
|
.replace(/^[^a-zA-Zéèàöùç]+/, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
function tokenize (text) {
|
||||||
|
return (trimword(text).split(/\s+/).map(trimword));
|
||||||
|
}
|
||||||
|
|
||||||
|
// used for both pre + post subs
|
||||||
|
function sub (tokens, subst) {
|
||||||
|
for (var i=0, l=tokens.length; i<l; i++) {
|
||||||
|
var sub = subst[tokens[i].toLowerCase()];
|
||||||
|
if (sub) {
|
||||||
|
if (Array.isArray(sub)) {
|
||||||
|
Array.prototype.splice.apply(tokens, [i, 1].concat(sub));
|
||||||
|
i += (sub.length - 1);
|
||||||
|
} else {
|
||||||
|
tokens[i] = sub;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
function select_keywords (tokens) {
|
||||||
|
var ret = [];
|
||||||
|
for (var i=0, l=tokens.length; i<l; i++) {
|
||||||
|
var w = tokens[i].toLowerCase(),
|
||||||
|
rule = rules.keywords_by_token[w];
|
||||||
|
if (rule) { ret.push(rule); }
|
||||||
|
}
|
||||||
|
if (rules.keywords_by_token.xnone && rules.keywords_by_token.xnone.weight != 0) {
|
||||||
|
// append xnone rule pre-sort
|
||||||
|
ret.push(rules.keywords_by_token.xnone);
|
||||||
|
}
|
||||||
|
ret.sort(function (a, b) { return b.weight - a.weight });
|
||||||
|
if (rules.keywords_by_token.xnone && rules.keywords_by_token.xnone.weight == 0) {
|
||||||
|
// append xnone rule post-sort (ensuring it's last)
|
||||||
|
ret.push(rules.keywords_by_token.xnone);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
function compile_pattern (pattern) {
|
||||||
|
// compile a decomposition pattern
|
||||||
|
// * i @cannot * ==> i(cannot|cant|...)(.+)
|
||||||
|
// * i* @belief *you * ==> (belief|feel|think|believe|wish)
|
||||||
|
// * i @belief i *
|
||||||
|
var ret = pattern
|
||||||
|
.replace(/ *\* */g, "*") // compact spaces around stars
|
||||||
|
.replace(/\*/g, "(.*?)")
|
||||||
|
.replace(/@(\w+)/, function (match, word) {
|
||||||
|
var syn = rules.synon[word.toLowerCase()];
|
||||||
|
if (syn) {
|
||||||
|
return "("+syn.join("|")+")";
|
||||||
|
} else {
|
||||||
|
console.log("Missing @synonym", word);
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return "^"+ret+"$";
|
||||||
|
}
|
||||||
|
|
||||||
|
function match_decomp (pattern, tokens) {
|
||||||
|
var ppat = compile_pattern(pattern);
|
||||||
|
if (debug) {
|
||||||
|
console.log("compile_pattern.in", pattern);
|
||||||
|
console.log("compile_pattern.out", ppat);
|
||||||
|
}
|
||||||
|
var ppat = new RegExp(ppat, "i");
|
||||||
|
return ppat.exec(tokens.join(" "));
|
||||||
|
}
|
||||||
|
|
||||||
|
function do_post (txt) {
|
||||||
|
var tokens = tokenize(txt);
|
||||||
|
tokens = sub(tokens, rules.post);
|
||||||
|
return tokens.join(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
function do_reasmb (reasmb, match, tokens) {
|
||||||
|
if (Array.isArray(match)) {
|
||||||
|
return reasmb.replace(/\((\d+)\)/, function (m, n) {
|
||||||
|
return do_post(match[parseInt(n)]); // apply POST substitutions here to matching input
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return reasmb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function apply_keywords (keywords, tokens) {
|
||||||
|
for (var i=0, l=keywords.length; i<l; i++) {
|
||||||
|
var keyword = keywords[i];
|
||||||
|
if ((keyword.token == "xnone") && (saved_statements.length > 0)) {
|
||||||
|
if (debug) { console.log("using saved statement"); }
|
||||||
|
return saved_statements.shift();
|
||||||
|
}
|
||||||
|
var loop = true;
|
||||||
|
while (loop) {
|
||||||
|
loop = false;
|
||||||
|
if (debug) { console.log("trying keyword", keyword.token); }
|
||||||
|
for (var ri=0, rl = keyword.rules.length; ri<rl; ri++) {
|
||||||
|
var rule = keyword.rules[ri];
|
||||||
|
if (debug) { console.log("trying rule", rule.decomp, "("+(ri+1)+"/"+rl+")"); }
|
||||||
|
var match = match_decomp(rule.decomp, tokens);
|
||||||
|
if (match) {
|
||||||
|
var ra = rule.reasmb();
|
||||||
|
if (rule['save']) {
|
||||||
|
var save = do_reasmb(ra, match, tokens);
|
||||||
|
if (debug) { console.log("save", save); }
|
||||||
|
saved_statements.push(save);
|
||||||
|
} else if (ra.indexOf("goto ") == 0) {
|
||||||
|
var goto_name = ra.substr(5);
|
||||||
|
if (debug) { console.log("goto", goto_name); }
|
||||||
|
keyword = rules.keywords_by_token[goto_name];
|
||||||
|
loop = true;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (debug) { console.log("match", match, ra); }
|
||||||
|
return do_reasmb(ra, match, tokens);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function process (text) {
|
||||||
|
if (debug) { console.log("input", text); }
|
||||||
|
var tokens = tokenize(text);
|
||||||
|
if (debug) { console.log("tokens", tokens); }
|
||||||
|
tokens = sub(tokens, rules.pre);
|
||||||
|
if (debug) { console.log("pre", tokens); }
|
||||||
|
var keywords = select_keywords(tokens);
|
||||||
|
if (debug) { console.log("keywords", keywords.map(function (x) { return x.token })); }
|
||||||
|
var output = apply_keywords(keywords, tokens);
|
||||||
|
if (debug) { console.log("output", output); }
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
process_rules(rules);
|
||||||
|
return process;
|
||||||
|
}
|
@ -0,0 +1,90 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>CLICKBAIT GENERATOR</title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<style type="text/css">
|
||||||
|
* {
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-size: calc(1vw + 3vh);
|
||||||
|
}
|
||||||
|
#wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: absolute;
|
||||||
|
left: 5%; top: 5%; right: 5%; bottom: 5%;
|
||||||
|
}
|
||||||
|
#textinput {
|
||||||
|
width: 100%;
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
#input {
|
||||||
|
padding: 2%;
|
||||||
|
flex: 0 1 auto;
|
||||||
|
background: red;
|
||||||
|
}
|
||||||
|
#display {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
background: lightgrey;
|
||||||
|
padding: 2%;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
#display div.msg {
|
||||||
|
padding-bottom: 0.5em;
|
||||||
|
color: grey;
|
||||||
|
}
|
||||||
|
#display div.human {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
#display div.bot {
|
||||||
|
color: black;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
#display div.debug {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="wrapper">
|
||||||
|
<div id="display">
|
||||||
|
</div>
|
||||||
|
<div id="input">
|
||||||
|
<input type="text" id="textinput" autofocus />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="eliza.js"></script>
|
||||||
|
<script>
|
||||||
|
function eliza (rules) {
|
||||||
|
var input = document.getElementById("textinput"),
|
||||||
|
output = document.getElementById("display"),
|
||||||
|
bot = chatbot(rules, true);
|
||||||
|
|
||||||
|
function log (msg, kls) {
|
||||||
|
var d = document.createElement("div");
|
||||||
|
d.setAttribute("class", "msg " + kls);
|
||||||
|
d.innerHTML = msg;
|
||||||
|
display.appendChild(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
function say (msg) {
|
||||||
|
log(msg, "bot");
|
||||||
|
display.scrollTop = display.scrollTopMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.addEventListener("keypress", function (event) {
|
||||||
|
if (event.keyCode == 13) {
|
||||||
|
var text = input.value;
|
||||||
|
log(text, "user");
|
||||||
|
say(bot(text), "bot");
|
||||||
|
input.value = "";
|
||||||
|
input.focus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
say(rules.initial);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script src="doctor.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,60 @@
|
|||||||
|
"""
|
||||||
|
Michael Murtaugh
|
||||||
|
Following Charles Hayden's 1990's interpretation implemented in Java
|
||||||
|
(C) 2018 and released under the Free Art License 1.3
|
||||||
|
See LICENSE.txt and http://artlibre.org/licence/lal/en/
|
||||||
|
|
||||||
|
For use with eliza.js
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
python3 eliza_script_to_json.py < doctor.txt > doctor.json
|
||||||
|
|
||||||
|
"""
|
||||||
|
import sys, json
|
||||||
|
|
||||||
|
output = {}
|
||||||
|
output['pre'] = pre = []
|
||||||
|
output['post'] = post = []
|
||||||
|
output['synon'] = synon = []
|
||||||
|
output['quit'] = quit = []
|
||||||
|
output['keywords'] = keys = []
|
||||||
|
for line in sys.stdin:
|
||||||
|
line = line.strip()
|
||||||
|
if line.startswith("#") or not line:
|
||||||
|
continue
|
||||||
|
cmd, rest = line.split(" ", 1)
|
||||||
|
cmd = cmd.strip()
|
||||||
|
rest = rest.strip()
|
||||||
|
if cmd == "initial:":
|
||||||
|
output['initial'] = rest
|
||||||
|
elif cmd == "final:":
|
||||||
|
output['final'] = rest
|
||||||
|
elif cmd == "pre:":
|
||||||
|
pre.append(rest)
|
||||||
|
elif cmd == "post:":
|
||||||
|
post.append(rest)
|
||||||
|
elif cmd == "synon:":
|
||||||
|
synon.append(rest)
|
||||||
|
elif cmd == "key:":
|
||||||
|
try:
|
||||||
|
token, weight = rest.split()
|
||||||
|
except ValueError:
|
||||||
|
token = rest.strip()
|
||||||
|
weight = 0
|
||||||
|
print ("key", token, int(weight), file=sys.stderr)
|
||||||
|
keys.append({"token": token.strip(), "weight": int(weight), "rules": []})
|
||||||
|
elif line.startswith("decomp:"):
|
||||||
|
_, pattern = line.split(" ", 1)
|
||||||
|
pattern = pattern.strip()
|
||||||
|
if pattern.startswith("$"):
|
||||||
|
decomp = {"decomp": pattern[1:].strip(), "reasmb": [], "save": True}
|
||||||
|
else:
|
||||||
|
decomp = {"decomp": pattern, "reasmb": []}
|
||||||
|
print ("decomp", decomp, file=sys.stderr)
|
||||||
|
keys[-1]['rules'].append(decomp)
|
||||||
|
elif line.startswith("reasmb:"):
|
||||||
|
_, pattern = line.split(" ", 1)
|
||||||
|
print ("reasmb", pattern, file=sys.stderr)
|
||||||
|
keys[-1]['rules'][-1]['reasmb'].append(pattern.strip())
|
||||||
|
|
||||||
|
print (json.dumps(output, indent=2))
|
@ -0,0 +1,64 @@
|
|||||||
|
How Eliza Works
|
||||||
|
|
||||||
|
All the behavior of Eliza is controlled by a script file.
|
||||||
|
The standard script is attached to the end of this explanation.
|
||||||
|
|
||||||
|
Eliza starts by reading the script file. Because of Java security, it
|
||||||
|
must be on the same server as the class files. Eliza then reads a line at
|
||||||
|
a time from the user, processes it, and formulates a reply.
|
||||||
|
|
||||||
|
Processing consists of the following steps.
|
||||||
|
First the sentence broken down into words, separated by spaces. All further
|
||||||
|
processing takes place on these words as a whole, not on the individual
|
||||||
|
characters in them.
|
||||||
|
Second, a set of pre-substitutions takes place.
|
||||||
|
Third, Eliza takes all the words in the sentence and makes a list of all
|
||||||
|
keywords it finds. It sorts this keyword list in descending weight. It
|
||||||
|
process these keywords until it produces an output.
|
||||||
|
Fourth, for the given keyword, a list of decomposition patterns is searched.
|
||||||
|
The first one that matches is selected. If no match is found, the next keyword
|
||||||
|
is selected instead.
|
||||||
|
Fifth, for the matching decomposition pattern, a reassembly pattern is
|
||||||
|
selected. There may be several reassembly patterns, but only one is used
|
||||||
|
for a given sentence. If a subsequent sentence selects the same decomposition
|
||||||
|
pattern, the next reassembly pattern in sequence is used, until they have all
|
||||||
|
been used, at which point Eliza starts over with the first reassembly pattern.
|
||||||
|
Sixth, a set of post-substitutions takes place.
|
||||||
|
Finally, the resulting sentence is displayed as output.
|
||||||
|
|
||||||
|
The script is used to construct the pre and post substitution lists, the
|
||||||
|
keyword lists, and the decomposition and reassembly patterns.
|
||||||
|
In addition, there is a synonym matching facility, which is explained below.
|
||||||
|
|
||||||
|
Every line of script is prefaced by a tag that tells what list it is
|
||||||
|
part of. Here is an explanation of the tags.
|
||||||
|
|
||||||
|
initial: Eliza says this when it starts.
|
||||||
|
final: Eliza says this when it quits.
|
||||||
|
quit: If the input is this, then Eliza quits. Any number permitted.
|
||||||
|
pre: Part of the pre-substitution list. If the first word appears in
|
||||||
|
the sentence, it is replaced by the rest of the words.
|
||||||
|
post: Part of the post-subsititution list. If the first word appears
|
||||||
|
in the sentence, it is replaced by the rest of the words.
|
||||||
|
key: A keyword. Keywords with greater weight are selected in
|
||||||
|
preference to ones with lesser weight.
|
||||||
|
If no weight is given, it is assumed to be 1.
|
||||||
|
decomp: A decomposition pattern. The character * stands for any
|
||||||
|
sequence of words.
|
||||||
|
reasmb: A reassembly pattern. A set of words matched by * in
|
||||||
|
the decomposition pattern can be used as part of the reassembly.
|
||||||
|
For instance, (2) inserts the words matched by the second *
|
||||||
|
in the decomposition pattern.
|
||||||
|
synon: A list of synonyms. In a decomposition rule, for instance, @be
|
||||||
|
matches any of the words "be am is are was" because of the line:
|
||||||
|
"synon: be am is are was". The match @be also counts as a *
|
||||||
|
in numbering the matches for use by reassembly rules.
|
||||||
|
|
||||||
|
Other Special Rules
|
||||||
|
If a $ appears first in a decomposition rule, then the output is formed as
|
||||||
|
normal, but is saved and Eliza goes on to the next keyword. If no keywords
|
||||||
|
match, and there are saved sentences, one of them is picked at random and
|
||||||
|
used as the output, then it is discarded.
|
||||||
|
If there are no saved sentences, and no keywords match, then it uses the
|
||||||
|
keyword "xnone".
|
||||||
|
|
@ -0,0 +1,13 @@
|
|||||||
|
from __future__ import print_function
|
||||||
|
import json, sys, argparse
|
||||||
|
|
||||||
|
ap = argparse.ArgumentParser("wrap JSON in either a variable declaration (hardcode) or a callback (JSONP).")
|
||||||
|
ap.add_argument("--variable", default="weft", help="define a variable")
|
||||||
|
ap.add_argument("--callback", help="use a named callback (JSONP) -- overrides --variable")
|
||||||
|
args = ap.parse_args()
|
||||||
|
|
||||||
|
d = json.load(sys.stdin)
|
||||||
|
if args.callback:
|
||||||
|
print ("{0}({1});".format(args.callback, json.dumps(d)))
|
||||||
|
else:
|
||||||
|
print ("{0} = {1};".format(args.variable, json.dumps(d)))
|
@ -0,0 +1,7 @@
|
|||||||
|
%.json: %.txt
|
||||||
|
python3 eliza_script_to_json.py < $< > $@
|
||||||
|
%.js: %.json
|
||||||
|
python3 jsonp.py --callback "eliza" < $< > $@
|
||||||
|
|
||||||
|
doctor.html: doctor.json
|
||||||
|
python3 json_to_print.py $< rules.template.html > $@
|
@ -0,0 +1,24 @@
|
|||||||
|
import collections
|
||||||
|
|
||||||
|
file = open("results.txt") # open and read file
|
||||||
|
|
||||||
|
trump_list = []
|
||||||
|
|
||||||
|
trump = set(line.strip() for line in open('trump.txt')) # words that are inside sad.txt
|
||||||
|
|
||||||
|
# in the future I should split words from punctuation, so Trump's count as Trump
|
||||||
|
# for word in a.lower().split():
|
||||||
|
|
||||||
|
with open("results.txt") as f:
|
||||||
|
for line in f:
|
||||||
|
for word in line.split():
|
||||||
|
if word in trump:
|
||||||
|
#print(word + " this is sad")
|
||||||
|
trump_list.append(line + "<br>")
|
||||||
|
break
|
||||||
|
|
||||||
|
text_file = open("trump_news.htm", "w+")
|
||||||
|
text_file.write("".join(trump_list))
|
||||||
|
# print("".join(happy_list))
|
||||||
|
# Close the file
|
||||||
|
file.close()
|
@ -0,0 +1,20 @@
|
|||||||
|
from urllib.request import urlopen
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
|
||||||
|
html = urlopen('https://www.washingtonpost.com/')
|
||||||
|
|
||||||
|
bs = BeautifulSoup(html, "html.parser")
|
||||||
|
|
||||||
|
titles = bs.find_all('h2')
|
||||||
|
titles_list = []
|
||||||
|
|
||||||
|
#getting the content of <a> tag inside h2
|
||||||
|
for h2 in titles:
|
||||||
|
titles_list.append(h2.a.text.strip())
|
||||||
|
|
||||||
|
# write() argument must be str, not list
|
||||||
|
titles_list_strings = "\n".join(titles_list)
|
||||||
|
|
||||||
|
text_file = open("results.txt", "w")
|
||||||
|
text_file.write(titles_list_strings)
|
||||||
|
text_file.close()
|
@ -0,0 +1 @@
|
|||||||
|
Trump
|
@ -0,0 +1,48 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Double tap</title>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="date" content="2019-09-25">
|
||||||
|
<meta name="author" content="Rita Graca">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link rel="icon" href="">
|
||||||
|
<link rel="stylesheet" type="text/css" href="reset.css">
|
||||||
|
<link rel="stylesheet" type="text/css" href="style.css">
|
||||||
|
<script src="https://hammerjs.github.io/dist/hammer.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="myElement"></div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var myElement = document.getElementById('myElement');
|
||||||
|
|
||||||
|
// We create a manager object, which is the same as Hammer(), but without the presetted recognizers.
|
||||||
|
var mc = new Hammer.Manager(myElement);
|
||||||
|
|
||||||
|
|
||||||
|
// Tap recognizer with minimal 2 taps
|
||||||
|
mc.add( new Hammer.Tap({ event: 'doubletap', taps: 2 }) );
|
||||||
|
// Single tap recognizer
|
||||||
|
mc.add( new Hammer.Tap({ event: 'singletap' }) );
|
||||||
|
|
||||||
|
|
||||||
|
// we want to recognize this simulatenous, so a quadrupletap will be detected even while a tap has been recognized.
|
||||||
|
mc.get('doubletap').recognizeWith('singletap');
|
||||||
|
// we only want to trigger a tap, when we don't have detected a doubletap
|
||||||
|
mc.get('singletap').requireFailure('doubletap');
|
||||||
|
|
||||||
|
|
||||||
|
mc.on("doubletap", function(ev) {
|
||||||
|
// myElement.textContent += ev.type +" ";
|
||||||
|
var backColor = myElement.style.backgroundImage;
|
||||||
|
myElement.style.backgroundImage = backColor === 'linear-gradient(pink, red)' ? "linear-gradient(red, pink)" : "linear-gradient(pink, red)";
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</html>
|
@ -0,0 +1,48 @@
|
|||||||
|
/* http://meyerweb.com/eric/tools/css/reset/
|
||||||
|
v2.0 | 20110126
|
||||||
|
License: none (public domain)
|
||||||
|
*/
|
||||||
|
|
||||||
|
html, body, div, span, applet, object, iframe,
|
||||||
|
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||||
|
a, abbr, acronym, address, big, cite, code,
|
||||||
|
del, dfn, em, img, ins, kbd, q, s, samp,
|
||||||
|
small, strike, strong, sub, sup, tt, var,
|
||||||
|
b, u, i, center,
|
||||||
|
dl, dt, dd, ol, ul, li,
|
||||||
|
fieldset, form, label, legend,
|
||||||
|
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||||
|
article, aside, canvas, details, embed,
|
||||||
|
figure, figcaption, footer, header, hgroup,
|
||||||
|
menu, nav, output, ruby, section, summary,
|
||||||
|
time, mark, audio, video {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
font-size: 100%;
|
||||||
|
font: inherit;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
/* HTML5 display-role reset for older browsers */
|
||||||
|
article, aside, details, figcaption, figure,
|
||||||
|
footer, header, hgroup, menu, nav, section {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
ol, ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
blockquote, q {
|
||||||
|
quotes: none;
|
||||||
|
}
|
||||||
|
blockquote:before, blockquote:after,
|
||||||
|
q:before, q:after {
|
||||||
|
content: '';
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
#myElement {
|
||||||
|
background-image: linear-gradient(pink, red);
|
||||||
|
height: 100vh;
|
||||||
|
text-align: center;
|
||||||
|
font: 30px/300px Arial, sans-serif;
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 182 KiB |
@ -0,0 +1,38 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Pan up</title>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link rel="icon" href="">
|
||||||
|
<link rel="stylesheet" type="text/css" href="reset.css">
|
||||||
|
<link rel="stylesheet" type="text/css" href="style.css">
|
||||||
|
<script src="https://hammerjs.github.io/dist/hammer.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="myElement"></div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var myElement = document.getElementById('myElement');
|
||||||
|
|
||||||
|
// create a simple instance
|
||||||
|
// by default, it only adds horizontal recognizers
|
||||||
|
var mc = new Hammer(myElement);
|
||||||
|
|
||||||
|
// let the pan gesture support all directions.
|
||||||
|
// this will block the vertical scrolling on a touch-device while on the element
|
||||||
|
mc.get('pan').set({ direction: Hammer.DIRECTION_ALL });
|
||||||
|
|
||||||
|
// listen to events...
|
||||||
|
mc.on("panup", function(ev) {
|
||||||
|
// myElement.textContent = ev.type +" gesture detected.";
|
||||||
|
myElement.style.animation = "gradient 5s ease infinite";
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
Binary file not shown.
After Width: | Height: | Size: 159 KiB |
@ -0,0 +1,48 @@
|
|||||||
|
/* http://meyerweb.com/eric/tools/css/reset/
|
||||||
|
v2.0 | 20110126
|
||||||
|
License: none (public domain)
|
||||||
|
*/
|
||||||
|
|
||||||
|
html, body, div, span, applet, object, iframe,
|
||||||
|
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||||
|
a, abbr, acronym, address, big, cite, code,
|
||||||
|
del, dfn, em, img, ins, kbd, q, s, samp,
|
||||||
|
small, strike, strong, sub, sup, tt, var,
|
||||||
|
b, u, i, center,
|
||||||
|
dl, dt, dd, ol, ul, li,
|
||||||
|
fieldset, form, label, legend,
|
||||||
|
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||||
|
article, aside, canvas, details, embed,
|
||||||
|
figure, figcaption, footer, header, hgroup,
|
||||||
|
menu, nav, output, ruby, section, summary,
|
||||||
|
time, mark, audio, video {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
font-size: 100%;
|
||||||
|
font: inherit;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
/* HTML5 display-role reset for older browsers */
|
||||||
|
article, aside, details, figcaption, figure,
|
||||||
|
footer, header, hgroup, menu, nav, section {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
ol, ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
blockquote, q {
|
||||||
|
quotes: none;
|
||||||
|
}
|
||||||
|
blockquote:before, blockquote:after,
|
||||||
|
q:before, q:after {
|
||||||
|
content: '';
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
#myElement {
|
||||||
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
background: linear-gradient(-45deg, green, orange, blue);
|
||||||
|
background-size: 400% 400%;
|
||||||
|
animation: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes gradient {
|
||||||
|
0% {
|
||||||
|
background-position: 0% 50%;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
background-position: 100% 50%;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
background-position: 0% 50%;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue