This commit is contained in:
Tony Garnock-Jones 2016-07-11 12:16:51 -04:00
parent 4ea5b79f3f
commit a0143855f3
5 changed files with 215 additions and 121 deletions

View File

@ -105,7 +105,7 @@ Syndicate.Actor.createFacet()
}); });
} }
} }
var _cachedAssertion1468253137502_0 = (function() { var _ = Syndicate.__; return fromBroker(wsurl, locationRecord(id, email, _, _, _)); })(); var _cachedAssertion1468253787297_0 = (function() { var _ = Syndicate.__; return fromBroker(wsurl, locationRecord(id, email, _, _, _)); })();
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.addInitBlock((function() { .addInitBlock((function() {
marker.addListener('click', Syndicate.Dataspace.wrap(function () { marker.addListener('click', Syndicate.Dataspace.wrap(function () {
@ -132,6 +132,6 @@ Syndicate.Actor.createFacet()
marker.setMap(null); marker.setMap(null);
if (selectedMarker === marker) selectedMarker = null; if (selectedMarker === marker) selectedMarker = null;
})) }))
.onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1468253137502_0, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1468253137502_0, metalevel: 0 }; }), (function() {})).completeBuild(); })).completeBuild(); })(); .onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1468253787297_0, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1468253787297_0, metalevel: 0 }; }), (function() {})).completeBuild(); })).completeBuild(); })();
}); });
}).startStepping(); }).startStepping();

View File

