Changed tweets, added eca

This commit is contained in:
2022-10-25 12:15:41 +02:00
parent 7597d7648a
commit 9860bee497
71 changed files with 7476 additions and 2036 deletions

56
demos/advancedcontexts.py Normal file
View File

@@ -0,0 +1,56 @@
from eca import *
import random
# declare two separate rule sets
consumer = Rules()
producer = Rules()
# default init
@event('init')
def bootstrap(c, e):
# start a few contexts for the generation of stock quotes
# (The simple workload here can easily be done in a single context, but we
# do this in separate contexts to give an example of the feature.)
spawn_context({'symbol':'GOOG', 'start':500.0, 'delay':1.2}, rules=producer, daemon=True)
spawn_context({'symbol':'AAPL', 'start':99.0, 'delay':0.9}, rules=producer, daemon=True)
spawn_context(rules=consumer, daemon=True)
@event('end-of-input')
def done(c,e):
# terminate if the input is closed
shutdown()
# producer rules
@producer.event('init')
def start_work(c, e):
c.symbol = e.data['symbol']
c.delay = e.data['delay']
fire('sample', {
'previous': e.data['start']
})
@producer.event('sample')
def work(c, e):
current = e.data['previous'] + random.uniform(-0.5, 0.5)
fire_global('quote', {
'symbol': c.symbol,
'value': current
})
fire('sample', {
'previous': current
}, delay=c.delay)
# consumer rules
@consumer.event('quote')
def show_quote(c, e):
print("Quote for {symbol}: {value}".format(**e.data))

47
demos/average.py Normal file
View File

@@ -0,0 +1,47 @@
from eca import *
@event('main')
def setup(ctx, e):
"""
Initialise the context with an accumulator value, and inform
the user about the fact that we process input.
"""
print("Enter a number per line and end with EOF:")
print("(EOF is ctrl+d under linux and MacOSes, ctrl+z followed by return under Windows)")
ctx.accumulator = 0
ctx.count = 0
@event('line')
def line(ctx, e):
"""
Tries to parse the input line as a number and add it to the accumulator.
"""
try:
value = float(e.data) if '.' in e.data else int(e.data)
ctx.accumulator += value
ctx.count += 1
print("sum = " + str(ctx.accumulator))
except ValueError:
print("'{}' is not a number.".format(e.data))
@event('end-of-input')
@condition(lambda c,e: c.count > 0)
def done(ctx, e):
"""
Outputs the final average to the user.
"""
print("{} samples with average of {}".format(ctx.count, ctx.accumulator / ctx.count))
shutdown()
@event('end-of-input')
@condition(lambda c,e: c.count == 0)
def no_input(ctx, e):
"""
Invoked of no input is given and input is finished.
"""
print("0 samples. \"Does not compute!\"")
shutdown()

40
demos/chat.py Normal file
View File

@@ -0,0 +1,40 @@
from eca import *
import datetime
import eca.http
# add message posting handler
def add_request_handlers(httpd):
httpd.add_route('/api/message', eca.http.GenerateEvent('incoming'), methods=['POST'])
# use the library content from the template_static dir instead of our own
# this is a bit finicky, since execution now depends on a proper working directory.
httpd.add_content('/lib/', 'template_static/lib')
httpd.add_content('/style/', 'template_static/style')
# store name of context
@event('init')
def setup(ctx, e):
ctx.name = e.data['name']
# emit incoming messages to the client
@event('message')
def on_message(ctx, e):
name = e.data['name']
text = e.data['text']
time = e.data['time'].strftime('%Y-%m-%d %H:%M:%S')
emit('message',{
'text': "{} @{}: {}".format(name, time, text)
})
# do a global fire for each message from the client
@event('incoming')
def on_incoming(ctx, e):
fire_global('message', {
'name': ctx.name,
'text': e.data['text'],
'time': datetime.datetime.now()
})

View File

