Just some new banterbot trick and changes and things

This commit is contained in:
Russell 2016-02-04 09:41:43 -05:00
parent 10d2aef8d0
commit 5bd1f60a0b
24 changed files with 784 additions and 40 deletions

View File

@ -19,6 +19,10 @@ from rhymesWith import getRhymes
from rhymesWith import rhymeZone from rhymesWith import rhymeZone
from defineWord import defWord from defineWord import defWord
from rainbow import makeRainbow from rainbow import makeRainbow
import welch
import evil
import tumblr
import xkcdApropos
parser = OptionParser() parser = OptionParser()
@ -129,14 +133,35 @@ def define_word(channel, user, text):
ircsock.send("PRIVMSG " + channel + " :" + user + ": Couldn't find the definition of '" + word + "' :(\n") ircsock.send("PRIVMSG " + channel + " :" + user + ": Couldn't find the definition of '" + word + "' :(\n")
else: else:
for entry in defs: for entry in defs:
ircsock.send("PRIVMSG " + channel + " :" + user + ": Define '" + word + "'" + entry[0:200] + "\n") ircsock.send("PRIVMSG " + channel + " :" + user + ": Define '" + word + "'" + entry[0:400] + "\n")
def make_rainbow(channel, user, text): def make_rainbow(channel, user, text):
rbword = makeRainbow(text[9:]) rbword = makeRainbow(text[9:])
ircsock.send("PRIVMSG " + channel + " :" + rbword + "\n") ircsock.send("PRIVMSG " + channel + " :" + rbword + "\n")
def get_welch(channel):
ircsock.send("PRIVMSG " + channel + " :" + welch.get_thing()[0:400] + "\n")
def get_evil(channel):
evilThing = evil.get_thing();
for line in [evilThing[i:i+400] for i in range(0, len(evilThing), 400)]:
ircsock.send("PRIVMSG " + channel + " :" + line + "\n")
def get_tumble(url, channel):
tumble = tumblr.tumble(url)
for line in [tumble[i:i+400] for i in range(0, len(tumble), 400)]:
ircsock.send("PRIVMSG " + channel + " :" + line + "\n")
def get_xkcd(channel, text):
links = xkcdApropos.xkcd_links(text[6:])
joined_links = ', '.join(links)
for line in [joined_links[i:i+400] for i in range(0, len(joined_links), 400)]:
ircsock.send("PRIVMSG " + channel + " :" + line + "\n")
#res = xkcdApropos.xkcd(text[6:])
#ircsock.send("PRIVMSG " + channel + " :" + res + "\n")
def rollcall(channel): def rollcall(channel):
ircsock.send("PRIVMSG "+ channel +" :U wot m8? I score all the top drawer #banter and #bantz on this channel! Find new top-shelf banter with !newbanter, !rhymes, and !define. Make your chatter #legend with !rainbow\n") ircsock.send("PRIVMSG "+ channel +" :U wot m8? I score all the top drawer #banter and #bantz on this channel! Find new top-shelf banter with !newbanter, !rhymes, and !define. Make your chatter #legend with !rainbow and get jokes with !welch and !evil\n")
def connect(server, channel, botnick): def connect(server, channel, botnick):
ircsock.connect((server, 6667)) ircsock.connect((server, 6667))
@ -192,6 +217,21 @@ def listen():
if ircmsg.find(":!rainbow") != -1: if ircmsg.find(":!rainbow") != -1:
make_rainbow(channel, user, messageText) make_rainbow(channel, user, messageText)
if ircmsg.find("!welch") != -1:
get_welch(channel)
if ircmsg.find("!evil") != -1:
get_evil(channel)
if ircmsg.find("!kjp") != -1:
get_tumble('http://kingjamesprogramming.tumblr.com', channel)
if ircmsg.find("!help") != -1:
get_tumble('http://thedoomthatcametopuppet.tumblr.com', channel)
if ircmsg.find("!xkcd") != -1:
get_xkcd(channel, messageText)
if ircmsg.find(":!rollcall") != -1: if ircmsg.find(":!rollcall") != -1:
rollcall(channel) rollcall(channel)

179
Code/irc/duckduckgo.py Executable file
View File