@ -54,10 +54,10 @@ function todoListItemView(id) {
(function () { (function () {
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(todo(id, _, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: todo(id, (Syndicate._$("title")), (Syndicate._$("completed"))), metalevel: 0 }; }), (function(title, completed) { .onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(todo(id, _, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: todo(id, (Syndicate._$("title")), (Syndicate._$("completed"))), metalevel: 0 }; }), (function(title, completed) {
var _cachedAssertion1468253138670_0 = (function() { var _ = Syndicate.__; return todo(id, title, completed); })(); var _cachedAssertion1468253788491_0 = (function() { var _ = Syndicate.__; return todo(id, title, completed); })();
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(show(completed), 0); }), (function() { var _ = Syndicate.__; return { assertion: show(completed), metalevel: 0 }; }), (function() { .onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(show(completed), 0); }), (function() { var _ = Syndicate.__; return { assertion: show(completed), metalevel: 0 }; }), (function() {
var _cachedAssertion1468253138670_1 = (function() { var _ = Syndicate.__; return show(completed); })(); var _cachedAssertion1468253788491_1 = (function() { var _ = Syndicate.__; return show(completed); })();
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(this.ui.html('.todo-list', .addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(this.ui.html('.todo-list',
Mustache.render(getTemplate(this.editing Mustache.render(getTemplate(this.editing
@ -70,8 +70,8 @@ Syndicate.Actor.createFacet()
checked: completed ? "checked" : "", checked: completed ? "checked" : "",
}), }),
id), 0); })) id), 0); }))
.onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1468253138670_1, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1468253138670_1, metalevel: 0 }; }), (function() {})).completeBuild(); })) .onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1468253788491_1, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1468253788491_1, metalevel: 0 }; }), (function() {})).completeBuild(); }))
.onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1468253138670_0, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1468253138670_0, metalevel: 0 }; }), (function() {})).completeBuild(); })) .onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1468253788491_0, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1468253788491_0, metalevel: 0 }; }), (function() {})).completeBuild(); }))
.onEvent(false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(this.ui.event('.toggle', 'change', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: this.ui.event('.toggle', 'change', (Syndicate._$("e"))), metalevel: 0 }; }), (function(e) { .onEvent(false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(this.ui.event('.toggle', 'change', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: this.ui.event('.toggle', 'change', (Syndicate._$("e"))), metalevel: 0 }; }), (function(e) {
Syndicate.Dataspace.send(setCompleted(id, e.target.checked)); Syndicate.Dataspace.send(setCompleted(id, e.target.checked));
})) }))
@ -119,31 +119,31 @@ Syndicate.Actor.createFacet()
(function () { (function () {
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(activeTodoCount(_), 0); }), (function() { var _ = Syndicate.__; return { assertion: activeTodoCount((Syndicate._$("count"))), metalevel: 0 }; }), (function(count) { .onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(activeTodoCount(_), 0); }), (function() { var _ = Syndicate.__; return { assertion: activeTodoCount((Syndicate._$("count"))), metalevel: 0 }; }), (function(count) {
var _cachedAssertion1468253138670_2 = (function() { var _ = Syndicate.__; return activeTodoCount(count); })(); var _cachedAssertion1468253788491_2 = (function() { var _ = Syndicate.__; return activeTodoCount(count); })();
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(this.ui.context('count').html('.todo-count strong', '' + count), 0); })) .addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(this.ui.context('count').html('.todo-count strong', '' + count), 0); }))
.addAssertion((function() { var _ = Syndicate.__; return (count !== 1) ? Syndicate.Patch.assert(, 0) : Syndicate.Patch.emptyPatch; })) .addAssertion((function() { var _ = Syndicate.__; return (count !== 1) ? Syndicate.Patch.assert(, 0) : Syndicate.Patch.emptyPatch; }))
.onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1468253138670_2, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1468253138670_2, metalevel: 0 }; }), (function() {})).completeBuild(); })) .onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1468253788491_2, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1468253788491_2, metalevel: 0 }; }), (function() {})).completeBuild(); }))
.onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(totalTodoCount(0), 0); }), (function() { var _ = Syndicate.__; return { assertion: totalTodoCount(0), metalevel: 0 }; }), (function() { .onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(totalTodoCount(0), 0); }), (function() { var _ = Syndicate.__; return { assertion: totalTodoCount(0), metalevel: 0 }; }), (function() {
var _cachedAssertion1468253138670_3 = (function() { var _ = Syndicate.__; return totalTodoCount(0); })(); var _cachedAssertion1468253788491_3 = (function() { var _ = Syndicate.__; return totalTodoCount(0); })();
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(Syndicate.UI.uiAttribute('section.main', 'class', 'hidden'), 0); })) .addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(Syndicate.UI.uiAttribute('section.main', 'class', 'hidden'), 0); }))
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(Syndicate.UI.uiAttribute('footer.footer', 'class', 'hidden'), 0); })) .addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(Syndicate.UI.uiAttribute('footer.footer', 'class', 'hidden'), 0); }))
.onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1468253138670_3, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1468253138670_3, metalevel: 0 }; }), (function() {})).completeBuild(); })) .onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1468253788491_3, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1468253788491_3, metalevel: 0 }; }), (function() {})).completeBuild(); }))
.onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(completedTodoCount(0), 0); }), (function() { var _ = Syndicate.__; return { assertion: completedTodoCount(0), metalevel: 0 }; }), (function() { .onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(completedTodoCount(0), 0); }), (function() { var _ = Syndicate.__; return { assertion: completedTodoCount(0), metalevel: 0 }; }), (function() {
var _cachedAssertion1468253138670_4 = (function() { var _ = Syndicate.__; return completedTodoCount(0); })(); var _cachedAssertion1468253788491_4 = (function() { var _ = Syndicate.__; return completedTodoCount(0); })();
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(Syndicate.UI.uiAttribute('button.clear-completed', 'class', 'hidden'), 0); })) .addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(Syndicate.UI.uiAttribute('button.clear-completed', 'class', 'hidden'), 0); }))
.onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1468253138670_4, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1468253138670_4, metalevel: 0 }; }), (function() {})).completeBuild(); })) .onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1468253788491_4, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1468253788491_4, metalevel: 0 }; }), (function() {})).completeBuild(); }))
.onEvent(false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.globalEvent('button.clear-completed', 'click', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.globalEvent('button.clear-completed', 'click', _), metalevel: 0 }; }), (function() { .onEvent(false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.globalEvent('button.clear-completed', 'click', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.globalEvent('button.clear-completed', 'click', _), metalevel: 0 }; }), (function() {
Syndicate.Dataspace.send(clearCompletedTodos()); Syndicate.Dataspace.send(clearCompletedTodos());
})) }))
.onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(allCompleted(), 0); }), (function() { var _ = Syndicate.__; return { assertion: allCompleted(), metalevel: 0 }; }), (function() { .onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(allCompleted(), 0); }), (function() { var _ = Syndicate.__; return { assertion: allCompleted(), metalevel: 0 }; }), (function() {
var _cachedAssertion1468253138670_5 = (function() { var _ = Syndicate.__; return allCompleted(); })(); var _cachedAssertion1468253788491_5 = (function() { var _ = Syndicate.__; return allCompleted(); })();
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.addInitBlock((function() { Syndicate.Dataspace.send(Syndicate.UI.setProperty('.toggle-all', 'checked', true)); })) .addInitBlock((function() { Syndicate.Dataspace.send(Syndicate.UI.setProperty('.toggle-all', 'checked', true)); }))
.addDoneBlock((function() { Syndicate.Dataspace.send(Syndicate.UI.setProperty('.toggle-all', 'checked', false)); })) .addDoneBlock((function() { Syndicate.Dataspace.send(Syndicate.UI.setProperty('.toggle-all', 'checked', false)); }))
.onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1468253138670_5, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1468253138670_5, metalevel: 0 }; }), (function() {})).completeBuild(); })) .onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1468253788491_5, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1468253788491_5, metalevel: 0 }; }), (function() {})).completeBuild(); }))
.onEvent(false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.globalEvent('.toggle-all', 'change', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.globalEvent('.toggle-all', 'change', (Syndicate._$("e"))), metalevel: 0 }; }), (function(e) { .onEvent(false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.globalEvent('.toggle-all', 'change', _), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.globalEvent('.toggle-all', 'change', (Syndicate._$("e"))), metalevel: 0 }; }), (function(e) {
Syndicate.Dataspace.send(setAllCompleted(e.target.checked)); Syndicate.Dataspace.send(setAllCompleted(e.target.checked));
})) }))
@ -169,27 +169,27 @@ Syndicate.Actor.createFacet()
(function () { (function () {
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.locationHash(_), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.locationHash((Syndicate._$("hash"))), metalevel: 0 }; }), (function(hash) { .onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.locationHash(_), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.locationHash((Syndicate._$("hash"))), metalevel: 0 }; }), (function(hash) {
var _cachedAssertion1468253138670_6 = (function() { var _ = Syndicate.__; return Syndicate.UI.locationHash(hash); })(); var _cachedAssertion1468253788491_6 = (function() { var _ = Syndicate.__; return Syndicate.UI.locationHash(hash); })();
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(Syndicate.UI.uiAttribute('ul.filters > li > a[href="#'+hash+'"]', .addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(Syndicate.UI.uiAttribute('ul.filters > li > a[href="#'+hash+'"]',
'class', 'selected'), 0); })) 'class', 'selected'), 0); }))
.onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1468253138670_6, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1468253138670_6, metalevel: 0 }; }), (function() {})).completeBuild(); })) .onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1468253788491_6, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1468253788491_6, metalevel: 0 }; }), (function() {})).completeBuild(); }))
.onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.locationHash('/'), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.locationHash('/'), metalevel: 0 }; }), (function() { .onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.locationHash('/'), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.locationHash('/'), metalevel: 0 }; }), (function() {
var _cachedAssertion1468253138670_7 = (function() { var _ = Syndicate.__; return Syndicate.UI.locationHash('/'); })(); var _cachedAssertion1468253788491_7 = (function() { var _ = Syndicate.__; return Syndicate.UI.locationHash('/'); })();
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(show(true), 0); })) .addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(show(true), 0); }))
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(show(false), 0); })) .addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(show(false), 0); }))
.onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1468253138670_7, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1468253138670_7, metalevel: 0 }; }), (function() {})).completeBuild(); })) .onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1468253788491_7, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1468253788491_7, metalevel: 0 }; }), (function() {})).completeBuild(); }))
.onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.locationHash('/active'), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.locationHash('/active'), metalevel: 0 }; }), (function() { .onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.locationHash('/active'), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.locationHash('/active'), metalevel: 0 }; }), (function() {
var _cachedAssertion1468253138670_8 = (function() { var _ = Syndicate.__; return Syndicate.UI.locationHash('/active'); })(); var _cachedAssertion1468253788491_8 = (function() { var _ = Syndicate.__; return Syndicate.UI.locationHash('/active'); })();
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(show(false), 0); })) .addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(show(false), 0); }))
.onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1468253138670_8, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1468253138670_8, metalevel: 0 }; }), (function() {})).completeBuild(); })) .onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1468253788491_8, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1468253788491_8, metalevel: 0 }; }), (function() {})).completeBuild(); }))
.onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.locationHash('/completed'), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.locationHash('/completed'), metalevel: 0 }; }), (function() { .onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.UI.locationHash('/completed'), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.UI.locationHash('/completed'), metalevel: 0 }; }), (function() {
var _cachedAssertion1468253138670_9 = (function() { var _ = Syndicate.__; return Syndicate.UI.locationHash('/completed'); })(); var _cachedAssertion1468253788491_9 = (function() { var _ = Syndicate.__; return Syndicate.UI.locationHash('/completed'); })();
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(show(true), 0); })) .addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(show(true), 0); }))
.onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1468253138670_9, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1468253138670_9, metalevel: 0 }; }), (function() {})).completeBuild(); })).completeBuild(); })(); .onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1468253788491_9, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1468253788491_9, metalevel: 0 }; }), (function() {})).completeBuild(); })).completeBuild(); })();
}); });
Syndicate.Actor.spawnActor(new Object(), function() { Syndicate.Actor.spawnActor(new Object(), function() {
@ -218,20 +218,20 @@ Syndicate.Actor.createFacet()
todoListItemModel(db.nextId++, title, false); todoListItemModel(db.nextId++, title, false);
})) }))
.onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(todo(_, _, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: todo((Syndicate._$("id")), _, _), metalevel: 0 }; }), (function(id) { .onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(todo(_, _, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: todo((Syndicate._$("id")), _, _), metalevel: 0 }; }), (function(id) {
var _cachedAssertion1468253138670_10 = (function() { var _ = Syndicate.__; return todo(id, _, _); })(); var _cachedAssertion1468253788491_10 = (function() { var _ = Syndicate.__; return todo(id, _, _); })();
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(todo(id, _, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: todo(id, (Syndicate._$("title")), (Syndicate._$("completed"))), metalevel: 0 }; }), (function(title, completed) { .onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(todo(id, _, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: todo(id, (Syndicate._$("title")), (Syndicate._$("completed"))), metalevel: 0 }; }), (function(title, completed) {
var _cachedAssertion1468253138670_11 = (function() { var _ = Syndicate.__; return todo(id, title, completed); })(); var _cachedAssertion1468253788491_11 = (function() { var _ = Syndicate.__; return todo(id, title, completed); })();
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.addInitBlock((function() { .addInitBlock((function() {
db.todos[id] = {id: id, title: title, completed: completed}; db.todos[id] = {id: id, title: title, completed: completed};
localStorage['todos-syndicate'] = JSON.stringify(db); localStorage['todos-syndicate'] = JSON.stringify(db);
})) }))
.onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1468253138670_11, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1468253138670_11, metalevel: 0 }; }), (function() {})).completeBuild(); })) .onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1468253788491_11, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1468253788491_11, metalevel: 0 }; }), (function() {})).completeBuild(); }))
.addDoneBlock((function() { .addDoneBlock((function() {
delete db.todos[id]; delete db.todos[id];
localStorage['todos-syndicate'] = JSON.stringify(db); localStorage['todos-syndicate'] = JSON.stringify(db);
})) }))
.onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1468253138670_10, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1468253138670_10, metalevel: 0 }; }), (function() {})).completeBuild(); })).completeBuild(); })(); .onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1468253788491_10, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1468253788491_10, metalevel: 0 }; }), (function() {})).completeBuild(); })).completeBuild(); })();
}); });
}).startStepping(); }).startStepping();