@@ -0,0 +1,44 @@
<!DOCTYPE html>
<html>
<head>
<title>Neca Test</title>
<link rel="stylesheet" href="/style/layout.css"/>
<link rel="stylesheet" href="/style/theme.css"/>
<script src="/lib/jquery-2.1.1.min.js"></script>
<script src="/lib/jquery.flot.min.js"></script>
<script src="/lib/core.js"></script>
<script src="/lib/form.js"></script>
<script src="/lib/log.js"></script>
</head>
<body class="container_12">
<h1>ECA Chat</h1>
<div id='messages' class='grid_12 vert_4'></div>
<div id='form' class='grid_8 vert_2'>
<form>
<textarea name='text' style='width: 100%'></textarea>
<input type='submit' value='Send message'/>
</form>
</div>
<script>
block('#messages').log();
events.connect('message', '#messages');
block('#form').form({
target: '/api/message',
callback: function() {
$('textarea').val('');
}
});
// small usability tweak
$('textarea').keydown(function(e) {
if((e.which == 10 || e.which == 13) && e.ctrlKey) {
$('#form input[type="submit"]').click();
}
});
</script>
</body>
</html>

52
demos/drinks.py Normal file
View File

@@ -0,0 +1,52 @@
from eca import *
import eca.http
from pprint import pprint
# This function will be called to set up the HTTP server
def add_request_handlers(httpd):
# add an event-generating request handler to fire 'order' events
# This requires the POST method because the event generation handler only
# understands POST requests.
httpd.add_route('/api/order', eca.http.GenerateEvent('order'), methods=['POST'])
# use the library content from the template_static dir instead of our own
# this is a bit finicky, since execution now depends on a proper working directory.
httpd.add_content('/lib/', 'template_static/lib')
httpd.add_content('/style/', 'template_static/style')
@event('order')
def order(c, e):
# we received an order...
# ...go an print it
print("Received a new order:")
pprint(e.data)
# ...and emit it to all interested browsers
# (conceptually, this could also include the Barista's workstation)
emit('orders',{
'text': str(e.data)
});
# Below are some examples of how to handle incoming requests based
# on observed qualities.
# Inform the coffee machine handler that more coffee is required.
@event('order')
@condition(lambda c,e: e.data['drink'] == 'Coffee')
def start_brewing(c,e):
print("-> Start the coffee brewer!")
# Check for a very specific order
@event('order')
@condition(lambda c,e: e.data['drink'] == 'Tea'
and not e.data['additives']
and e.data['type'].lower() == 'earl grey'
and 'hot' in e.data['notes'].lower())
def picard_has_arrived(c,e):
print("-> Captain Picard has arrived.")

View File

@@ -0,0 +1,64 @@
<!DOCTYPE html>
<html>
<head>
<title>Neca Test</title>
<link rel="stylesheet" href="/style/layout.css"/>
<link rel="stylesheet" href="/style/theme.css"/>
<script src="/lib/jquery-2.1.1.min.js"></script>
<script src="/lib/jquery.flot.min.js"></script>
<script src="/lib/core.js"></script>
<script src="/lib/log.js"></script>
<script src="/lib/form.js"></script>
</head>
<body class="container_12">
<h1>Hot Drinks Dashboard</h1>
<!-- Add an order log -->
<div id='log' class="grid_6 vert_6"></div>
<!-- Input form -->
<div id='knopjes' class="grid_6 vert_4">
<h3>Your Order...</h3>
<form>
<div>
<select name='drink'>
<option>Coffee</option>
<option>Tea</option>
</select>
<label for='type_box'>Type</label> <input type='text' name='type' id='type_box'/>
</div>
<div>
Extras:
<input type='checkbox' name='additives' value='sugar' id='sugar_box'/> <label for='sugar_box'>+Sugar</label>
<input type='checkbox' name='additives' value='milk' id='milk_box'/> <label for='milk_box'>+Milk</label>
</div>
<div>
<label for="notes_box">Notes:</label>
<textarea name='notes' id='notes_box' style="width:100%"></textarea>
</div>
<div>
<input type='radio' name='when' id='when_now' value='now'/><label for='when_now'>Now</label><br>
<input type='radio' name='when' id='when_later' value='later'/><label for='when_later'>Later</label>
</div>
<input type='submit' value='Place order'/>
</form>
</div>
<script>
// connect order log to 'orders' emit
block('#log').log();
events.connect('orders', '#log');
// target the form at the exposed API
block('#knopjes').form({
target: '/api/order'
});
</script>
</body>
</html>

94
demos/rolling_chart.py Normal file
View File