@ -0,0 +1,179 @@
import urllib
import urllib2
import json as j
import sys
__version__ = 0.242
def query(query, useragent='python-duckduckgo '+str(__version__), safesearch=True, html=False, meanings=True, **kwargs):
"""
Query DuckDuckGo, returning a Results object.
Here's a query that's unlikely to change:
>>> result = query('1 + 1')
>>> result.type
'nothing'
>>> result.answer.text
'1 + 1 = 2'
>>> result.answer.type
'calc'
Keword arguments:
useragent: UserAgent to use while querying. Default: "python-duckduckgo %d" (str)
safesearch: True for on, False for off. Default: True (bool)
html: True to allow HTML in output. Default: False (bool)
meanings: True to include disambiguations in results (bool)
Any other keyword arguments are passed directly to DuckDuckGo as URL params.
""" % __version__
safesearch = '1' if safesearch else '-1'
html = '0' if html else '1'
meanings = '0' if meanings else '1'
params = {
'q': query,
'o': 'json',
'kp': safesearch,
'no_redirect': '1',
'no_html': html,
'd': meanings,
}
params.update(kwargs)
encparams = urllib.urlencode(params)
url = 'http://api.duckduckgo.com/?' + encparams
request = urllib2.Request(url, headers={'User-Agent': useragent})
response = urllib2.urlopen(request)
json = j.loads(response.read())
response.close()
return Results(json)
class Results(object):
def __init__(self, json):
self.type = {'A': 'answer', 'D': 'disambiguation',
'C': 'category', 'N': 'name',
'E': 'exclusive', '': 'nothing'}.get(json.get('Type',''), '')
self.json = json
self.api_version = None # compat
self.heading = json.get('Heading', '')
self.results = [Result(elem) for elem in json.get('Results',[])]
self.related = [Result(elem) for elem in
json.get('RelatedTopics',[])]
self.abstract = Abstract(json)
self.redirect = Redirect(json)
self.definition = Definition(json)
self.answer = Answer(json)
self.image = Image({'Result':json.get('Image','')})
class Abstract(object):
def __init__(self, json):
self.html = json.get('Abstract', '')
self.text = json.get('AbstractText', '')
self.url = json.get('AbstractURL', '')
self.source = json.get('AbstractSource')
class Redirect(object):
def __init__(self, json):
self.url = json.get('Redirect', '')
class Result(object):
def __init__(self, json):
self.topics = json.get('Topics', [])
if self.topics:
self.topics = [Result(t) for t in self.topics]
return
self.html = json.get('Result')
self.text = json.get('Text')
self.url = json.get('FirstURL')
icon_json = json.get('Icon')
if icon_json is not None:
self.icon = Image(icon_json)
else:
self.icon = None
class Image(object):
def __init__(self, json):
self.url = json.get('Result')
self.height = json.get('Height', None)
self.width = json.get('Width', None)
class Answer(object):
def __init__(self, json):
self.text = json.get('Answer')
self.type = json.get('AnswerType', '')
class Definition(object):
def __init__(self, json):
self.text = json.get('Definition','')
self.url = json.get('DefinitionURL')
self.source = json.get('DefinitionSource')
def get_zci(q, web_fallback=True, priority=['answer', 'abstract', 'related.0', 'definition'], urls=True, **kwargs):
'''A helper method to get a single (and hopefully the best) ZCI result.
priority=list can be used to set the order in which fields will be checked for answers.
Use web_fallback=True to fall back to grabbing the first web result.
passed to query. This method will fall back to 'Sorry, no results.'
if it cannot find anything.'''
ddg = query('\\'+q, **kwargs)
response = ''
for p in priority:
ps = p.split('.')
type = ps[0]
index = int(ps[1]) if len(ps) > 1 else None
result = getattr(ddg, type)
if index is not None:
if not hasattr(result, '__getitem__'): raise TypeError('%s field is not indexable' % type)
result = result[index] if len(result) > index else None
if not result: continue
if result.text: response = result.text
if result.text and hasattr(result,'url') and urls:
if result.url: response += ' (%s)' % result.url
if response: break
# if there still isn't anything, try to get the first web result
if not response and web_fallback:
if ddg.redirect.url:
response = ddg.redirect.url
# final fallback
if not response:
response = 'Sorry, no results.'
return response
def main():
if len(sys.argv) > 1:
q = query(' '.join(sys.argv[1:]))
keys = q.json.keys()
keys.sort()
for key in keys:
sys.stdout.write(key)
if type(q.json[key]) in [str,unicode]: print(':', q.json[key])
else:
sys.stdout.write('\n')
for i in q.json[key]: print('\t',i)
else:
print('Usage: %s [query]' % sys.argv[0])

6
Code/irc/evil.py Normal file
View File

@ -0,0 +1,6 @@
import random
def get_thing():
file = "/home/krowbar/logs/evildata.txt"
thing = ""
return "If I Ever Become an Evil Overlord: " + random.choice(list(open(file))).rstrip()

View File

@ -37,8 +37,8 @@ def make_puzzle():
elif roll == 5: elif roll == 5:
p1 = primes[random.randrange(0,len(primes))] p1 = primes[random.randrange(0,len(primes))]
p2 = primes[random.randrange(0,len(primes))] p2 = primes[random.randrange(0,len(primes))]
answer = str(p1) + ',' + str(p2) answer = str(min(p1,p2)) + ',' + str(max(p1,p2))
puzzle += p.number_to_words(p1 * p2) + " when factored into its two primes (answer in the form of the two primes with a comman between)" puzzle += p.number_to_words(p1 * p2) + " when factored into its two primes (answer in the form of the two primes with a comma between)"
puzzle += "? (Answer with numbers)" puzzle += "? (Answer with numbers)"

View File