View File

@ -2,13 +2,15 @@
var Syndicate = require('../../src/main.js'); var Syndicate = require('../../src/main.js');
/// --> /// -->
/// # {{ page.title }}
///
/// This is an extended two-buyer book-purchase protocol, based /// This is an extended two-buyer book-purchase protocol, based
/// loosely on an example given in: /// loosely on an example given in:
/// ///
/// > K. Honda, N. Yoshida, and M. Carbone, “Multiparty asynchronous /// > K. Honda, N. Yoshida, and M. Carbone, “Multiparty asynchronous
/// > session types,” POPL 2008. /// > session types,” POPL 2008.
/// # The Scenario /// ## The Scenario
/// ///
/// A book-seller responds to requests for book prices when asked. A /// A book-seller responds to requests for book prices when asked. A
/// pair of prospective buyers run through a shopping list. For each /// pair of prospective buyers run through a shopping list. For each
@ -18,9 +20,9 @@ var Syndicate = require('../../src/main.js');
/// different split. If the second buyer agrees to a split, it then /// different split. If the second buyer agrees to a split, it then
/// negotiates the purchase of the book with the book-seller. /// negotiates the purchase of the book with the book-seller.
/// # The Protocol /// ## The Protocol
/// ## Role: SELLER /// ### Role: SELLER
/// ///
/// - when interest in `bookQuote($title, _)` appears, /// - when interest in `bookQuote($title, _)` appears,
/// asserts `bookQuote(title, Maybe Float)`, `false` meaning not available, /// asserts `bookQuote(title, Maybe Float)`, `false` meaning not available,
@ -29,17 +31,17 @@ var Syndicate = require('../../src/main.js');
/// asserts `order(title, offer-price, false, false)` for "no sale", otherwise /// asserts `order(title, offer-price, false, false)` for "no sale", otherwise
/// `order(title, offer-price, PositiveInteger, String)`, an accepted sale. /// `order(title, offer-price, PositiveInteger, String)`, an accepted sale.
/// ## Role: BUYER /// ### Role: BUYER
/// ///
/// - observes `bookQuote(title, $price)` to learn prices. /// - observes `bookQuote(title, $price)` to learn prices.
/// - observes `order(title, offer-price, $id, $delivery-date)` to make orders. /// - observes `order(title, offer-price, $id, $delivery-date)` to make orders.
/// ## Role: SPLIT-PROPOSER /// ### Role: SPLIT-PROPOSER
/// ///
/// - observes `splitProposal(title, asking-price, contribution, $accepted)` /// - observes `splitProposal(title, asking-price, contribution, $accepted)`
/// to make a split-proposal and learn whether it was accepted or not. /// to make a split-proposal and learn whether it was accepted or not.
/// ## Role: SPLIT-DISPOSER /// ### Role: SPLIT-DISPOSER
/// ///
/// - when interest in `splitProposal($title, $asking-price, $contribution, _)` /// - when interest in `splitProposal($title, $asking-price, $contribution, _)`
/// appears, asserts `splitProposal(title, askingPrice, contribution, true)` /// appears, asserts `splitProposal(title, askingPrice, contribution, true)`
@ -48,7 +50,7 @@ var Syndicate = require('../../src/main.js');
/// `splitProposal(title, asking-price, contribution, false)` to indicate they /// `splitProposal(title, asking-price, contribution, false)` to indicate they
/// are unwilling to go through with the deal. /// are unwilling to go through with the deal.
/// # A Sample Run /// ## A Sample Run
/// ///
/// Run the program with `../../bin/syndicatec index.js | node` from a /// Run the program with `../../bin/syndicatec index.js | node` from a
/// checkout of the Syndicate repository. /// checkout of the Syndicate repository.
@ -90,9 +92,9 @@ var Syndicate = require('../../src/main.js');
/// A has bought everything they wanted! /// A has bought everything they wanted!
/// The order for The Wind in the Willows has id 10001485, and will be delivered on March 9th /// The order for The Wind in the Willows has id 10001485, and will be delivered on March 9th
/// # The Code /// ## The Code
/// ## Type Declarations /// ### Type Declarations
/// First, we declare *assertion types* for our protocol. /// First, we declare *assertion types* for our protocol.
@ -101,7 +103,7 @@ var order = Syndicate.Struct.makeConstructor("order", ["title","price","id","del
var splitProposal = Syndicate.Struct.makeConstructor("splitProposal", ["title","price","contribution","accepted"]); var splitProposal = Syndicate.Struct.makeConstructor("splitProposal", ["title","price","contribution","accepted"]);
/// ## Utilities /// ### Utilities
/// This routine is under consideration for possible addition to the /// This routine is under consideration for possible addition to the
/// core library. /// core library.
@ -113,7 +115,7 @@ Syndicate.Actor.createFacet()
.onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.observe(P), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.observe(P), metalevel: 0 }; }), (function() {})).completeBuild(); })(); .onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.observe(P), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.observe(P), metalevel: 0 }; }), (function() {})).completeBuild(); })();
} }
/// ## Implementation: SELLER /// ### Implementation: SELLER
function seller() { function seller() {
Syndicate.Actor.spawnActor(new Object(), function() { Syndicate.Actor.spawnActor(new Object(), function() {
@ -129,16 +131,23 @@ function seller() {
}; };
this.nextOrderId = 10001483; this.nextOrderId = 10001483;
/// Looking up a price yields `false` if no such book is in our
/// inventory.
this.priceOf = function (title) {
return (title in this.books) && this.books[title];
};
/// The seller responds to interest in bookQuotes by asserting a /// The seller responds to interest in bookQuotes by asserting a
/// responsive record, if one exists. /// responsive record, if one exists.
(function () { (function () {
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.observe(bookQuote(_, _)), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.observe(bookQuote((Syndicate._$("title")), _)), metalevel: 0 }; }), (function(title) { .onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.observe(bookQuote(_, _)), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.observe(bookQuote((Syndicate._$("title")), _)), metalevel: 0 }; }), (function(title) {
var _cachedAssertion1468253139911_0 = (function() { var _ = Syndicate.__; return Syndicate.observe(bookQuote(title, _)); })(); var _cachedAssertion1468253789712_0 = (function() { var _ = Syndicate.__; return Syndicate.observe(bookQuote(title, _)); })();
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(bookQuote(title, title in this.books ? this.books[title] : false), 0); })) .addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(bookQuote(title, this.priceOf(title)), 0); }))
.onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1468253139911_0, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1468253139911_0, metalevel: 0 }; }), (function() {})).completeBuild(); })).completeBuild(); })(); .onEvent(true, "retracted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(_cachedAssertion1468253789712_0, 0); }), (function() { var _ = Syndicate.__; return { assertion: _cachedAssertion1468253789712_0, metalevel: 0 }; }), (function() {})).completeBuild(); })).completeBuild(); })();
/// It also responds to order requests. /// It also responds to order requests.
@ -149,9 +158,10 @@ Syndicate.Actor.createFacet()
/// We cannot sell a book we do not have, and we will not sell for /// We cannot sell a book we do not have, and we will not sell for
/// less than our asking price. /// less than our asking price.
var askingPrice = title in this.books ? this.books[title] : false; var askingPrice = this.priceOf(title);
if ((askingPrice === false) || (offerPrice < askingPrice)) { if ((askingPrice === false) || (offerPrice < askingPrice)) {
whileRelevantAssert(order(title, offerPrice, false, false)); whileRelevantAssert(
order(title, offerPrice, false, false));
} else { } else {
/// But if we can sell it, we do so by allocating an order ID and /// But if we can sell it, we do so by allocating an order ID and
@ -161,14 +171,15 @@ Syndicate.Actor.createFacet()
delete this.books[title]; delete this.books[title];
Syndicate.Actor.spawnActor(new Object(), function() { Syndicate.Actor.spawnActor(new Object(), function() {
whileRelevantAssert(order(title, offerPrice, orderId, "March 9th")); whileRelevantAssert(
order(title, offerPrice, orderId, "March 9th"));
}); });
} }
})).completeBuild(); })(); })).completeBuild(); })();
}); });
} }
/// ## Implementation: SPLIT-PROPOSER and book-quote-requestor /// ### Implementation: SPLIT-PROPOSER and book-quote-requestor
function buyerA() { function buyerA() {
Syndicate.Actor.spawnActor(new Object(), function() { Syndicate.Actor.spawnActor(new Object(), function() {
@ -205,7 +216,8 @@ Syndicate.Actor.createFacet()
console.log("A learns that "+title+" is out-of-stock."); console.log("A learns that "+title+" is out-of-stock.");
buyBooks(); buyBooks();
} else { } else {
console.log("A learns that the price of "+title+" is "+price); console.log("A learns that the price of "+title+
" is "+price);
/// Next, repeatedly make split offers to a SPLIT-DISPOSER until /// Next, repeatedly make split offers to a SPLIT-DISPOSER until
/// either one is accepted, or the contribution from the /// either one is accepted, or the contribution from the
@ -236,19 +248,23 @@ Syndicate.Actor.createFacet()
(function () { (function () {
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.onEvent(true, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(splitProposal(title, price, contribution, true), 0); }), (function() { var _ = Syndicate.__; return { assertion: splitProposal(title, price, contribution, true), metalevel: 0 }; }), (function() { .onEvent(true, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(splitProposal(title, price, contribution, true), 0); }), (function() { var _ = Syndicate.__; return { assertion: splitProposal(title, price, contribution, true), metalevel: 0 }; }), (function() {
console.log("A learns that the split-proposal for "+title+" was accepted"); console.log("A learns that the split-proposal for "+
title+" was accepted");
buyBooks(); buyBooks();
})) }))
.onEvent(true, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(splitProposal(title, price, contribution, false), 0); }), (function() { var _ = Syndicate.__; return { assertion: splitProposal(title, price, contribution, false), metalevel: 0 }; }), (function() { .onEvent(true, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(splitProposal(title, price, contribution, false), 0); }), (function() { var _ = Syndicate.__; return { assertion: splitProposal(title, price, contribution, false), metalevel: 0 }; }), (function() {
console.log("A learns that the split-proposal for "+title+" was rejected"); console.log("A learns that the split-proposal for "+
trySplit(title, price, contribution + ((price - contribution) / 2)); title+" was rejected");
trySplit(title,
price,
contribution + ((price - contribution) / 2));
})).completeBuild(); })(); })).completeBuild(); })();
} }
} }
}); });
} }
/// ## Implementation: SPLIT-DISPOSER and BUYER /// ### Implementation: SPLIT-DISPOSER and BUYER
function buyerB() { function buyerB() {
Syndicate.Actor.spawnActor(new Object(), function() { Syndicate.Actor.spawnActor(new Object(), function() {
@ -263,16 +279,24 @@ function buyerB() {
(function () { (function () {
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.observe(splitProposal(_, _, _, _)), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.observe(splitProposal((Syndicate._$("title")), (Syndicate._$("price")), (Syndicate._$("theirContribution")), _)), metalevel: 0 }; }), (function(title, price, theirContribution) { .onEvent(false, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(Syndicate.observe(splitProposal(_,
_,
_,
_)), 0); }), (function() { var _ = Syndicate.__; return { assertion: Syndicate.observe(splitProposal((Syndicate._$("title")),
(Syndicate._$("price")),
(Syndicate._$("theirContribution")),
_)), metalevel: 0 }; }), (function(title, price, theirContribution) {
var myContribution = price - theirContribution; var myContribution = price - theirContribution;
console.log("B is being asked to contribute "+myContribution+" toward "+title+ console.log("B is being asked to contribute "+myContribution+
" at price "+price); " toward "+title+" at price "+price);
/// We may not be able to afford contributing this much. /// We may not be able to afford contributing this much.
if (myContribution > this.funds) { if (myContribution > this.funds) {
console.log("B hasn't enough funds ("+this.funds+" remaining)"); console.log("B hasn't enough funds ("+this.funds+
whileRelevantAssert(splitProposal(title, price, theirContribution, false)); " remaining)");
whileRelevantAssert(
splitProposal(title, price, theirContribution, false));
} else { } else {
/// But if we *can* afford it, update our remaining funds and spawn a /// But if we *can* afford it, update our remaining funds and spawn a
@ -280,13 +304,17 @@ Syndicate.Actor.createFacet()
/// on a split. /// on a split.
var remainingFunds = this.funds - myContribution; var remainingFunds = this.funds - myContribution;
console.log("B accepts the offer, leaving them with "+remainingFunds+" remaining funds"); console.log("B accepts the offer, leaving them with "+
remainingFunds+" remaining funds");
this.funds = remainingFunds; this.funds = remainingFunds;
Syndicate.Actor.spawnActor(new Object(), function() { Syndicate.Actor.spawnActor(new Object(), function() {
(function () { (function () {
Syndicate.Actor.createFacet() Syndicate.Actor.createFacet()
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(splitProposal(title, price, theirContribution, true), 0); })) .addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(splitProposal(title,
price,
theirContribution,
true), 0); }))
.onEvent(true, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(order(title, price, _, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: order(title, price, (Syndicate._$("id")), (Syndicate._$("date"))), metalevel: 0 }; }), (function(id, date) { .onEvent(true, "asserted", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(order(title, price, _, _), 0); }), (function() { var _ = Syndicate.__; return { assertion: order(title, price, (Syndicate._$("id")), (Syndicate._$("date"))), metalevel: 0 }; }), (function(id, date) {
console.log("The order for "+title+" has id "+id+ console.log("The order for "+title+" has id "+id+
", and will be delivered on "+date); ", and will be delivered on "+date);
@ -297,7 +325,7 @@ Syndicate.Actor.createFacet()
}); });
} }
/// ## Starting Configuration /// ### Starting Configuration
new Syndicate.Ground(function () { new Syndicate.Ground(function () {
seller(); seller();

View File

@ -6,13 +6,15 @@
var Syndicate = require('../../src/main.js'); var Syndicate = require('../../src/main.js');
/// --> /// -->
/// # {{ page.title }}
///
/// This is an extended two-buyer book-purchase protocol, based /// This is an extended two-buyer book-purchase protocol, based
/// loosely on an example given in: /// loosely on an example given in:
/// ///
/// > K. Honda, N. Yoshida, and M. Carbone, “Multiparty asynchronous /// > K. Honda, N. Yoshida, and M. Carbone, “Multiparty asynchronous
/// > session types,” POPL 2008. /// > session types,” POPL 2008.
/// # The Scenario /// ## The Scenario
/// ///
/// A book-seller responds to requests for book prices when asked. A /// A book-seller responds to requests for book prices when asked. A
/// pair of prospective buyers run through a shopping list. For each /// pair of prospective buyers run through a shopping list. For each
@ -22,9 +24,9 @@ var Syndicate = require('../../src/main.js');
/// different split. If the second buyer agrees to a split, it then /// different split. If the second buyer agrees to a split, it then
/// negotiates the purchase of the book with the book-seller. /// negotiates the purchase of the book with the book-seller.
/// # The Protocol /// ## The Protocol
/// ## Role: SELLER /// ### Role: SELLER
/// ///
/// - when interest in `bookQuote($title, _)` appears, /// - when interest in `bookQuote($title, _)` appears,
/// asserts `bookQuote(title, Maybe Float)`, `false` meaning not available, /// asserts `bookQuote(title, Maybe Float)`, `false` meaning not available,
@ -33,17 +35,17 @@ var Syndicate = require('../../src/main.js');
/// asserts `order(title, offer-price, false, false)` for "no sale", otherwise /// asserts `order(title, offer-price, false, false)` for "no sale", otherwise
/// `order(title, offer-price, PositiveInteger, String)`, an accepted sale. /// `order(title, offer-price, PositiveInteger, String)`, an accepted sale.
/// ## Role: BUYER /// ### Role: BUYER
/// ///
/// - observes `bookQuote(title, $price)` to learn prices. /// - observes `bookQuote(title, $price)` to learn prices.
/// - observes `order(title, offer-price, $id, $delivery-date)` to make orders. /// - observes `order(title, offer-price, $id, $delivery-date)` to make orders.
/// ## Role: SPLIT-PROPOSER /// ### Role: SPLIT-PROPOSER
/// ///
/// - observes `splitProposal(title, asking-price, contribution, $accepted)` /// - observes `splitProposal(title, asking-price, contribution, $accepted)`
/// to make a split-proposal and learn whether it was accepted or not. /// to make a split-proposal and learn whether it was accepted or not.
/// ## Role: SPLIT-DISPOSER /// ### Role: SPLIT-DISPOSER
/// ///
/// - when interest in `splitProposal($title, $asking-price, $contribution, _)` /// - when interest in `splitProposal($title, $asking-price, $contribution, _)`
/// appears, asserts `splitProposal(title, askingPrice, contribution, true)` /// appears, asserts `splitProposal(title, askingPrice, contribution, true)`
@ -52,7 +54,7 @@ var Syndicate = require('../../src/main.js');
/// `splitProposal(title, asking-price, contribution, false)` to indicate they /// `splitProposal(title, asking-price, contribution, false)` to indicate they
/// are unwilling to go through with the deal. /// are unwilling to go through with the deal.
/// # A Sample Run /// ## A Sample Run
/// ///
/// Run the program with `../../bin/syndicatec index.js | node` from a /// Run the program with `../../bin/syndicatec index.js | node` from a
/// checkout of the Syndicate repository. /// checkout of the Syndicate repository.
@ -94,9 +96,9 @@ var Syndicate = require('../../src/main.js');
/// A has bought everything they wanted! /// A has bought everything they wanted!
/// The order for The Wind in the Willows has id 10001485, and will be delivered on March 9th /// The order for The Wind in the Willows has id 10001485, and will be delivered on March 9th
/// # The Code /// ## The Code
/// ## Type Declarations /// ### Type Declarations
/// First, we declare *assertion types* for our protocol. /// First, we declare *assertion types* for our protocol.
@ -105,7 +107,7 @@ assertion type order(title, price, id, deliveryDate);
assertion type splitProposal(title, price, contribution, accepted); assertion type splitProposal(title, price, contribution, accepted);
/// ## Utilities /// ### Utilities
/// This routine is under consideration for possible addition to the /// This routine is under consideration for possible addition to the
/// core library. /// core library.
@ -118,7 +120,7 @@ function whileRelevantAssert(P) {
} }
} }
/// ## Implementation: SELLER /// ### Implementation: SELLER
function seller() { function seller() {
actor { actor {
@ -134,26 +136,36 @@ function seller() {
}; };
this.nextOrderId = 10001483; this.nextOrderId = 10001483;
/// Looking up a price yields `false` if no such book is in our
/// inventory.
this.priceOf = function (title) {
return (title in this.books) && this.books[title];
};
/// The seller responds to interest in bookQuotes by asserting a /// The seller responds to interest in bookQuotes by asserting a
/// responsive record, if one exists. /// responsive record, if one exists.
react { react {
during Syndicate.observe(bookQuote($title, _)) { during Syndicate.observe(bookQuote($title, _)) {
assert bookQuote(title, title in this.books ? this.books[title] : false); assert bookQuote(title, this.priceOf(title));
} }
} }
/// It also responds to order requests. /// It also responds to order requests.
react { react {
on asserted Syndicate.observe(order($title, $offerPrice, _, _)) { on asserted
Syndicate.observe(order($title, $offerPrice, _, _))
{
/// We cannot sell a book we do not have, and we will not sell for /// We cannot sell a book we do not have, and we will not sell for
/// less than our asking price. /// less than our asking price.
var askingPrice = title in this.books ? this.books[title] : false; var askingPrice = this.priceOf(title);
if ((askingPrice === false) || (offerPrice < askingPrice)) { if ((askingPrice === false) || (offerPrice < askingPrice)) {
whileRelevantAssert(order(title, offerPrice, false, false)); whileRelevantAssert(
order(title, offerPrice, false, false));
} else { } else {
/// But if we can sell it, we do so by allocating an order ID and /// But if we can sell it, we do so by allocating an order ID and
@ -163,7 +175,8 @@ function seller() {
delete this.books[title]; delete this.books[title];
actor { actor {
whileRelevantAssert(order(title, offerPrice, orderId, "March 9th")); whileRelevantAssert(
order(title, offerPrice, orderId, "March 9th"));
} }
} }
} }
@ -171,7 +184,7 @@ function seller() {
} }
} }
/// ## Implementation: SPLIT-PROPOSER and book-quote-requestor /// ### Implementation: SPLIT-PROPOSER and book-quote-requestor
function buyerA() { function buyerA() {
actor { actor {
@ -207,7 +220,8 @@ function buyerA() {
console.log("A learns that "+title+" is out-of-stock."); console.log("A learns that "+title+" is out-of-stock.");
buyBooks(); buyBooks();
} else { } else {
console.log("A learns that the price of "+title+" is "+price); console.log("A learns that the price of "+title+
" is "+price);
/// Next, repeatedly make split offers to a SPLIT-DISPOSER until /// Next, repeatedly make split offers to a SPLIT-DISPOSER until
/// either one is accepted, or the contribution from the /// either one is accepted, or the contribution from the
@ -237,14 +251,22 @@ function buyerA() {
/// Make our proposal, and wait for a response. /// Make our proposal, and wait for a response.
react until { react until {
case asserted splitProposal(title, price, contribution, true) { case asserted
console.log("A learns that the split-proposal for "+title+" was accepted"); splitProposal(title, price, contribution, true)
{
console.log("A learns that the split-proposal for "+
title+" was accepted");
buyBooks(); buyBooks();
} }
case asserted splitProposal(title, price, contribution, false) { case asserted
console.log("A learns that the split-proposal for "+title+" was rejected"); splitProposal(title, price, contribution, false)
trySplit(title, price, contribution + ((price - contribution) / 2)); {
console.log("A learns that the split-proposal for "+
title+" was rejected");
trySplit(title,
price,
contribution + ((price - contribution) / 2));
} }
} }
} }
@ -252,7 +274,7 @@ function buyerA() {
} }
} }
/// ## Implementation: SPLIT-DISPOSER and BUYER /// ### Implementation: SPLIT-DISPOSER and BUYER
function buyerB() { function buyerB() {
actor { actor {
@ -266,16 +288,23 @@ function buyerB() {
/// `splitProposal`. /// `splitProposal`.
react { react {
on asserted Syndicate.observe(splitProposal($title, $price, $theirContribution, _)) { on asserted
Syndicate.observe(splitProposal($title,
$price,
$theirContribution,
_))
{
var myContribution = price - theirContribution; var myContribution = price - theirContribution;
console.log("B is being asked to contribute "+myContribution+" toward "+title+ console.log("B is being asked to contribute "+myContribution+
" at price "+price); " toward "+title+" at price "+price);
/// We may not be able to afford contributing this much. /// We may not be able to afford contributing this much.
if (myContribution > this.funds) { if (myContribution > this.funds) {
console.log("B hasn't enough funds ("+this.funds+" remaining)"); console.log("B hasn't enough funds ("+this.funds+
whileRelevantAssert(splitProposal(title, price, theirContribution, false)); " remaining)");
whileRelevantAssert(
splitProposal(title, price, theirContribution, false));
} else { } else {
/// But if we *can* afford it, update our remaining funds and spawn a /// But if we *can* afford it, update our remaining funds and spawn a
@ -283,7 +312,8 @@ function buyerB() {
/// on a split. /// on a split.
var remainingFunds = this.funds - myContribution; var remainingFunds = this.funds - myContribution;
console.log("B accepts the offer, leaving them with "+remainingFunds+" remaining funds"); console.log("B accepts the offer, leaving them with "+
remainingFunds+" remaining funds");
this.funds = remainingFunds; this.funds = remainingFunds;
actor { actor {
@ -292,7 +322,10 @@ function buyerB() {
/// While waiting for order confirmation, take the opportunity to /// While waiting for order confirmation, take the opportunity to
/// signal to our SPLIT-PROPOSER that we accepted their proposal. /// signal to our SPLIT-PROPOSER that we accepted their proposal.
assert splitProposal(title, price, theirContribution, true); assert splitProposal(title,
price,
theirContribution,
true);
/// When order confirmation arrives, this purchase is completed. /// When order confirmation arrives, this purchase is completed.
@ -309,7 +342,7 @@ function buyerB() {
} }
} }
/// ## Starting Configuration /// ### Starting Configuration
ground dataspace { ground dataspace {
seller(); seller();

View File

@ -6,13 +6,15 @@ title: Two-Party Buyer Protocol
var Syndicate = require('../../src/main.js'); var Syndicate = require('../../src/main.js');
--> -->
# {{ page.title }}
This is an extended two-buyer book-purchase protocol, based This is an extended two-buyer book-purchase protocol, based
loosely on an example given in: loosely on an example given in:
> K. Honda, N. Yoshida, and M. Carbone, “Multiparty asynchronous > K. Honda, N. Yoshida, and M. Carbone, “Multiparty asynchronous
> session types,” POPL 2008. > session types,” POPL 2008.
# The Scenario ## The Scenario
A book-seller responds to requests for book prices when asked. A A book-seller responds to requests for book prices when asked. A
pair of prospective buyers run through a shopping list. For each pair of prospective buyers run through a shopping list. For each
@ -22,9 +24,9 @@ otherwise, it rejects the offer, and the first buyer tries a
different split. If the second buyer agrees to a split, it then different split. If the second buyer agrees to a split, it then
negotiates the purchase of the book with the book-seller. negotiates the purchase of the book with the book-seller.
# The Protocol ## The Protocol
## Role: SELLER ### Role: SELLER
- when interest in `bookQuote($title, _)` appears, - when interest in `bookQuote($title, _)` appears,
asserts `bookQuote(title, Maybe Float)`, `false` meaning not available, asserts `bookQuote(title, Maybe Float)`, `false` meaning not available,
@ -33,17 +35,17 @@ negotiates the purchase of the book with the book-seller.
asserts `order(title, offer-price, false, false)` for "no sale", otherwise asserts `order(title, offer-price, false, false)` for "no sale", otherwise
`order(title, offer-price, PositiveInteger, String)`, an accepted sale. `order(title, offer-price, PositiveInteger, String)`, an accepted sale.
## Role: BUYER ### Role: BUYER
- observes `bookQuote(title, $price)` to learn prices. - observes `bookQuote(title, $price)` to learn prices.
- observes `order(title, offer-price, $id, $delivery-date)` to make orders. - observes `order(title, offer-price, $id, $delivery-date)` to make orders.
## Role: SPLIT-PROPOSER ### Role: SPLIT-PROPOSER
- observes `splitProposal(title, asking-price, contribution, $accepted)` - observes `splitProposal(title, asking-price, contribution, $accepted)`
to make a split-proposal and learn whether it was accepted or not. to make a split-proposal and learn whether it was accepted or not.
## Role: SPLIT-DISPOSER ### Role: SPLIT-DISPOSER
- when interest in `splitProposal($title, $asking-price, $contribution, _)` - when interest in `splitProposal($title, $asking-price, $contribution, _)`
appears, asserts `splitProposal(title, askingPrice, contribution, true)` appears, asserts `splitProposal(title, askingPrice, contribution, true)`
@ -52,7 +54,7 @@ negotiates the purchase of the book with the book-seller.
`splitProposal(title, asking-price, contribution, false)` to indicate they `splitProposal(title, asking-price, contribution, false)` to indicate they
are unwilling to go through with the deal. are unwilling to go through with the deal.
# A Sample Run ## A Sample Run
Run the program with `../../bin/syndicatec index.js | node` from a Run the program with `../../bin/syndicatec index.js | node` from a
checkout of the Syndicate repository. checkout of the Syndicate repository.
@ -94,9 +96,9 @@ checkout of the Syndicate repository.
A has bought everything they wanted! A has bought everything they wanted!
The order for The Wind in the Willows has id 10001485, and will be delivered on March 9th The order for The Wind in the Willows has id 10001485, and will be delivered on March 9th
# The Code ## The Code
## Type Declarations ### Type Declarations
First, we declare *assertion types* for our protocol. First, we declare *assertion types* for our protocol.
@ -105,7 +107,7 @@ First, we declare *assertion types* for our protocol.
assertion type splitProposal(title, price, contribution, accepted); assertion type splitProposal(title, price, contribution, accepted);
## Utilities ### Utilities
This routine is under consideration for possible addition to the This routine is under consideration for possible addition to the
core library. core library.
@ -118,7 +120,7 @@ core library.
} }
} }
## Implementation: SELLER ### Implementation: SELLER
function seller() { function seller() {
actor { actor {
@ -134,26 +136,36 @@ tracking the next order ID to be allocated.
}; };
this.nextOrderId = 10001483; this.nextOrderId = 10001483;
Looking up a price yields `false` if no such book is in our
inventory.
this.priceOf = function (title) {
return (title in this.books) && this.books[title];
};
The seller responds to interest in bookQuotes by asserting a The seller responds to interest in bookQuotes by asserting a
responsive record, if one exists. responsive record, if one exists.
react { react {
during Syndicate.observe(bookQuote($title, _)) { during Syndicate.observe(bookQuote($title, _)) {
assert bookQuote(title, title in this.books ? this.books[title] : false); assert bookQuote(title, this.priceOf(title));
} }
} }
It also responds to order requests. It also responds to order requests.
react { react {
on asserted Syndicate.observe(order($title, $offerPrice, _, _)) { on asserted
Syndicate.observe(order($title, $offerPrice, _, _))
{
We cannot sell a book we do not have, and we will not sell for We cannot sell a book we do not have, and we will not sell for
less than our asking price. less than our asking price.
var askingPrice = title in this.books ? this.books[title] : false; var askingPrice = this.priceOf(title);
if ((askingPrice === false) || (offerPrice < askingPrice)) { if ((askingPrice === false) || (offerPrice < askingPrice)) {
whileRelevantAssert(order(title, offerPrice, false, false)); whileRelevantAssert(
order(title, offerPrice, false, false));
} else { } else {
But if we can sell it, we do so by allocating an order ID and But if we can sell it, we do so by allocating an order ID and
@ -163,7 +175,8 @@ replying to the orderer.
delete this.books[title]; delete this.books[title];
actor { actor {
whileRelevantAssert(order(title, offerPrice, orderId, "March 9th")); whileRelevantAssert(
order(title, offerPrice, orderId, "March 9th"));
} }
} }
} }
@ -171,7 +184,7 @@ replying to the orderer.
} }
} }
## Implementation: SPLIT-PROPOSER and book-quote-requestor ### Implementation: SPLIT-PROPOSER and book-quote-requestor
function buyerA() { function buyerA() {
actor { actor {
@ -207,7 +220,8 @@ First, retrieve a quote for the title, and analyze the result.
console.log("A learns that "+title+" is out-of-stock."); console.log("A learns that "+title+" is out-of-stock.");
buyBooks(); buyBooks();
} else { } else {
console.log("A learns that the price of "+title+" is "+price); console.log("A learns that the price of "+title+
" is "+price);
Next, repeatedly make split offers to a SPLIT-DISPOSER until Next, repeatedly make split offers to a SPLIT-DISPOSER until
either one is accepted, or the contribution from the either one is accepted, or the contribution from the
@ -237,14 +251,22 @@ perform the BUYER role here.
Make our proposal, and wait for a response. Make our proposal, and wait for a response.
react until { react until {
case asserted splitProposal(title, price, contribution, true) { case asserted
console.log("A learns that the split-proposal for "+title+" was accepted"); splitProposal(title, price, contribution, true)
{
console.log("A learns that the split-proposal for "+
title+" was accepted");
buyBooks(); buyBooks();
} }
case asserted splitProposal(title, price, contribution, false) { case asserted
console.log("A learns that the split-proposal for "+title+" was rejected"); splitProposal(title, price, contribution, false)
trySplit(title, price, contribution + ((price - contribution) / 2)); {
console.log("A learns that the split-proposal for "+
title+" was rejected");
trySplit(title,
price,
contribution + ((price - contribution) / 2));
} }
} }
} }
@ -252,7 +274,7 @@ Make our proposal, and wait for a response.
} }
} }
## Implementation: SPLIT-DISPOSER and BUYER ### Implementation: SPLIT-DISPOSER and BUYER
function buyerB() { function buyerB() {
actor { actor {
@ -266,16 +288,23 @@ It spends its time waiting for a SPLIT-PROPOSER to offer a
`splitProposal`. `splitProposal`.
react { react {
on asserted Syndicate.observe(splitProposal($title, $price, $theirContribution, _)) { on asserted
Syndicate.observe(splitProposal($title,
$price,
$theirContribution,
_))
{
var myContribution = price - theirContribution; var myContribution = price - theirContribution;
console.log("B is being asked to contribute "+myContribution+" toward "+title+ console.log("B is being asked to contribute "+myContribution+
" at price "+price); " toward "+title+" at price "+price);
We may not be able to afford contributing this much. We may not be able to afford contributing this much.
if (myContribution > this.funds) { if (myContribution > this.funds) {
console.log("B hasn't enough funds ("+this.funds+" remaining)"); console.log("B hasn't enough funds ("+this.funds+
whileRelevantAssert(splitProposal(title, price, theirContribution, false)); " remaining)");
whileRelevantAssert(
splitProposal(title, price, theirContribution, false));
} else { } else {
But if we *can* afford it, update our remaining funds and spawn a But if we *can* afford it, update our remaining funds and spawn a
@ -283,7 +312,8 @@ small actor to handle the actual purchase now that we have agreed
on a split. on a split.
var remainingFunds = this.funds - myContribution; var remainingFunds = this.funds - myContribution;
console.log("B accepts the offer, leaving them with "+remainingFunds+" remaining funds"); console.log("B accepts the offer, leaving them with "+
remainingFunds+" remaining funds");
this.funds = remainingFunds; this.funds = remainingFunds;
actor { actor {
@ -292,7 +322,10 @@ on a split.
While waiting for order confirmation, take the opportunity to While waiting for order confirmation, take the opportunity to
signal to our SPLIT-PROPOSER that we accepted their proposal. signal to our SPLIT-PROPOSER that we accepted their proposal.
assert splitProposal(title, price, theirContribution, true); assert splitProposal(title,
price,
theirContribution,
true);
When order confirmation arrives, this purchase is completed. When order confirmation arrives, this purchase is completed.
@ -309,7 +342,7 @@ When order confirmation arrives, this purchase is completed.
} }
} }
## Starting Configuration ### Starting Configuration
ground dataspace { ground dataspace {
seller(); seller();