@@ -0,0 +1,94 @@
from eca import *
import random
# This function will be called to set up the HTTP server
def add_request_handlers(httpd):
# use the library content from the template_static dir instead of our own
# this is a bit finicky, since execution now depends on a proper working directory.
httpd.add_content('/lib/', 'template_static/lib')
httpd.add_content('/style/', 'template_static/style')
# binds the 'setup' function as the action for the 'init' event
# the action will be called with the context and the event
@event('init')
def setup(ctx, e):
ctx.count = 0
ctx.samples = {
'sensor0': 0.0,
'sensor1': 0.0
}
fire('sample', {
'previous': 0.0,
'name': 'sensor0',
'failure-chance': 0.0,
'reboot-chance': 1.0,
'delay': 0.05
})
fire('sample', {
'previous': 0.0,
'name': 'sensor1',
'failure-chance': 0.05,
'reboot-chance': 0.1,
'delay': 0.05
})
fire('sample', {
'previous': None,
'name': 'sensor2',
'failure-chance': 0.2,
'reboot-chance': 0.8,
'delay': 0.1
})
fire('tick')
# define a normal Python function
def clip(lower, value, upper):
return max(lower, min(value, upper))
@event('sample')
@condition(lambda c,e: e.get('previous') is not None)
def generate_sample(ctx, e):
sample = e.get('previous')
# failure chance off...
if e.get('failure-chance') > random.random():
sample = None
del ctx.samples[e.get('name')]
else:
# base sample on previous one
sample = clip(-100, e.get('previous') + random.uniform(+5.0, -5.0), 100)
ctx.samples[e.get('name')] = sample
# chain event
data = dict(e.data)
data.update({'previous': sample})
fire('sample', data, delay=e.get('delay'))
@event('sample')
@condition(lambda c,e: e.get('previous') is None)
def try_reboot(ctx, e):
sample = e.get('previous')
if e.get('reboot-chance') > random.random():
sample = random.uniform(100,-100)
ctx.samples[e.get('name')] = sample
data = dict(e.data)
data.update({'previous': sample})
fire('sample', data, delay=e.get('delay'))
@event('tick')
def tick(ctx, e):
# emit to outside world
emit('sample',{
'action': 'add',
'values': ctx.samples
})
fire('tick', delay=0.05);

View File

@@ -0,0 +1,65 @@
<!DOCTYPE html>
<html>
<head>
<title>Neca Test</title>
<link rel="stylesheet" href="/style/layout.css"/>
<link rel="stylesheet" href="/style/theme.css"/>
<script src="/lib/jquery-2.1.1.min.js"></script>
<script src="/lib/jquery.flot.min.js"></script>
<script src="/lib/core.js"></script>
<script src="/lib/charts.js"></script>
</head>
<body class="container_12">
<h1>Rolling Chart Dashboard</h1>
<div id="graph0" class="grid_12 vert_5"></div>
<div id="graph1" class="grid_12 vert_5"></div>
<script>
// create a rolling chart block
block('#graph0').rolling_chart({
memory: 75,
series: {
'sensor0': {},
'sensor1': {}
},
chart: {
yaxis:{
min: -100,
max: 100
},
xaxis: {
show: false
}
}
});
block('#graph1').rolling_chart({
memory: 150,
series: {
'sensor0': {},
'sensor1': {},
'sensor2': {
lines: {
fill: true,
steps: true
}
}
},
chart: {
yaxis:{
min: -100,
max: 100
},
xaxis: {
show: false
}
}
});
// connect sample event to graph
events.connect('sample', '#graph0');
events.connect('sample', '#graph1');
</script>
</body>
</html>

52
demos/shout.js Normal file
View File

@@ -0,0 +1,52 @@
/*
* This file is the demo for a block definition. For more information
* see:
* https://github.com/utwente-db/eca/wiki/Extending:-Creating-Your-Own-Blocks
*
*/
(function($, block) {
block.fn.shout = function(config) {
// handle configuration
var options = $.extend({
size: '64pt',
text: 'RED',
color: 'red'
}, config);
// create HTML representation
var $el = $('<span></span>').appendTo(this.$element);
$el.css('font-size', options.size);
// create HTML element for display
var data = {
text: options.text,
color: options.color
}
// update function to update element
var update = function() {
$el.text(data.text+'!').css('color', data.color);
}
// invoke update to initialise the display
update();
// register actions
this.actions({
word: function(e, message) {
data.text = message.text;
update();
},
color: function(e, message) {
data.color = message.color;
update();
}
});
// return the element for further work
return this.$element;
}
})(jQuery, block);

25
demos/tweet_arff.py Normal file
View File