@ -1,14 +1,14 @@
krowbar&^%336&^%1452540446 krowbar&^%399&^%1454593921
karlen&^%272&^%1449500011 karlen&^%272&^%1449500011
endorphant&^%682&^%1444775660 endorphant&^%682&^%1444775660
jumblesale&^%24&^%1426171214 jumblesale&^%24&^%1426171214
marcus&^%834&^%1452521269 marcus&^%877&^%1454436882
papa&^%179&^%1438878499 papa&^%179&^%1438878499
epicmorphism&^%5&^%1421937744 epicmorphism&^%5&^%1421937744
audy&^%78&^%1442345315 audy&^%78&^%1442345315
kc&^%18&^%1422326056 kc&^%18&^%1422326056
vilmibm&^%9&^%1445468087 vilmibm&^%9&^%1445468087
cmr&^%1074&^%1451719260 cmr&^%1131&^%1454335852
imt&^%519&^%1424087616 imt&^%519&^%1424087616
cndorphant&^%788&^%1424094192 cndorphant&^%788&^%1424094192
rain&^%17&^%1422310975 rain&^%17&^%1422310975
@ -28,11 +28,13 @@ reppard&^%11&^%1437512059
jesse&^%6&^%1437569027 jesse&^%6&^%1437569027
khoi&^%3&^%1438044039 khoi&^%3&^%1438044039
sanqui&^%4&^%1438184911 sanqui&^%4&^%1438184911
endorphan&^%57&^%1450367628 endorphan&^%64&^%1452614950
cndorphbo&^%2&^%1447862524 cndorphbo&^%2&^%1447862524
santi&^%3&^%1447873216 santi&^%3&^%1447873216
insom&^%1&^%1450346059 insom&^%1&^%1450346059
tahnok&^%3&^%1450457276 tahnok&^%3&^%1450457276
nilsding&^%8&^%1452449452 nilsding&^%12&^%1454100197
vypr&^%3&^%1452470872 vypr&^%3&^%1452470872
synergian&^%1&^%1452541847 synergian&^%21&^%1454583808
dheeraj&^%2&^%1454438936
demobot&^%6&^%1454439605

View File

@ -18,3 +18,5 @@
1444203916&^%cmr&^%http://tilde.town/~wiki/ircbots.html | cndorphbot: 1444203916&^%cmr&^%http://tilde.town/~wiki/ircbots.html | cndorphbot:
1447252215&^%krowbar&^%#bots, the last bastion of the free 1447252215&^%krowbar&^%#bots, the last bastion of the free
1451487092&^%krowbar&^%Bots rule! Users drool! 1451487092&^%krowbar&^%Bots rule! Users drool!
1453394948&^%krowbar&^%We'll leave it to the future to resolve the present
1453924207&^%krowbar&^%The best things happen when you're parsing

View File

@ -130,3 +130,4 @@
1449698715&^%vilmibm&^%hack the planet (with feels) 1449698715&^%vilmibm&^%hack the planet (with feels)
1451971379&^%vilmibm&^%let's talk about html & feels | welcome new users! 1451971379&^%vilmibm&^%let's talk about html & feels | welcome new users!
1452017977&^%vilmibm&^%let's talk about html & feels! | add yrself to the map of townies! http://tilde.town/~bear/where.html 1452017977&^%vilmibm&^%let's talk about html & feels! | add yrself to the map of townies! http://tilde.town/~bear/where.html
1453427743&^%vilmibm&^%WHAT MOVIE SHOULD WE WATCH IN ASCII ON MOVIE NIGHT? | add yrself to the map http://tilde.town/~bear/where.html

View File

@ -1,5 +1,5 @@
krowbar&^%7&^%17 krowbar&^%9&^%19
vilmibm&^%0&^%19 vilmibm&^%0&^%20
hardmath123&^%0&^%6 hardmath123&^%0&^%6
joe&^%1&^%1jumblesale joe&^%1&^%1jumblesale
audiodude&^%1&^%0 audiodude&^%1&^%0

23
Code/irc/tumblr.py Normal file
View File

@ -0,0 +1,23 @@
import urllib
from bs4 import BeautifulSoup
import random
import re
def tumble(url):
#Find the max pages
soup = BeautifulSoup(urllib.urlopen(url).read(), 'html.parser')
pages = soup.findAll('span', 'page-numbers')[0].text.split('/')[1] #this could totally fail several ways
page = random.randrange(1, int(pages)+1)
#Parse a page
soup = BeautifulSoup(urllib.urlopen(url + '/page/' + str(page)).read(), 'html.parser')
article = random.choice(soup.findAll('article'))
quote = article.find('blockquote').text.replace('\n','');
if len(article.find('footer').findAll('ul')) > 1:
quote += re.sub('\n+', ' ', article.find('footer').findAll('ul')[0].text); #the hash tags
quote += '(' + re.sub('\n+', ' ', article.find('footer').findAll('ul')[1].text) + ')'; #and the date and notes
else:
quote += '(' + re.sub('\n+', ' ', article.find('footer').findAll('ul')[0].text) + ')'; #just the date and notes
return quote.encode('ascii', 'ignore')

6
Code/irc/welch.py Normal file
View File

@ -0,0 +1,6 @@
import random
def get_thing():
file = "/home/krowbar/logs/welchdata.txt"
thing = ""
return "Thing Mr. Welch can no longer do in a RPG #" + random.choice(list(open(file))).rstrip()

24
Code/irc/xkcdApropos.py Normal file
View File

@ -0,0 +1,24 @@
import duckduckgo
import urllib
from bs4 import BeautifulSoup
def xkcd(query):
res = duckduckgo.get_zci('site:xkcd.com ' + query);
title = "";
try: #ddg returns a url for these searches. i want a title as well
title = BeautifulSoup(urllib.urlopen(res).read(), 'html.parser').title.text
except:
pass #just swallow the error. maybe the result wasn't a url or something else bad happened
return (((title + ' - ') if title else '') + res).encode('ascii', 'ignore')
def xkcd_links(query):
url = "https://duckduckgo.com/html/?q=site%3Axkcd.com+" + query.replace(' ', '+')
soup = BeautifulSoup(urllib.urlopen(url).read(), 'html.parser')
links = filter(lambda a: a[0:8] == 'xkcd.com', [a.text.strip() for a in soup.find_all("div", class_="url")])
def pretty_link(url):
data = BeautifulSoup(urllib.urlopen('http://'+url).read(), 'html.parser')
title = data.title.text if data.title else ''
return (title + ' - ' + url) if title else url
links = map(lambda url: pretty_link(url), links)
return links

105
Code/python/chatbesties.py Normal file
View File

@ -0,0 +1,105 @@
#!/usr/bin/python
import fileinput
import json
import time
import calendar
import shutil
import re
import math
import operator
MAX_NODES = 3
logfile = "/home/jumblesale/Code/irc/log"
outfile = "/home/krowbar/logs/chatBesties.json"
outCircle = "/home/krowbar/logs/chatcircle.json"
userData = {} #hash keyed by "user" that contains a hash of mentioned other users with count
nameFix = {
'jumblesal': 'jumblesale',
'hardmath1': 'kc',
'hardmath123': 'kc',
'bendorphan': 'endorphant',
'endorphan': 'endorphant',
'synergian': 'synergiance'
}
users = []
#Get a list of all user names by checking the logs for people who have said things
with open(logfile, "r") as log:
for line in log:
try:
time, user, message = line.split("\t", 3)
if nameFix.has_key(user):
user = nameFix[user]
else:
user = user.lower()
if user not in users:
users.append(user)
except ValueError:
continue #There are some bad lines in the log file that we'll ignore if we can't parse
d3data = {}
d3data['nodes'] = []
#re-read the log and this time look for instances of user names in messages
with open(logfile, "r") as log:
for line in log:
try:
time, user, message = line.split("\t", 3)
if nameFix.has_key(user):
user = nameFix[user]
else:
user = user.lower()
except ValueError:
continue #There are some bad lines in the log file that we'll ignore if we can't parse
for word in message.split(' '):
word = re.sub('[^A-Za-z0-9]+', '', word)
if word in users: #SOMEONE MENTIONED SOMEONE
if userData.has_key(user): #This user is already set up
if userData[user]['data'].has_key(word): #This user has mentioned this person before
userData[user]['data'][word] += 1
else: #This user never mentioned this person before
userData[user]['data'][word] = 1
else: #This user was never set up
userData[user] = {} #make it a dictionary!
userData[user]['data'] = {}
userData[user]['data'][word] = 1
userData[user]['id'] = len(d3data['nodes']) #so we know how to match people during the links phase
d3data['nodes'].append({"name": user, "group": 1})
if not userData.has_key(word): #check if the target has not been set up
userData[word] = {}
userData[word]['data'] = {}
userData[word]['id'] = len(d3data['nodes'])
d3data['nodes'].append({"name": word, "group": 1})
d3data['links'] = []
#Now connect all the pople to their stuff
for user, values in userData.iteritems():
besties = sorted(values['data'].items(), key=operator.itemgetter(1), reverse=True)[0:MAX_NODES] #ONLY the top 5 besties
for target, score in besties:
try:
print "Adding link for " + user + " (" + str(values['id']) + ") to " + target + " (" + str(userData[target]['id']) + ") for " + str(score)
d3data['links'].append({"source": values['id'], "target": userData[target]['id'], "value": math.ceil(math.sqrt(score))})
except KeyError:
print "Error when trying to link " + user + " to " + target
continue
if len(values['data']) > MAX_NODES:
print "...ignoring " + str(len(values['data']) - MAX_NODES) + " more connections"
d3Circle = {}
d3Circle['names'] = [''] * len(userData)
d3Circle['matrix'] = [[0] * len(userData)] * len(userData)
for user, values in userData.iteritems():
d3Circle['names'][values['id']] = user
for name, score in values['data'].iteritems():
d3Circle['matrix'][values['id']][userData[name]['id']] = score if score > 1 else 0
with open(outfile + ".tmp", "w") as tmpFile:
tmpFile.write(json.dumps(d3data))
shutil.move(outfile + ".tmp", outfile)
with open(outCircle + ".tmp", "w") as tmpFile:
tmpFile.write(json.dumps(d3Circle))
shutil.move(outCircle + ".tmp", outCircle)

View File