@@ -0,0 +1,25 @@
from eca import *
from eca.generators import start_offline_tweets
import datetime
import textwrap
@event('init')
def setup(ctx, e):
# start the offline tweet stream
start_offline_tweets('data/batatweets.txt', 'chirp', time_factor=10000, arff_file='data/batatweets.arff')
@event('chirp')
def tweet(ctx, e):
# we receive a tweet
tweet = e.data
# parse date
time = datetime.datetime.strptime(tweet['created_at'], '%a %b %d %H:%M:%S %z %Y')
# nicify text
text = textwrap.fill(tweet['text'],initial_indent=' ', subsequent_indent=' ')
# generate output
output = "[{}] {} (@{}) +{}:\n{}".format(time, tweet['user']['name'], tweet['user']['screen_name'], tweet['extra']['@@class@@'], text)
emit('tweet', output)

25
demos/tweet_rules.py Normal file
View File

@@ -0,0 +1,25 @@
from eca import *
from eca.generators import start_offline_tweets
import datetime
import textwrap
@event('init')
def setup(ctx, e):
# start the offline tweet stream
start_offline_tweets('data/batatweets.txt', 'chirp', time_factor=10000)
@event('chirp')
def tweet(ctx, e):
# we receive a tweet
tweet = e.data
# parse date
time = datetime.datetime.strptime(tweet['created_at'], '%a %b %d %H:%M:%S %z %Y')
# nicify text
text = textwrap.fill(tweet['text'],initial_indent=' ', subsequent_indent=' ')
# generate output
output = "[{}] {} (@{}):\n{}".format(time, tweet['user']['name'], tweet['user']['screen_name'], text)
emit('tweet', output)

53
demos/wordcloud.py Normal file
View File

@@ -0,0 +1,53 @@
from eca import *
from eca.generators import start_offline_tweets
import datetime
import textwrap
import pprint
import re
# This function will be called to set up the HTTP server
def add_request_handlers(httpd):
# use the library content from the template_static dir instead of our own
# this is a bit finicky, since execution now depends on a proper working directory.
httpd.add_content('/lib/', 'template_static/lib')
httpd.add_content('/style/', 'template_static/style')
@event('init')
def setup(ctx, e):
# start the offline tweet stream
start_offline_tweets('data/bata_2014.txt', 'chirp', time_factor=100000)
ctx.words = {}
# simple word splitter
pattern = re.compile('\W+')
# sample stopword list, needs to be much more sophisticated
stopwords = ['het', 'een', 'aan', 'zijn', 'http', 'www', 'com', 'ben', 'jij']
def words(message):
result = pattern.split(message)
result = map(lambda w: w.lower(), result)
result = filter(lambda w: w not in stopwords, result)
result = filter(lambda w: len(w) > 2, result)
return result
@event('chirp')
def tweet(ctx, e):
# we receive a tweet
tweet = e.data
for w in words(tweet['text']):
emit('word', {
'action': 'add',
'value': (w, 1)
})
emit('taart', {
'action': 'add',
'value': (str(w[0]), 1)
})
emit('balk', {
'action': 'add',
'value': (str(w[0]), 1)
})

View File

@@ -0,0 +1,40 @@
<!DOCTYPE html>
<html>
<head>
<title>Neca Test</title>
<link rel="stylesheet" href="/style/layout.css"/>
<link rel="stylesheet" href="/style/theme.css"/>
<link rel="stylesheet" href="/style/wordcloud.css"/>
<script src="/lib/jquery-2.1.1.min.js"></script>
<script src="/lib/jquery.flot.min.js"></script>
<script src="/lib/jquery.flot.categories.min.js"></script>
<script src="/lib/jquery.flot.pie.js"></script>
<script src="/lib/core.js"></script>
<script src="/lib/charts.js"></script>
<script src="/lib/jqcloud-1.0.4.js"></script>
<script src="/lib/wordcloud.js"></script>
<script src="/lib/tweets.js"></script>
</head>
<body class="container_12">
<h1>Word Cloud Dashboard</h1>
<div id="wolk" class="grid_12 vert_4"></div>
<div id="taart" class="grid_6 vert_4"></div>
<div id="balk" class="grid_6 vert_4"></div>
<script>
block('#wolk').wordcloud({
filter_function: function(cat, val, max) {
return val >= 3; // do not display words seen less than 3 times
}
});
events.connect('word', '#wolk');
block('#taart').piechart();
events.connect('taart', '#taart');
block('#balk').barchart();
events.connect('balk', '#balk');
</script>
</body>
</html>