@ -22,7 +22,8 @@ charset="utf-8"></script>-->
data.push([user, d, d]); data.push([user, d, d]);
}) })
}); });
google.setOnLoadCallback(drawChart); //google.setOnLoadCallback(drawChart);
$(drawChart);
}); });
function drawChart() { function drawChart() {

View File

@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html content="text/html; charset=UTF-8;charset=utf-8">
<head> <head>
<title>IRC chat stats</title> <title>IRC chat stats</title>
</head> </head>
@ -12,6 +12,7 @@ charset="utf-8"></script>-->
google.load("visualization", "1.1", {packages:["table"]}); google.load("visualization", "1.1", {packages:["table"]});
data = []; data = [];
jQuery.getJSON("/~krowbar/data/chatStats.json", function(json) { jQuery.getJSON("/~krowbar/data/chatStats.json", function(json) {
now = new Date(); now = new Date();
nowSec = Math.round(now.getTime()/1000) nowSec = Math.round(now.getTime()/1000)
@ -27,12 +28,15 @@ charset="utf-8"></script>-->
Number((userData.responseTime / (userData.mentions ? userData.mentions : 1) / 60).toFixed(2)), Number((userData.responseTime / (userData.mentions ? userData.mentions : 1) / 60).toFixed(2)),
]); ]);
}); });
google.setOnLoadCallback(drawTable); console.log("* Loaded the data!");
//google.setOnLoadCallback(drawTable);
$(drawTable)
}); });
function drawTable() { function drawTable() {
var dataTable = new google.visualization.DataTable(); var dataTable = new google.visualization.DataTable();
var userFormatter = new google.visualization.PatternFormat('<a href="/~{0}">{0}</a>');
var minFormatter = new google.visualization.NumberFormat({pattern: '##.## minutes'}); var minFormatter = new google.visualization.NumberFormat({pattern: '##.## minutes'});
var dayFormatter = new google.visualization.NumberFormat({pattern: '## days'}); var dayFormatter = new google.visualization.NumberFormat({pattern: '## days'});
var wordFormatter = new google.visualization.NumberFormat({pattern: '##.## words'}); var wordFormatter = new google.visualization.NumberFormat({pattern: '##.## words'});
@ -40,23 +44,24 @@ charset="utf-8"></script>-->
var streakFormatter = new google.visualization.NumberFormat({pattern: '## lines'}); var streakFormatter = new google.visualization.NumberFormat({pattern: '## lines'});
var mentionsFormatter = new google.visualization.NumberFormat({pattern: '## mentions'}); var mentionsFormatter = new google.visualization.NumberFormat({pattern: '## mentions'});
dataTable.addColumn('string', 'User'); //col0 dataTable.addColumn('string', 'User'); //col0
dataTable.addColumn('datetime', 'First Spoke'); //col1 dataTable.addColumn('datetime', 'First Spoke'); //col1
dataTable.addColumn('datetime', 'Last Spoke'); //col2 dataTable.addColumn('datetime', 'Last Spoke'); //col2
dataTable.addColumn('number', 'Total Time'); //col3 dataTable.addColumn('number', 'Total'); //col3
dataTable.addColumn('number', 'Active on'); //col4 dataTable.addColumn('number', 'Active on'); //col4
dataTable.addColumn('number', 'Active Ratio');//col5 dataTable.addColumn('number', 'Ratio'); //col5
dataTable.addColumn('number', 'Lines'); //col6 dataTable.addColumn('number', 'Lines'); //col6
dataTable.addColumn('number', 'Words'); //col7 dataTable.addColumn('number', 'Words'); //col7
dataTable.addColumn('number', 'per Line'); //col8 dataTable.addColumn('number', 'per Line'); //col8
dataTable.addColumn('number', 'Characters'); //col9 dataTable.addColumn('number', 'Characters'); //col9
dataTable.addColumn('number', 'per Line'); //col10 dataTable.addColumn('number', 'per Line'); //col10
dataTable.addColumn('number', 'Chat Streak'); //col11 dataTable.addColumn('number', 'Chat Streak'); //col11
dataTable.addColumn('number', 'Popularity'); //col12 dataTable.addColumn('number', 'Popularity'); //col12
dataTable.addColumn('number', 'Bot Use'); //col13 dataTable.addColumn('number', 'Bot Use'); //col13
dataTable.addColumn('number', 'Avg response time'); //col14 dataTable.addColumn('number', 'Response time'); //col14
dataTable.addRows(data); dataTable.addRows(data);
userFormatter.format(dataTable, [0]);
dayFormatter.format(dataTable, 3); dayFormatter.format(dataTable, 3);
dayFormatter.format(dataTable, 4); dayFormatter.format(dataTable, 4);
wordFormatter.format(dataTable, 8); wordFormatter.format(dataTable, 8);
@ -64,10 +69,12 @@ charset="utf-8"></script>-->
streakFormatter.format(dataTable, 11); streakFormatter.format(dataTable, 11);
mentionsFormatter.format(dataTable, 12); mentionsFormatter.format(dataTable, 12);
minFormatter.format(dataTable, 14); minFormatter.format(dataTable, 14);
console.log("* Set up the columns!");
var table = new google.visualization.Table(document.getElementById('statTable')); var table = new google.visualization.Table(document.getElementById('statTable'));
table.draw(dataTable, {showRowNumber: false, width:'95%', height: '60%', sortColumn:2, sortAscending:false}); table.draw(dataTable, {showRowNumber: false, width:'95%', height: '60%', sortColumn:2, sortAscending:false, allowHtml: true});
console.log("* Drew the tables! (I hope.)");
} }
</script> </script>
<body> <body>

View File

@ -49,6 +49,9 @@
linedata.addColumn('date', 'Date'); linedata.addColumn('date', 'Date');
var userData = {}; var userData = {};
_.forEach(json, function(set, idx) { _.forEach(json, function(set, idx) {
//only display 1/8 the points. (every 2 days instead of every 6 hours) page is loading too slow
//maybe i could add something to show more points but we're not losing too much granularity for the speed we gain
if(idx % 8 != 0) return;
_.forEach(set.data, function(point) { _.forEach(set.data, function(point) {
if(point.du > 2000) { //the 'interesting' threshold is set at 20000kb if(point.du > 2000) { //the 'interesting' threshold is set at 20000kb
if(!userData[point.user]) { if(!userData[point.user]) {
@ -63,6 +66,7 @@
}) })
}) })
_.forEach(json, function(set,idx) { _.forEach(json, function(set,idx) {
if(idx % 8 != 0) return;
var d = new Date(0); var d = new Date(0);
d.setUTCSeconds(set.date); d.setUTCSeconds(set.date);
linedata.addRow([d].concat(_.map(userData, function(user) { return user[idx];}))); linedata.addRow([d].concat(_.map(userData, function(user) { return user[idx];})));

View File

@ -0,0 +1,46 @@
.jsondiffpatch-annotated-delta {
font-family: 'Bitstream Vera Sans Mono', 'DejaVu Sans Mono', Monaco, Courier, monospace;
font-size: 12px;
margin: 0;
padding: 0 0 0 12px;
display: inline-block;
}
.jsondiffpatch-annotated-delta pre {
font-family: 'Bitstream Vera Sans Mono', 'DejaVu Sans Mono', Monaco, Courier, monospace;
font-size: 12px;
margin: 0;
padding: 0;
display: inline-block;
}
.jsondiffpatch-annotated-delta td {
margin: 0;
padding: 0;
}
.jsondiffpatch-annotated-delta td pre:hover {
font-weight: bold;
}
td.jsondiffpatch-delta-note {
font-style: italic;
padding-left: 10px;
}
.jsondiffpatch-delta-note > div {
margin: 0;
padding: 0;
}
.jsondiffpatch-delta-note pre {
font-style: normal;
}
.jsondiffpatch-annotated-delta .jsondiffpatch-delta-note {
color: #777;
}
.jsondiffpatch-annotated-delta tr:hover {
background: #ffc;
}
.jsondiffpatch-annotated-delta tr:hover > td.jsondiffpatch-delta-note {
color: black;
}
.jsondiffpatch-error {
background: red;
color: white;
font-weight: bold;
}

View File

@ -0,0 +1,149 @@
.jsondiffpatch-delta {
font-family: 'Bitstream Vera Sans Mono', 'DejaVu Sans Mono', Monaco, Courier, monospace;
font-size: 12px;
margin: 0;
padding: 0 0 0 12px;
display: inline-block;
}
.jsondiffpatch-delta pre {
font-family: 'Bitstream Vera Sans Mono', 'DejaVu Sans Mono', Monaco, Courier, monospace;
font-size: 12px;
margin: 0;
padding: 0;
display: inline-block;
}
ul.jsondiffpatch-delta {
list-style-type: none;
padding: 0 0 0 20px;
margin: 0;
}
.jsondiffpatch-delta ul {
list-style-type: none;
padding: 0 0 0 20px;
margin: 0;
}
.jsondiffpatch-added .jsondiffpatch-property-name,
.jsondiffpatch-added .jsondiffpatch-value pre,
.jsondiffpatch-modified .jsondiffpatch-right-value pre,
.jsondiffpatch-textdiff-added {
background: #bbffbb;
}
.jsondiffpatch-deleted .jsondiffpatch-property-name,
.jsondiffpatch-deleted pre,
.jsondiffpatch-modified .jsondiffpatch-left-value pre,
.jsondiffpatch-textdiff-deleted {
background: #ffbbbb;
text-decoration: line-through;
}
.jsondiffpatch-unchanged,
.jsondiffpatch-movedestination {
color: gray;
}
.jsondiffpatch-unchanged,
.jsondiffpatch-movedestination > .jsondiffpatch-value {
transition: all 0.5s;
-webkit-transition: all 0.5s;
overflow-y: hidden;
}
.jsondiffpatch-unchanged-showing .jsondiffpatch-unchanged,
.jsondiffpatch-unchanged-showing .jsondiffpatch-movedestination > .jsondiffpatch-value {
max-height: 100px;
}
.jsondiffpatch-unchanged-hidden .jsondiffpatch-unchanged,
.jsondiffpatch-unchanged-hidden .jsondiffpatch-movedestination > .jsondiffpatch-value {
max-height: 0;
}
.jsondiffpatch-unchanged-hiding .jsondiffpatch-movedestination > .jsondiffpatch-value,
.jsondiffpatch-unchanged-hidden .jsondiffpatch-movedestination > .jsondiffpatch-value {
display: block;
}
.jsondiffpatch-unchanged-visible .jsondiffpatch-unchanged,
.jsondiffpatch-unchanged-visible .jsondiffpatch-movedestination > .jsondiffpatch-value {
max-height: 100px;
}
.jsondiffpatch-unchanged-hiding .jsondiffpatch-unchanged,
.jsondiffpatch-unchanged-hiding .jsondiffpatch-movedestination > .jsondiffpatch-value {
max-height: 0;
}
.jsondiffpatch-unchanged-showing .jsondiffpatch-arrow,
.jsondiffpatch-unchanged-hiding .jsondiffpatch-arrow {
display: none;
}
.jsondiffpatch-value {
display: inline-block;
}
.jsondiffpatch-property-name {
display: inline-block;
padding-right: 5px;
vertical-align: top;
}
.jsondiffpatch-property-name:after {
content: ': ';
}
.jsondiffpatch-child-node-type-array > .jsondiffpatch-property-name:after {
content: ': [';
}
.jsondiffpatch-child-node-type-array:after {
content: '],';
}
div.jsondiffpatch-child-node-type-array:before {
content: '[';
}
div.jsondiffpatch-child-node-type-array:after {
content: ']';
}
.jsondiffpatch-child-node-type-object > .jsondiffpatch-property-name:after {
content: ': {';
}
.jsondiffpatch-child-node-type-object:after {
content: '},';
}
div.jsondiffpatch-child-node-type-object:before {
content: '{';
}
div.jsondiffpatch-child-node-type-object:after {
content: '}';
}
.jsondiffpatch-value pre:after {
content: ',';
}
li:last-child > .jsondiffpatch-value pre:after,
.jsondiffpatch-modified > .jsondiffpatch-left-value pre:after {
content: '';
}
.jsondiffpatch-modified .jsondiffpatch-value {
display: inline-block;
}
.jsondiffpatch-modified .jsondiffpatch-right-value {
margin-left: 5px;
}
.jsondiffpatch-moved .jsondiffpatch-value {
display: none;
}
.jsondiffpatch-moved .jsondiffpatch-moved-destination {
display: inline-block;
background: #ffffbb;
color: #888;
}
.jsondiffpatch-moved .jsondiffpatch-moved-destination:before {
content: ' => ';
}
ul.jsondiffpatch-textdiff {
padding: 0;
}
.jsondiffpatch-textdiff-location {
color: #bbb;
display: inline-block;
min-width: 60px;
}
.jsondiffpatch-textdiff-line {
display: inline-block;
}
.jsondiffpatch-textdiff-line-number:after {
content: ',';
}
.jsondiffpatch-error {
background: red;
color: white;
font-weight: bold;
}

View File

@ -2,4 +2,4 @@
"data1": "foo", "data1": "foo",
"data2": "bar", "data2": "bar",
"data3": ["foo","bar","baz"] "data3": ["foo","bar","baz"]
}; }

View File

@ -0,0 +1,5 @@
{
"data1": "foo",
"data4": "banana",
"data3": ["foo","bat","baz","bang"]
}

View File

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html content="text/html; charset=UTF-8;charset=utf-8">
<head>
<title>JSON diff POC</title>
</head>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<!--<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"
charset="utf-8"></script>-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.min.js"></script>
<script type="text/javascript">
jQuery.getJSON("data.json", function(json) {
});
jQuery.getJSON("data2.json", function(json) {
});
</script>
<body>
<div>HERE'S SOME STUFF!</div>
<textarea id="text1" cols="40" rows="10"></textarea>
<textarea id="text2" cols="40" rows="10"></textarea>
<textarea id="diff" cols="40" rows="10"></textarea>
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,67 @@
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js"></script>
<script type="text/javascript" src="js/jsondiffpatch.min.js"></script>
<script type="text/javascript" src="js/jsondiffpatch-formatters.min.js"></script>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<link rel="stylesheet" href="css/html.css" type="text/css" />
<link rel="stylesheet" href="css/annotated.css" type="text/css" />
</head>
<body ng-app="DiffApp">
<div ng-controller="DiffCtrl as d">
<button type="button" ng-click="d.get_data()">Get Data</button>
<button type="button" ng-click="d.compare()">Compare</button>
<br/>
<textarea id="text1" columns="40" rows="10" ng-model="d.left"></textarea>
<div id="visual"></div>
<textarea id="text2" columns="40" rows="10" ng-model="d.right"></textarea>
<hr/>
<div id="annotated"></div>
</div>
<script>
(function(angular) {
'use strict';
angular.module('DiffApp',[]);
function DiffCtrl($scope) {
var self = this;
this.left = "";
this.right = "";
console.log("HEELLLLO!!!");
this.get_data = function() {
console.log("Starting to load data...");
jQuery.getJSON("data.json", function(data) {
console.log("Loaded data.json");
self.left = JSON.stringify(data, null, 2);
$scope.$apply();
})
.fail(function(fail) {
console.log("FAIL", fail);
});
jQuery.getJSON("data2.json", function(json) {
console.log("Loaded data2.json");
self.right = JSON.stringify(json, null, 2);
$scope.$apply();
});
};
this.compare = function() {
console.log("Running compare");
// beautiful html diff
var jsonLeft = JSON.parse(self.left);
var jsonRight = JSON.parse(self.right);
var delta = jsondiffpatch.diff(jsonLeft, jsonRight);
document.getElementById('visual').innerHTML = jsondiffpatch.formatters.html.format(delta, jsonLeft);
// self-explained json
document.getElementById('annotated').innerHTML = jsondiffpatch.formatters.annotated.format(delta, jsonLeft);
};
};
angular.module('DiffApp').controller('DiffCtrl', ['$scope', DiffCtrl]);
}(window.angular));
</script>
</body>
</html>

View File

@ -7,21 +7,21 @@
var self = this; var self = this;
var adjectives = Array('Bold','Breaking','Brilliant','Crescent','Dark|Darkness','Desert|Desert','Eternal','Evening|Darkness','Final','First','Forever','Glorious','Joyful','July','Last','Liberty|Liberty','Magic|Magic','Morning|Morning','Power|Power','Phantom','Present','Roaring|Roar|Scream','Rolling','Sand','Screaming|Roar|Scream','Soaring','Standing|Stand','Star|Star','Twisted','Urgent','Utopian','Valiant'); var adjectives = Array('Ancient','Bold','Breaking','Brightest','Brilliant','Crescent','Dark|Darkness','Darkest|Darkness','Desert|Desert','Eternal','Evening|Darkness','Final','First','Forever','Giant|Giant','Glorious|Glory','Joyful|Joy','July','Last','Liberty|Liberty','Magic|Magic','Morning|Morning','Power|Power','Phantom','Present','Righteous','Roaring|Roar|Scream','Rolling','Sand','Screaming|Roar|Scream','Silent','Soaring','Standing|Stand','Star|Star','Stunning','Super','Thunderous|Thunder','Twisted','Urgent','Utopian','Valiant');
var nouns = Array('Action','Alert','Beauty','Claw','Darkness','Dawn','Day','Desert','Envy','Fall','Fist','Flight','Fury','Guard','Hammer','Hand','Honor','Hope','Hurricane','Liberty','Light','Lightning','Magic','Morning','October','Power','Rain','Repose','Roar','Scream','Skull','Sky','Skies','Shield','Stand','Star','Storm','Streak','Strike','Sun','Thunder','Victory','Whisper','Wind','Wrath'); var nouns = Array('Action','Alert','Bane','Beauty','Claw','Darkness','Dawn','Day','Defense','Desert','Envy','Fall','Fist','Flight','Fury','Guard','Glory','Hammer','Hand','Honor','Hope','Hunt','Hurricane','Joy','Liberty','Light','Lightning','Magic','Morning','October','Power','Rain','Response','Repose','Roar','Scream','Skull','Sky','Skies','Shield','Shout','Stand','Star','Storm','Streak','Strike','Sun','Thunder','Victory','Whisper','Wind','Wrath');
var colors = Array('Black','Blue','Brown','Gray','Green','Indego','Orange','Purple','Rainbow','Red','Scarlet','Silver','Violet','White','Yellow'); var colors = Array('Black','Blue','Brown','Golden','Gray','Green','Indego','Orange','Purple','Rainbow','Red','Scarlet','Silver','Violet','White','Yellow');
var actors = Array('Cobra','Condor','Dragon','Eagle','Guardian','Hawk','Hydra','Jackal','King','Knight','Lady','Lion','Scorpion','Spartan','Titan','Victor','Viking','Warrior'); var actors = Array('Cobra','Condor','Dragon','Eagle','Giant','Guardian','Hawk','Hydra','Jackal','King','Knight','Lady','Lion','Scorpion','Spartan','Stranger','Titan','Victor','Viking','Warrior');
var mission_grammars = Array( var mission_grammars = Array(
{chance:30, grammar: "{adj1} {noun1}"}, {chance:30, grammar: "{adj1} {noun1}"},
{chance:20, grammar: "{adj1} {actor}"}, {chance:20, grammar: "{adj1} {actor}"},
{chance:10, grammar: "{color} {noun1}"}, {chance:10, grammar: "{color} {noun1}"},
{chance:10, grammar: "{color} {actor}"}, {chance:10, grammar: "{color} {actor}"},
{chance:10, grammar: "{actor}'s {noun1}"}, {chance:20, grammar: "{actor}'s {noun1}"},
{chance:10, grammar: "{noun1} of the {noun2}"}, //{chance:10, grammar: "{noun1} of the {noun2}"}, //this one has been producing too many odd lines
{chance:10, grammar: "{noun1} of the {actor}"}, {chance:10, grammar: "{noun1} of the {actor}"},
{chance:10, grammar: "{actor} of the {noun1}"}, {chance:10, grammar: "{actor} of the {noun1}"},
{chance:10, grammar: "{noun1} of {noun2}"}, {chance:5, grammar: "{noun1} of {noun2}"},
{chance:10, grammar: "{noun1} of {color} {noun2}"}, {chance:5, grammar: "{noun1} of {color} {noun2}"},
{chance:10, grammar: "{adj1} {noun1} and {adj2} {noun2}"}, {chance:10, grammar: "{adj1} {noun1} and {adj2} {noun2}"},
{chance:3, grammar: "Attack of the {actor}s"}, {chance:3, grammar: "Attack of the {actor}s"},
{chance:3, grammar: "Return of the {actor}s"} {chance:3, grammar: "Return of the {actor}s"}