This gist explores an example from Grokking Simplicity, a book by Eric Normand.
Last active
December 29, 2020 12:49
-
-
Save kenwebb/6424d56a48695ad96175a20ef48394ed to your computer and use it in GitHub Desktop.
Grokking Simplicity - book by Eric Normand
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
https://livebook.manning.com/book/grokking-simplicity/chapter-3/v-9/ | |
See my Xholon workbook: Grokking Simplicity - book by Eric Normand | |
cd ~/gwtspace/Xholon/workbook/groksimpl/coupondog | |
gcc -o CouponDog.out CouponDog.c | |
./CouponDog.out | |
*/ | |
#include <stdio.h> | |
#include <string.h> | |
#define GOOD "good" | |
#define BEST "best" | |
#define BAD "bad" | |
// function prototypes --------------------------------------------------- | |
void initDbA(); | |
struct subscriber *fetchSubscribersFromDbA(); | |
struct coupon *fetchCouponsFromDbA(); | |
struct coupon *selectCouponsByRankC(struct coupon *coupons, char *rank); | |
struct coupon *selectBestCouponsC(struct coupon *coupons); | |
struct coupon *selectGoodCouponsC(struct coupon *coupons); | |
char *decideCouponRankC(struct subscriber subscriber); | |
struct email planEmailC(struct subscriber subscriber, char *couponRank, struct coupon *coupons); | |
struct email planEmailForSubscriberC(struct subscriber subscriber, struct coupon *goods, struct coupon *bests); | |
struct email *planListOfEmailsC(struct subscriber *subscribers, struct coupon *goods, struct coupon *bests); | |
char *toJSONC(struct email *emails); | |
void sendEmailsA(char *json); | |
// struct definitions ---------------------------------------------------- | |
struct subscriber { | |
char *email; | |
int rec_count; | |
}; | |
struct coupon { | |
char coupon[20]; | |
char rank[5]; | |
}; | |
struct db { | |
struct subscriber *subscribers; | |
struct coupon *coupons; | |
}; | |
struct email { | |
char from[30]; | |
char to[30]; | |
char subject[50]; | |
char body[100]; | |
}; | |
// extern definitions ---------------------------------------------------- | |
struct subscriber subscribers[] = { | |
"john@coldmail.com",2, | |
"sam@pmail.co",16, | |
"linda1989@oal.com",1, | |
"jan1940@ahoy.com",0, | |
"mrbig@pmail.co",25, | |
"lol@lol.lol",0 | |
}; | |
struct coupon coupons[] = { | |
"MAYDISCOUNT",GOOD, | |
"10PERCENT",BAD, | |
"PROMOTION45",BEST, | |
"IHEARTYOU",BAD, | |
"GETADEAL",BEST, | |
"ILIKEDISCOUNTS",GOOD | |
}; | |
struct db dbD; | |
struct coupon rbests[] = {"","", "","", "","", "","", "","", "",""}; | |
struct coupon rgoods[] = {"","", "","", "","", "","", "","", "",""}; | |
struct email email; | |
struct email emails[10]; | |
char json[1000]; | |
// Populate Database ---------------------------------------------------------- | |
void initDbA() { | |
extern struct subscriber subscribers[]; | |
extern struct coupon coupons[]; | |
extern struct db dbD; | |
dbD.subscribers = subscribers; | |
dbD.coupons = coupons; | |
} | |
// Fetch Lists from Database --------------------------------------------------- | |
struct subscriber *fetchSubscribersFromDbA() { | |
extern struct db dbD; | |
return dbD.subscribers; | |
} | |
struct coupon *fetchCouponsFromDbA() { | |
extern struct db dbD; | |
return dbD.coupons; | |
} | |
// Select Coupons -------------------------------------------------------------- | |
struct coupon *selectCouponsByRankC(struct coupon *coupons, char *rank) { | |
extern struct coupon rbests[]; | |
extern struct coupon rgoods[]; | |
int ix = 0; | |
struct coupon *ranked = strcmp(rank, BEST) ? rbests : rgoods; | |
for (int c = 0; c < sizeof(coupons); c++) { | |
strcpy(ranked[c].coupon, ""); | |
strcpy(ranked[c].rank, ""); | |
struct coupon coupon = coupons[c]; | |
if (strcmp(coupon.rank, rank) == 0) { | |
strcpy(ranked[ix].coupon, coupon.coupon); | |
strcpy(ranked[ix].rank, coupon.rank); | |
ix++; | |
} | |
} | |
return ranked; | |
} | |
struct coupon *selectBestCouponsC(struct coupon *coupons) { | |
return selectCouponsByRankC(coupons, BEST); | |
} | |
struct coupon *selectGoodCouponsC(struct coupon *coupons) { | |
return selectCouponsByRankC(coupons, GOOD); | |
} | |
char *decideCouponRankC(struct subscriber subscriber) { | |
if (subscriber.rec_count >= 10) { | |
return BEST; | |
} | |
else { | |
return GOOD; | |
} | |
} | |
// Prepare and Send Emails ----------------------------------------------------- | |
struct email planEmailC(struct subscriber subscriber, char *couponRank, struct coupon *coupons) { | |
extern struct email email; | |
sprintf(email.from, "%s", "newsletter@coupondog.co"); | |
sprintf(email.to, "%s", subscriber.email); | |
sprintf(email.subject, "%s%s%s", "Your ", couponRank, " weekly coupons inside"); | |
char cstr[70]; | |
cstr[0] = '\0'; | |
for (int i = 0; i < sizeof(coupons); i++) { | |
if (coupons[i].coupon[0] != '\0') { | |
strcat(cstr, coupons[i].coupon); | |
strcat(cstr, " "); | |
} | |
} | |
sprintf(email.body, "%s%s%s%s", "Here are the ", couponRank, " coupons: ", cstr); | |
return email; | |
} | |
struct email planEmailForSubscriberC(struct subscriber subscriber, struct coupon *goods, struct coupon *bests) { | |
char *rank = decideCouponRankC(subscriber); | |
if (strcmp(rank, BEST) == '\0') { | |
return planEmailC(subscriber, BEST, bests); | |
} | |
else if (strcmp(rank, GOOD) == '\0') { | |
return planEmailC(subscriber, GOOD, goods); | |
} | |
else { | |
return planEmailC(subscriber, BAD, goods); | |
} | |
} | |
struct email *planListOfEmailsC(struct subscriber *subscribers, struct coupon *goods, struct coupon *bests) { | |
extern struct email emails[]; | |
for (int i = 0; i < sizeof(subscribers); i++) { | |
struct subscriber subscriber = subscribers[i]; | |
struct email email_ = planEmailForSubscriberC(subscriber, goods, bests); | |
emails[i] = email_; | |
} | |
return emails; | |
} | |
char *toJSONC(struct email *emails) { | |
extern char json[]; | |
json[0] = '\0'; | |
strcat(json, "[\n"); | |
for (int i = 0; i < sizeof(emails); i++) { | |
struct email email_ = emails[i]; | |
if (strcmp(email_.to, "(null)") != 0) { // ??? | |
strcat(json, " {"); | |
strcat(json, "\n \"from\": \""); | |
strcat(json, email_.from); | |
strcat(json, "\",\n \"to\": \""); | |
strcat(json, email_.to); | |
strcat(json, "\",\n \"subject\": \""); | |
strcat(json, email_.subject); | |
strcat(json, "\",\n \"body\": \""); | |
strcat(json, email_.body); | |
strcat(json, "\"\n },\n"); | |
} | |
} | |
strcat(json, "]\n"); | |
return json; | |
} | |
void sendEmailsA(char *json) { | |
printf("%s\n", json); | |
} | |
// MAIN ----------------------------------------------------------------- | |
int main() { | |
initDbA(); | |
struct subscriber *listOfSubscribersD = fetchSubscribersFromDbA(); | |
struct coupon *listOfCouponsD = fetchCouponsFromDbA(); | |
struct coupon *bestsD = selectBestCouponsC(listOfCouponsD); | |
struct coupon *goodsD = selectGoodCouponsC(listOfCouponsD); | |
struct email *listOfEmailsD = planListOfEmailsC( | |
listOfSubscribersD, | |
goodsD, | |
bestsD | |
); | |
char *jsonD = toJSONC(listOfEmailsD); | |
sendEmailsA(jsonD); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script><![CDATA[ | |
/* | |
This is an implementation of the CouponDog example app in chapter three of the book: | |
Eric Normand, "Grokking Simplicity: Taming complex software with functional thinking", | |
MEAP began August 2019 Publication in Spring 2021 (estimated), | |
ISBN 9781617296208 325 pages (estimated) | |
https://livebook.manning.com/book/grokking-simplicity/chapter-3/v-9/ | |
This JavaScript implementation is by Ken Webb. | |
December 8, 2020 | |
ken@primordion.com | |
Legend | |
------ | |
As per usage in the Grokking Simplicity book, the name of every const in my JavaScript code, ends in the letter A, C, or D. | |
A Action | |
C Calculation | |
D Data | |
As much as possible, I use the same function and data names as Eric uses in the example in his book. | |
All of the calculation (C) functions are preceeded by a Signature as a JavaScript comment. | |
The signature syntax is based on the Hindley-Milner syntax used in ramdajs (https://ramdajs.com/). | |
My Goal | |
------- | |
I am learning to use Functional Programming (FP) techniques in the latest versions of JavaScript. | |
I've found this to be a good exercise in support of my learning. | |
The following code works using Firefox and Chrome Dev Tools. | |
*/ | |
//clear(); | |
(() => { | |
// constants | |
const BEST = "best" | |
const GOOD = "good" | |
const BAD = "bad" | |
const RANK_CUTOFF = 10 | |
// Populate Database ---------------------------------------------------------- | |
// str2arrC :: String -> String -> [String] | |
const str2arrC = (sep) => (str) => str.split(sep) | |
const str2arrNlC = str2arrC("\n") | |
const str2arrCmC = str2arrC(",") | |
// Email database table | |
// email,rec_count | |
const subscribersRawD = | |
`john@coldmail.com,2 | |
sam@pmail.co,16 | |
linda1989@oal.com,1 | |
jan1940@ahoy.com,0 | |
mrbig@pmail.co,25 | |
lol@lol.lol,0`; | |
// Coupon database table | |
// coupon,rank | |
const couponsRawD = | |
`MAYDISCOUNT,good | |
10PERCENT,bad | |
PROMOTION45,best | |
IHEARTYOU,bad | |
GETADEAL,best | |
ILIKEDISCOUNTS,good` | |
// raw2jsoC :: (String, String, String) -> Object | |
const raw2jsoC = (hdr1, hdr2, raw) => str2arrNlC(raw).map((str) => { | |
const [data1, data2] = str2arrCmC(str) | |
return {[hdr1]: data1, [hdr2]: data2} | |
}) | |
const dbD = {} | |
dbD.subscribers = raw2jsoC("email", "rec_count", subscribersRawD) | |
dbD.coupons = raw2jsoC("coupon", "rank", couponsRawD) | |
// Fetch Lists from Database --------------------------------------------------- | |
// fetchSubscribersFromDbA :: () -> [Object] | |
const fetchSubscribersFromDbA = () => dbD.subscribers | |
const fetchCouponsFromDbA = () => dbD.coupons | |
const listOfSubscribersD = fetchSubscribersFromDbA() | |
const listOfCouponsD = fetchCouponsFromDbA() | |
// Select Coupons -------------------------------------------------------------- | |
// selectCouponsByRankC :: String -> [Object] -> [String] | |
const selectCouponsByRankC = rank => coupons => coupons.reduce((ret, coupon) => | |
(coupon.rank === rank) ? ret.concat([coupon.coupon]) : ret, []) | |
const selectBestCouponsC = selectCouponsByRankC(BEST) | |
const selectGoodCouponsC = selectCouponsByRankC(GOOD) | |
//const selectBadCouponsC = selectCouponsByRankC(BAD) | |
// decideCouponRankC :: Object -> String | |
const decideCouponRankC = (subscriber) => subscriber.rec_count >= RANK_CUTOFF ? BEST : GOOD | |
// Prepare and Send Emails ----------------------------------------------------- | |
// planEmailC :: (Object, String, [String]) -> Object | |
const planEmailC = (subscriber, couponRank, coupons) => ({ | |
from: "newsletter@coupondog.co", | |
to: subscriber.email, | |
subject: `Your ${couponRank} weekly coupons inside`, | |
body: `Here are the ${couponRank} coupons: ` + coupons.join(", ") | |
}) | |
// planEmailForSubscriberC :: (Object, [String], [String]) -> Object | |
const planEmailForSubscriberC = (subscriber, goods, bests) => { | |
switch (decideCouponRankC(subscriber)) { | |
case GOOD: return planEmailC(subscriber, GOOD, goods) | |
case BEST: return planEmailC(subscriber, BEST, bests) | |
default: return {}; | |
} | |
} | |
// planListOfEmailsC :: ([Object], [Object]) -> [Object] | |
const planListOfEmailsC = (subscribers, coupons) => subscribers.map((subscriber) => | |
planEmailForSubscriberC( | |
subscriber, | |
selectGoodCouponsC(coupons), | |
selectBestCouponsC(coupons) | |
) | |
) | |
const listOfEmailsD = planListOfEmailsC(listOfSubscribersD, listOfCouponsD) | |
const sendEmailsA = (emails) => console.log(emails) | |
sendEmailsA(listOfEmailsD) | |
if ($wnd.xh) { | |
$wnd.xh.root().println(JSON.stringify(listOfEmailsD, null, 2)) | |
} | |
})() | |
]]></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.primordion.user.app.groksimpl.ch03; | |
import java.util.ArrayList; | |
import java.util.List; | |
/** | |
* Coupon Dog. | |
* based on: https://gist.github.com/kenwebb/6424d56a48695ad96175a20ef48394ed CouponDog.js | |
* https://www.manning.com/books/grokking-simplicity | |
* @author <a href="mailto:ken@primordion.com">Ken Webb</a> | |
* @see <a href="http://www.primordion.com/Xholon">Xholon Project website</a> | |
* @see <a href="https://gist.github.com/kenwebb/6424d56a48695ad96175a20ef48394ed">Coupon Dog workbook Grokking Simplicity - book by Eric Normand</a> | |
* @since 0.9.1 (Created on December 28, 2020 | |
*/ | |
public class CouponDog { | |
// Populate Database ---------------------------------------------------------- | |
// Email database table | |
// email,rec_count | |
private static final String subscribersRawD = | |
"john@coldmail.com,2\n" + | |
"sam@pmail.co,16\n" + | |
"linda1989@oal.com,1\n" + | |
"jan1940@ahoy.com,0\n" + | |
"mrbig@pmail.co,25\n" + | |
"lol@lol.lol,0"; | |
// Coupon database table | |
// coupon,rank | |
private static final String couponsRawD = | |
"MAYDISCOUNT,good\n" + | |
"10PERCENT,bad\n" + | |
"PROMOTION45,best\n" + | |
"IHEARTYOU,bad\n" + | |
"GETADEAL,best\n" + | |
"ILIKEDISCOUNTS,good"; | |
protected class Subscriber { | |
String email = null; | |
int rec_count = 0; | |
} | |
protected class Coupon { | |
String coupon = null; | |
String rank = null; | |
} | |
protected class Db { | |
List<Subscriber> subscribers = null; | |
List<Coupon> coupons = null; | |
} | |
protected class Email { | |
String from = null; | |
String to = null; | |
String subject = null; | |
String body = null; | |
} | |
private final Db dbD = new Db(); | |
public void act() { | |
dbD.subscribers = raw2listofsubC(subscribersRawD); | |
dbD.coupons = raw2listofcpnC(couponsRawD); | |
List<Subscriber> listOfSubscribersD = fetchSubscribersFromDbA(); | |
List<Coupon> listOfCouponsD = fetchCouponsFromDbA(); | |
List<String> listOfEmailsD = planListOfEmailsC( | |
listOfSubscribersD, | |
selectGoodCouponsC(listOfCouponsD), | |
selectBestCouponsC(listOfCouponsD) | |
); | |
sendEmailsA(listOfEmailsD); | |
} | |
protected List<Subscriber> raw2listofsubC(String raw) { | |
List<Subscriber> list = new ArrayList<Subscriber>(); | |
String[] lines = raw.split("\n"); | |
for (int i = 0; i < lines.length; i++) { | |
String[] arr = lines[i].split(","); | |
String data1 = arr[0]; | |
String data2 = arr[1]; | |
Subscriber sub = new Subscriber(); | |
sub.email = data1; | |
sub.rec_count = Integer.parseInt(data2); | |
list.add(sub); | |
} | |
return list; | |
} | |
protected List<Coupon> raw2listofcpnC(String raw) { | |
List<Coupon> list = new ArrayList<Coupon>(); | |
String[] lines = raw.split("\n"); | |
for (int i = 0; i < lines.length; i++) { | |
String[] arr = lines[i].split(","); | |
String data1 = arr[0]; | |
String data2 = arr[1]; | |
Coupon cpn = new Coupon(); | |
cpn.coupon = data1; | |
cpn.rank = data2; | |
list.add(cpn); | |
} | |
return list; | |
} | |
// Fetch Lists from Database --------------------------------------------------- | |
protected List<Subscriber> fetchSubscribersFromDbA() {return dbD.subscribers;} | |
protected List<Coupon> fetchCouponsFromDbA() {return dbD.coupons;} | |
// Select Coupons -------------------------------------------------------------- | |
protected List<String> selectCouponsByRankC(List<Coupon> coupons, String rank) { | |
List<String> ret = new ArrayList<String>(); | |
for (int c = 0; c < coupons.size(); c++) { | |
Coupon coupon = coupons.get(c); | |
if (rank.equals(coupon.rank)) | |
ret.add(coupon.coupon); | |
} | |
return ret; | |
} | |
protected List<String> selectBestCouponsC(List<Coupon> coupons) { | |
return selectCouponsByRankC(coupons, "best"); | |
} | |
protected List<String> selectGoodCouponsC(List<Coupon> coupons) { | |
return selectCouponsByRankC(coupons, "good"); | |
} | |
protected String decideCouponRankC(Subscriber subscriber) { | |
if (subscriber.rec_count >= 10) { | |
return "best"; | |
} | |
else { | |
return "good"; | |
} | |
} | |
// Prepare and Send Emails ----------------------------------------------------- | |
protected String planEmailC(Subscriber subscriber, String couponRank, List<String> coupons) { | |
return "{\n" | |
+ " from: " + "\"newsletter@coupondog.co\"" + ",\n" | |
+ " to: \"" + subscriber.email + "\",\n" | |
+ " subject: \"" + "Your " + couponRank + " weekly coupons inside" + "\",\n" | |
+ " body: \"" + "Here are the " + couponRank + " coupons: " + String.join(", ", coupons) + "\"\n" | |
+ "}\n"; | |
} | |
protected String planEmailForSubscriberC(Subscriber subscriber, List<String> goods, List<String> bests) { | |
String rank = decideCouponRankC(subscriber); | |
if ("best".equals(rank)) { | |
return planEmailC(subscriber, "good", goods); | |
} | |
else if ("good".equals(rank)) { | |
return planEmailC(subscriber, "best", bests); | |
} | |
else { | |
return null; | |
} | |
} | |
protected List<String> planListOfEmailsC(List<Subscriber> subscribers, List<String> goods, List<String> bests) { | |
List<String> emails = new ArrayList<String>(); | |
for (int s = 0; s < subscribers.size(); s++) { | |
Subscriber subscriber = subscribers.get(s); | |
String email = planEmailForSubscriberC(subscriber, goods, bests); | |
emails.add(email); | |
} | |
return emails; | |
} | |
protected void sendEmailsA(List<String> emails) { | |
consoleLog(emails); | |
System.out.println(emails); | |
} | |
protected native void consoleLog(Object obj) /*-{ | |
$wnd.console.log(obj); | |
}-*/; | |
public static void main(String[] args) { | |
CouponDog couponDog = new CouponDog(); | |
couponDog.act(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script><![CDATA[ | |
/* | |
Traditional JavaScript - more or less directly from the book | |
This is an implementation of the example app in chapter three of the book: | |
Eric Normand, "Grokking Simplicity: Taming complex software with functional thinking", | |
MEAP began August 2019 Publication in Spring 2021 (estimated), | |
ISBN 9781617296208 325 pages (estimated) | |
https://livebook.manning.com/book/grokking-simplicity/chapter-3/v-9/ | |
This JavaScript implementation is by Ken Webb. | |
December 11, 2020 | |
ken@primordion.com | |
Legend | |
------ | |
As per usage in the Grokking Simplicity book, the name of every function or var in my JavaScript code, ends in the letter A, C, or D. | |
A Action | |
C Calculation | |
D Data | |
As much as possible, I use the same function and data names as Eric uses in the example in his book. | |
My Goal | |
------- | |
The following code works using Firefox and Chrome Dev Tools. | |
*/ | |
//clear(); | |
(function() { | |
// Populate Database ---------------------------------------------------------- | |
// Email database table | |
// email,rec_count | |
var subscribersRawD = | |
"john@coldmail.com,2\n" + | |
"sam@pmail.co,16\n" + | |
"linda1989@oal.com,1\n" + | |
"jan1940@ahoy.com,0\n" + | |
"mrbig@pmail.co,25\n" + | |
"lol@lol.lol,0"; | |
// Coupon database table | |
// coupon,rank | |
var couponsRawD = | |
"MAYDISCOUNT,good\n" + | |
"10PERCENT,bad\n" + | |
"PROMOTION45,best\n" + | |
"IHEARTYOU,bad\n" + | |
"GETADEAL,best\n" + | |
"ILIKEDISCOUNTS,good"; | |
function raw2jsoC(hdr1, hdr2, raw) { | |
var jso = []; | |
var lines = raw.split("\n"); | |
for (var i = 0; i < lines.length; i++) { | |
var arr = lines[i].split(","); | |
var data1 = arr[0]; | |
var data2 = arr[1]; | |
jso.push({[hdr1]: data1, [hdr2]: data2}); | |
} | |
return jso; | |
} | |
var dbD = {} | |
dbD.subscribers = raw2jsoC("email", "rec_count", subscribersRawD) | |
dbD.coupons = raw2jsoC("coupon", "rank", couponsRawD) | |
// Fetch Lists from Database --------------------------------------------------- | |
function fetchSubscribersFromDbA() {return dbD.subscribers} | |
function fetchCouponsFromDbA() {return dbD.coupons} | |
var listOfSubscribersD = fetchSubscribersFromDbA() | |
var listOfCouponsD = fetchCouponsFromDbA() | |
// Select Coupons -------------------------------------------------------------- | |
function selectCouponsByRankC(coupons, rank) { | |
var ret = []; | |
for (var c = 0; c < coupons.length; c++) { | |
var coupon = coupons[c]; | |
if (coupon.rank === rank) | |
ret.push(coupon.coupon); | |
} | |
return ret; | |
} | |
function selectBestCouponsC(coupons) { | |
return selectCouponsByRankC(coupons, "best"); | |
} | |
function selectGoodCouponsC(coupons) { | |
return selectCouponsByRankC(coupons, "good"); | |
} | |
function decideCouponRankC(subscriber) { | |
if (subscriber.rec_count >= 10) { | |
return "best"; | |
} | |
else { | |
return "good"; | |
} | |
} | |
// Prepare and Send Emails ----------------------------------------------------- | |
function planEmailC (subscriber, couponRank, coupons) { | |
return { | |
from: "newsletter@coupondog.co", | |
to: subscriber.email, | |
subject: "Your " + couponRank + " weekly coupons inside", | |
body: "Here are the " + couponRank + " coupons: " + coupons.join(", ") | |
} | |
} | |
function planEmailForSubscriberC(subscriber, goods, bests) { | |
var rank = decideCouponRankC(subscriber); | |
if (rank === "best") | |
return planEmailC(subscriber, "good", goods); | |
else if (rank == "good") | |
return planEmailC(subscriber, "best", bests) | |
} | |
function planListOfEmailsC(subscribers, goods, bests) { | |
var emails = []; | |
for (var s = 0; s < subscribers.length; s++) { | |
var subscriber = subscribers[s]; | |
var email = planEmailForSubscriberC(subscriber, goods, bests); | |
emails.push(email); | |
} | |
return emails; | |
} | |
var listOfEmailsD = planListOfEmailsC( | |
listOfSubscribersD, | |
selectGoodCouponsC(listOfCouponsD), | |
selectBestCouponsC(listOfCouponsD) | |
) | |
function sendEmailsA(emails) {console.log(emails)} | |
sendEmailsA(listOfEmailsD) | |
if ($wnd.xh) { | |
$wnd.xh.root().println(JSON.stringify(listOfEmailsD, null, 2)) | |
} | |
})() | |
]]></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script><![CDATA[ | |
/* | |
This is an implementation of the example app in chapter three of the book: | |
Eric Normand, "Grokking Simplicity: Taming complex software with functional thinking", | |
MEAP began August 2019 Publication in Spring 2021 (estimated), | |
ISBN 9781617296208 325 pages (estimated) | |
https://livebook.manning.com/book/grokking-simplicity/chapter-3/v-9/ | |
This JavaScript implementation is by Ken Webb. | |
December 19, 2020 | |
ken@primordion.com | |
This implementation requires Ramda "A practical functional library for JavaScript programmers." | |
https://ramdajs.com/ | |
Legend | |
------ | |
As per usage in the Grokking Simplicity book, the name of every const in my JavaScript code, ends in the letter A, C, or D. | |
A Action | |
C Calculation | |
D Data | |
As much as possible, I use the same function and data names as Eric uses in the example in his book. | |
All of the calculation (C) functions are preceeded by a Signature as a JavaScript comment. | |
The signature syntax is based on the Hindley-Milner syntax used in ramdajs (https://ramdajs.com/). | |
My Goal | |
------- | |
I am learning to use Functional Programming (FP) techniques in the latest versions of JavaScript. | |
I've found this to be a good exercise in support of my learning. | |
The following code works using Firefox and Chrome Dev Tools. | |
*/ | |
//clear(); | |
(() => { | |
// constants | |
const BEST = "best" | |
const GOOD = "good" | |
const BAD = "bad" | |
const RANK_CUTOFF = 10 | |
// str2arrC :: String -> String -> [String] | |
const str2arrC = (sep) => (str) => str.split(sep) | |
const str2arrNlC = str2arrC("\n") | |
const str2arrCmC = str2arrC(",") | |
// arrOfStr2arrOfArrC :: [String] -> [[String]] | |
const arrOfStr2arrOfArrC = arr => arr.map(str => str2arrCmC(str)) | |
// arrOfArr2ArrOfJsoC :: [[String]] -> [Object] | |
const arrOfArr2ArrOfJsoC = (hdr1, hdr2) => arr => arr.map(arr2 => ({[hdr1]: arr2[0], [hdr2]: arr2[1]})) | |
const arrOfJso2StrC = arrOfJso => arrOfJso.map(jso => jso.coupon); | |
// Email database table | |
// email,rec_count | |
const subscribersRawD = | |
`john@coldmail.com,2 | |
sam@pmail.co,16 | |
linda1989@oal.com,1 | |
jan1940@ahoy.com,0 | |
mrbig@pmail.co,25 | |
lol@lol.lol,0` | |
// Coupon database table | |
// coupon,rank | |
const couponsRawD = | |
`MAYDISCOUNT,good | |
10PERCENT,bad | |
PROMOTION45,best | |
IHEARTYOU,bad | |
GETADEAL,best | |
ILIKEDISCOUNTS,good` | |
const trace = label => obj => {console.log(label, obj); return obj;} | |
// raw2jsoC :: (String, String) -> String) -> Object | |
const raw2jsoC = (hdr1, hdr2) => raw => R.compose( | |
//trace("four"), | |
arrOfArr2ArrOfJsoC(hdr1, hdr2), | |
//trace("three"), | |
arrOfStr2arrOfArrC, | |
//trace("two"), | |
str2arrNlC, | |
//trace("one") | |
) | |
// TODO why do I need the extra () in the middle? | |
const dbD = { | |
subscribers: raw2jsoC("email", "rec_count")()(subscribersRawD), | |
coupons: raw2jsoC("coupon", "rank")()(couponsRawD) | |
} | |
const [bestCouponsD, goodCouponsD] = R.compose( | |
R.partition(R.propEq('rank', BEST)), | |
R.filter(R.complement(R.propEq('rank', BAD))) | |
)(dbD.coupons) | |
//console.log(bestCouponsD, goodCouponsD); | |
// Fetch Lists from Database --------------------------------------------------- | |
// fetchSubscribersFromDbA :: () -> [Object] | |
const fetchSubscribersFromDbA = () => dbD.subscribers | |
const fetchCouponsFromDbA = () => dbD.coupons | |
const listOfSubscribersD = fetchSubscribersFromDbA() | |
const listOfCouponsD = fetchCouponsFromDbA() | |
// decideCouponRankC :: Object -> String | |
const decideCouponRankC = (subscriber) => subscriber.rec_count >= RANK_CUTOFF ? BEST : GOOD | |
// Prepare and Send Emails ----------------------------------------------------- | |
// planEmailC :: (Object, String, [String]) -> Object | |
const planEmailC = (subscriber, couponRank, coupons) => ({ | |
from: "newsletter@coupondog.co", | |
to: subscriber.email, | |
subject: `Your ${couponRank} weekly coupons inside`, | |
body: `Here are the ${couponRank} coupons: ` + arrOfJso2StrC(coupons).join(", ") | |
}) | |
// planEmailForSubscriberC :: (Object, [String], [String]) -> Object | |
const planEmailForSubscriberC = (subscriber, goods, bests) => { | |
switch (decideCouponRankC(subscriber)) { | |
case GOOD: return planEmailC(subscriber, GOOD, goods) | |
case BEST: return planEmailC(subscriber, BEST, bests) | |
default: return {}; | |
} | |
} | |
// planListOfEmailsC :: ([Object], [Object]) -> [Object] | |
const planListOfEmailsC = (subscribers, coupons) => subscribers.map((subscriber) => | |
planEmailForSubscriberC( | |
subscriber, | |
goodCouponsD, | |
bestCouponsD | |
) | |
) | |
const listOfEmailsD = planListOfEmailsC(listOfSubscribersD, listOfCouponsD) | |
const sendEmailsA = (emails) => console.log(emails) | |
sendEmailsA(listOfEmailsD) | |
var $wnd = $wnd || window; | |
if ($wnd.xh) { | |
$wnd.xh.root().println(JSON.stringify(listOfEmailsD, null, 2)) | |
} | |
})() | |
]]></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.file "CouponDog.c" | |
.text | |
.globl subscribers | |
.section .rodata | |
.LC0: | |
.string "john@coldmail.com" | |
.LC1: | |
.string "sam@pmail.co" | |
.LC2: | |
.string "linda1989@oal.com" | |
.LC3: | |
.string "jan1940@ahoy.com" | |
.LC4: | |
.string "mrbig@pmail.co" | |
.LC5: | |
.string "lol@lol.lol" | |
.section .data.rel.local,"aw" | |
.align 32 | |
.type subscribers, @object | |
.size subscribers, 96 | |
subscribers: | |
.quad .LC0 | |
.long 2 | |
.zero 4 | |
.quad .LC1 | |
.long 16 | |
.zero 4 | |
.quad .LC2 | |
.long 1 | |
.zero 4 | |
.quad .LC3 | |
.long 0 | |
.zero 4 | |
.quad .LC4 | |
.long 25 | |
.zero 4 | |
.quad .LC5 | |
.long 0 | |
.zero 4 | |
.globl coupons | |
.data | |
.align 32 | |
.type coupons, @object | |
.size coupons, 150 | |
coupons: | |
.string "MAYDISCOUNT" | |
.zero 8 | |
.string "good" | |
.string "10PERCENT" | |
.zero 10 | |
.string "bad" | |
.zero 1 | |
.string "PROMOTION45" | |
.zero 8 | |
.string "best" | |
.string "IHEARTYOU" | |
.zero 10 | |
.string "bad" | |
.zero 1 | |
.string "GETADEAL" | |
.zero 11 | |
.string "best" | |
.string "ILIKEDISCOUNTS" | |
.zero 5 | |
.string "good" | |
.comm dbD,16,16 | |
.globl rbests | |
.bss | |
.align 32 | |
.type rbests, @object | |
.size rbests, 150 | |
rbests: | |
.zero 150 | |
.globl rgoods | |
.align 32 | |
.type rgoods, @object | |
.size rgoods, 150 | |
rgoods: | |
.zero 150 | |
.comm email,210,32 | |
.comm emails,2100,32 | |
.comm json,1000,32 | |
.text | |
.globl initDbA | |
.type initDbA, @function | |
initDbA: | |
.LFB0: | |
.cfi_startproc | |
endbr64 | |
pushq %rbp | |
.cfi_def_cfa_offset 16 | |
.cfi_offset 6, -16 | |
movq %rsp, %rbp | |
.cfi_def_cfa_register 6 | |
leaq subscribers(%rip), %rax | |
movq %rax, dbD(%rip) | |
leaq coupons(%rip), %rax | |
movq %rax, 8+dbD(%rip) | |
nop | |
popq %rbp | |
.cfi_def_cfa 7, 8 | |
ret | |
.cfi_endproc | |
.LFE0: | |
.size initDbA, .-initDbA | |
.globl fetchSubscribersFromDbA | |
.type fetchSubscribersFromDbA, @function | |
fetchSubscribersFromDbA: | |
.LFB1: | |
.cfi_startproc | |
endbr64 | |
pushq %rbp | |
.cfi_def_cfa_offset 16 | |
.cfi_offset 6, -16 | |
movq %rsp, %rbp | |
.cfi_def_cfa_register 6 | |
movq dbD(%rip), %rax | |
popq %rbp | |
.cfi_def_cfa 7, 8 | |
ret | |
.cfi_endproc | |
.LFE1: | |
.size fetchSubscribersFromDbA, .-fetchSubscribersFromDbA | |
.globl fetchCouponsFromDbA | |
.type fetchCouponsFromDbA, @function | |
fetchCouponsFromDbA: | |
.LFB2: | |
.cfi_startproc | |
endbr64 | |
pushq %rbp | |
.cfi_def_cfa_offset 16 | |
.cfi_offset 6, -16 | |
movq %rsp, %rbp | |
.cfi_def_cfa_register 6 | |
movq 8+dbD(%rip), %rax | |
popq %rbp | |
.cfi_def_cfa 7, 8 | |
ret | |
.cfi_endproc | |
.LFE2: | |
.size fetchCouponsFromDbA, .-fetchCouponsFromDbA | |
.section .rodata | |
.LC6: | |
.string "best" | |
.text | |
.globl selectCouponsByRankC | |
.type selectCouponsByRankC, @function | |
selectCouponsByRankC: | |
.LFB3: | |
.cfi_startproc | |
endbr64 | |
pushq %rbp | |
.cfi_def_cfa_offset 16 | |
.cfi_offset 6, -16 | |
movq %rsp, %rbp | |
.cfi_def_cfa_register 6 | |
pushq %rbx | |
subq $88, %rsp | |
.cfi_offset 3, -24 | |
movq %rdi, -88(%rbp) | |
movq %rsi, -96(%rbp) | |
movq %fs:40, %rax | |
movq %rax, -24(%rbp) | |
xorl %eax, %eax | |
movl $0, -80(%rbp) | |
movq -96(%rbp), %rax | |
leaq .LC6(%rip), %rsi | |
movq %rax, %rdi | |
call strcmp@PLT | |
testl %eax, %eax | |
je .L7 | |
leaq rbests(%rip), %rax | |
jmp .L8 | |
.L7: | |
leaq rgoods(%rip), %rax | |
.L8: | |
movq %rax, -72(%rbp) | |
movl $0, -76(%rbp) | |
jmp .L9 | |
.L11: | |
movl -76(%rbp), %eax | |
movslq %eax, %rdx | |
movq %rdx, %rax | |
salq $2, %rax | |
addq %rdx, %rax | |
leaq 0(,%rax,4), %rdx | |
addq %rax, %rdx | |
movq -72(%rbp), %rax | |
addq %rdx, %rax | |
movb $0, (%rax) | |
movl -76(%rbp), %eax | |
movslq %eax, %rdx | |
movq %rdx, %rax | |
salq $2, %rax | |
addq %rdx, %rax | |
leaq 0(,%rax,4), %rdx | |
addq %rax, %rdx | |
movq -72(%rbp), %rax | |
addq %rdx, %rax | |
addq $20, %rax | |
movb $0, (%rax) | |
movl -76(%rbp), %eax | |
movslq %eax, %rdx | |
movq %rdx, %rax | |
salq $2, %rax | |
addq %rdx, %rax | |
leaq 0(,%rax,4), %rdx | |
addq %rax, %rdx | |
movq -88(%rbp), %rax | |
addq %rdx, %rax | |
movq (%rax), %rcx | |
movq 8(%rax), %rbx | |
movq %rcx, -64(%rbp) | |
movq %rbx, -56(%rbp) | |
movq 16(%rax), %rdx | |
movq %rdx, -48(%rbp) | |
movzbl 24(%rax), %eax | |
movb %al, -40(%rbp) | |
movq -96(%rbp), %rax | |
leaq -64(%rbp), %rdx | |
addq $20, %rdx | |
movq %rax, %rsi | |
movq %rdx, %rdi | |
call strcmp@PLT | |
testl %eax, %eax | |
jne .L10 | |
movl -80(%rbp), %eax | |
movslq %eax, %rdx | |
movq %rdx, %rax | |
salq $2, %rax | |
addq %rdx, %rax | |
leaq 0(,%rax,4), %rdx | |
addq %rax, %rdx | |
movq -72(%rbp), %rax | |
addq %rdx, %rax | |
movq %rax, %rdx | |
leaq -64(%rbp), %rax | |
movq %rax, %rsi | |
movq %rdx, %rdi | |
call strcpy@PLT | |
movl -80(%rbp), %eax | |
movslq %eax, %rdx | |
movq %rdx, %rax | |
salq $2, %rax | |
addq %rdx, %rax | |
leaq 0(,%rax,4), %rdx | |
addq %rax, %rdx | |
movq -72(%rbp), %rax | |
addq %rdx, %rax | |
addq $20, %rax | |
leaq -64(%rbp), %rdx | |
addq $20, %rdx | |
movq %rdx, %rsi | |
movq %rax, %rdi | |
call strcpy@PLT | |
addl $1, -80(%rbp) | |
.L10: | |
addl $1, -76(%rbp) | |
.L9: | |
movl -76(%rbp), %eax | |
cmpl $7, %eax | |
jbe .L11 | |
movq -72(%rbp), %rax | |
movq -24(%rbp), %rbx | |
xorq %fs:40, %rbx | |
je .L13 | |
call __stack_chk_fail@PLT | |
.L13: | |
addq $88, %rsp | |
popq %rbx | |
popq %rbp | |
.cfi_def_cfa 7, 8 | |
ret | |
.cfi_endproc | |
.LFE3: | |
.size selectCouponsByRankC, .-selectCouponsByRankC | |
.globl selectBestCouponsC | |
.type selectBestCouponsC, @function | |
selectBestCouponsC: | |
.LFB4: | |
.cfi_startproc | |
endbr64 | |
pushq %rbp | |
.cfi_def_cfa_offset 16 | |
.cfi_offset 6, -16 | |
movq %rsp, %rbp | |
.cfi_def_cfa_register 6 | |
subq $16, %rsp | |
movq %rdi, -8(%rbp) | |
movq -8(%rbp), %rax | |
leaq .LC6(%rip), %rsi | |
movq %rax, %rdi | |
call selectCouponsByRankC | |
leave | |
.cfi_def_cfa 7, 8 | |
ret | |
.cfi_endproc | |
.LFE4: | |
.size selectBestCouponsC, .-selectBestCouponsC | |
.section .rodata | |
.LC7: | |
.string "good" | |
.text | |
.globl selectGoodCouponsC | |
.type selectGoodCouponsC, @function | |
selectGoodCouponsC: | |
.LFB5: | |
.cfi_startproc | |
endbr64 | |
pushq %rbp | |
.cfi_def_cfa_offset 16 | |
.cfi_offset 6, -16 | |
movq %rsp, %rbp | |
.cfi_def_cfa_register 6 | |
subq $16, %rsp | |
movq %rdi, -8(%rbp) | |
movq -8(%rbp), %rax | |
leaq .LC7(%rip), %rsi | |
movq %rax, %rdi | |
call selectCouponsByRankC | |
leave | |
.cfi_def_cfa 7, 8 | |
ret | |
.cfi_endproc | |
.LFE5: | |
.size selectGoodCouponsC, .-selectGoodCouponsC | |
.globl decideCouponRankC | |
.type decideCouponRankC, @function | |
decideCouponRankC: | |
.LFB6: | |
.cfi_startproc | |
endbr64 | |
pushq %rbp | |
.cfi_def_cfa_offset 16 | |
.cfi_offset 6, -16 | |
movq %rsp, %rbp | |
.cfi_def_cfa_register 6 | |
movq %rdi, %rax | |
movq %rsi, %rcx | |
movq %rcx, %rdx | |
movq %rax, -16(%rbp) | |
movq %rdx, -8(%rbp) | |
movl -8(%rbp), %eax | |
cmpl $9, %eax | |
jle .L19 | |
leaq .LC6(%rip), %rax | |
jmp .L20 | |
.L19: | |
leaq .LC7(%rip), %rax | |
.L20: | |
popq %rbp | |
.cfi_def_cfa 7, 8 | |
ret | |
.cfi_endproc | |
.LFE6: | |
.size decideCouponRankC, .-decideCouponRankC | |
.section .rodata | |
.LC8: | |
.string "newsletter@coupondog.co" | |
.LC9: | |
.string "%s" | |
.LC10: | |
.string " weekly coupons inside" | |
.LC11: | |
.string "Your " | |
.LC12: | |
.string "%s%s%s" | |
.LC13: | |
.string " coupons: " | |
.LC14: | |
.string "Here are the " | |
.LC15: | |
.string "%s%s%s%s" | |
.text | |
.globl planEmailC | |
.type planEmailC, @function | |
planEmailC: | |
.LFB7: | |
.cfi_startproc | |
endbr64 | |
pushq %rbp | |
.cfi_def_cfa_offset 16 | |
.cfi_offset 6, -16 | |
movq %rsp, %rbp | |
.cfi_def_cfa_register 6 | |
pushq %rbx | |
subq $152, %rsp | |
.cfi_offset 3, -24 | |
movq %rdi, -120(%rbp) | |
movq %rsi, %rax | |
movq %rdx, %rsi | |
movq %rsi, %rdx | |
movq %rax, -144(%rbp) | |
movq %rdx, -136(%rbp) | |
movq %rcx, -128(%rbp) | |
movq %r8, -152(%rbp) | |
movq %fs:40, %rax | |
movq %rax, -24(%rbp) | |
xorl %eax, %eax | |
leaq .LC8(%rip), %rdx | |
leaq .LC9(%rip), %rsi | |
leaq email(%rip), %rdi | |
movl $0, %eax | |
call sprintf@PLT | |
movq -144(%rbp), %rax | |
movq %rax, %rdx | |
leaq .LC9(%rip), %rsi | |
leaq 30+email(%rip), %rdi | |
movl $0, %eax | |
call sprintf@PLT | |
movq -128(%rbp), %rax | |
leaq .LC10(%rip), %r8 | |
movq %rax, %rcx | |
leaq .LC11(%rip), %rdx | |
leaq .LC12(%rip), %rsi | |
leaq 60+email(%rip), %rdi | |
movl $0, %eax | |
call sprintf@PLT | |
movb $0, -96(%rbp) | |
movl $0, -100(%rbp) | |
jmp .L22 | |
.L24: | |
movl -100(%rbp), %eax | |
movslq %eax, %rdx | |
movq %rdx, %rax | |
salq $2, %rax | |
addq %rdx, %rax | |
leaq 0(,%rax,4), %rdx | |
addq %rax, %rdx | |
movq -152(%rbp), %rax | |
addq %rdx, %rax | |
movzbl (%rax), %eax | |
testb %al, %al | |
je .L23 | |
movl -100(%rbp), %eax | |
movslq %eax, %rdx | |
movq %rdx, %rax | |
salq $2, %rax | |
addq %rdx, %rax | |
leaq 0(,%rax,4), %rdx | |
addq %rax, %rdx | |
movq -152(%rbp), %rax | |
addq %rdx, %rax | |
movq %rax, %rdx | |
leaq -96(%rbp), %rax | |
movq %rdx, %rsi | |
movq %rax, %rdi | |
call strcat@PLT | |
leaq -96(%rbp), %rax | |
movq $-1, %rcx | |
movq %rax, %rdx | |
movl $0, %eax | |
movq %rdx, %rdi | |
repnz scasb | |
movq %rcx, %rax | |
notq %rax | |
leaq -1(%rax), %rdx | |
leaq -96(%rbp), %rax | |
addq %rdx, %rax | |
movw $32, (%rax) | |
.L23: | |
addl $1, -100(%rbp) | |
.L22: | |
movl -100(%rbp), %eax | |
cmpl $7, %eax | |
jbe .L24 | |
leaq -96(%rbp), %rdx | |
movq -128(%rbp), %rax | |
movq %rdx, %r9 | |
leaq .LC13(%rip), %r8 | |
movq %rax, %rcx | |
leaq .LC14(%rip), %rdx | |
leaq .LC15(%rip), %rsi | |
leaq 110+email(%rip), %rdi | |
movl $0, %eax | |
call sprintf@PLT | |
movq -120(%rbp), %rax | |
movq email(%rip), %rcx | |
movq 8+email(%rip), %rbx | |
movq %rcx, (%rax) | |
movq %rbx, 8(%rax) | |
movq 16+email(%rip), %rcx | |
movq 24+email(%rip), %rbx | |
movq %rcx, 16(%rax) | |
movq %rbx, 24(%rax) | |
movq 32+email(%rip), %rcx | |
movq 40+email(%rip), %rbx | |
movq %rcx, 32(%rax) | |
movq %rbx, 40(%rax) | |
movq 48+email(%rip), %rcx | |
movq 56+email(%rip), %rbx | |
movq %rcx, 48(%rax) | |
movq %rbx, 56(%rax) | |
movq 64+email(%rip), %rcx | |
movq 72+email(%rip), %rbx | |
movq %rcx, 64(%rax) | |
movq %rbx, 72(%rax) | |
movq 80+email(%rip), %rcx | |
movq 88+email(%rip), %rbx | |
movq %rcx, 80(%rax) | |
movq %rbx, 88(%rax) | |
movq 96+email(%rip), %rcx | |
movq 104+email(%rip), %rbx | |
movq %rcx, 96(%rax) | |
movq %rbx, 104(%rax) | |
movq 112+email(%rip), %rcx | |
movq 120+email(%rip), %rbx | |
movq %rcx, 112(%rax) | |
movq %rbx, 120(%rax) | |
movq 128+email(%rip), %rcx | |
movq 136+email(%rip), %rbx | |
movq %rcx, 128(%rax) | |
movq %rbx, 136(%rax) | |
movq 144+email(%rip), %rcx | |
movq 152+email(%rip), %rbx | |
movq %rcx, 144(%rax) | |
movq %rbx, 152(%rax) | |
movq 160+email(%rip), %rcx | |
movq 168+email(%rip), %rbx | |
movq %rcx, 160(%rax) | |
movq %rbx, 168(%rax) | |
movq 176+email(%rip), %rcx | |
movq 184+email(%rip), %rbx | |
movq %rcx, 176(%rax) | |
movq %rbx, 184(%rax) | |
movq 192+email(%rip), %rcx | |
movq 200+email(%rip), %rbx | |
movq %rcx, 192(%rax) | |
movq %rbx, 200(%rax) | |
movzwl 208+email(%rip), %edx | |
movw %dx, 208(%rax) | |
movq -24(%rbp), %rax | |
xorq %fs:40, %rax | |
je .L26 | |
call __stack_chk_fail@PLT | |
.L26: | |
movq -120(%rbp), %rax | |
addq $152, %rsp | |
popq %rbx | |
popq %rbp | |
.cfi_def_cfa 7, 8 | |
ret | |
.cfi_endproc | |
.LFE7: | |
.size planEmailC, .-planEmailC | |
.section .rodata | |
.LC16: | |
.string "bad" | |
.text | |
.globl planEmailForSubscriberC | |
.type planEmailForSubscriberC, @function | |
planEmailForSubscriberC: | |
.LFB8: | |
.cfi_startproc | |
endbr64 | |
pushq %rbp | |
.cfi_def_cfa_offset 16 | |
.cfi_offset 6, -16 | |
movq %rsp, %rbp | |
.cfi_def_cfa_register 6 | |
subq $64, %rsp | |
movq %rdi, -24(%rbp) | |
movq %rsi, %rax | |
movq %rdx, %rsi | |
movq %rsi, %rdx | |
movq %rax, -48(%rbp) | |
movq %rdx, -40(%rbp) | |
movq %rcx, -32(%rbp) | |
movq %r8, -56(%rbp) | |
movq %fs:40, %rax | |
movq %rax, -8(%rbp) | |
xorl %eax, %eax | |
movq -48(%rbp), %rdx | |
movq -40(%rbp), %rax | |
movq %rdx, %rdi | |
movq %rax, %rsi | |
call decideCouponRankC | |
movq %rax, -16(%rbp) | |
movq -16(%rbp), %rax | |
leaq .LC6(%rip), %rsi | |
movq %rax, %rdi | |
call strcmp@PLT | |
testl %eax, %eax | |
jne .L28 | |
movq -24(%rbp), %rax | |
movq -56(%rbp), %rcx | |
movq -48(%rbp), %rsi | |
movq -40(%rbp), %rdx | |
movq %rcx, %r8 | |
leaq .LC6(%rip), %rcx | |
movq %rax, %rdi | |
call planEmailC | |
jmp .L27 | |
.L28: | |
movq -16(%rbp), %rax | |
leaq .LC7(%rip), %rsi | |
movq %rax, %rdi | |
call strcmp@PLT | |
testl %eax, %eax | |
jne .L30 | |
movq -24(%rbp), %rax | |
movq -32(%rbp), %rcx | |
movq -48(%rbp), %rsi | |
movq -40(%rbp), %rdx | |
movq %rcx, %r8 | |
leaq .LC7(%rip), %rcx | |
movq %rax, %rdi | |
call planEmailC | |
jmp .L27 | |
.L30: | |
movq -24(%rbp), %rax | |
movq -32(%rbp), %rcx | |
movq -48(%rbp), %rsi | |
movq -40(%rbp), %rdx | |
movq %rcx, %r8 | |
leaq .LC16(%rip), %rcx | |
movq %rax, %rdi | |
call planEmailC | |
.L27: | |
movq -8(%rbp), %rax | |
xorq %fs:40, %rax | |
je .L31 | |
call __stack_chk_fail@PLT | |
.L31: | |
movq -24(%rbp), %rax | |
leave | |
.cfi_def_cfa 7, 8 | |
ret | |
.cfi_endproc | |
.LFE8: | |
.size planEmailForSubscriberC, .-planEmailForSubscriberC | |
.globl planListOfEmailsC | |
.type planListOfEmailsC, @function | |
planListOfEmailsC: | |
.LFB9: | |
.cfi_startproc | |
endbr64 | |
pushq %rbp | |
.cfi_def_cfa_offset 16 | |
.cfi_offset 6, -16 | |
movq %rsp, %rbp | |
.cfi_def_cfa_register 6 | |
pushq %rbx | |
subq $296, %rsp | |
.cfi_offset 3, -24 | |
movq %rdi, -280(%rbp) | |
movq %rsi, -288(%rbp) | |
movq %rdx, -296(%rbp) | |
movq %fs:40, %rax | |
movq %rax, -24(%rbp) | |
xorl %eax, %eax | |
movl $0, -260(%rbp) | |
jmp .L33 | |
.L34: | |
movl -260(%rbp), %eax | |
cltq | |
salq $4, %rax | |
movq %rax, %rdx | |
movq -280(%rbp), %rax | |
addq %rdx, %rax | |
movq 8(%rax), %rdx | |
movq (%rax), %rax | |
movq %rax, -256(%rbp) | |
movq %rdx, -248(%rbp) | |
leaq -240(%rbp), %rax | |
movq -296(%rbp), %rdi | |
movq -288(%rbp), %rcx | |
movq -256(%rbp), %rsi | |
movq -248(%rbp), %rdx | |
movq %rdi, %r8 | |
movq %rax, %rdi | |
call planEmailForSubscriberC | |
movl -260(%rbp), %eax | |
cltq | |
imulq $210, %rax, %rax | |
leaq emails(%rip), %rdx | |
movq -240(%rbp), %rcx | |
movq -232(%rbp), %rbx | |
movq %rcx, (%rax,%rdx) | |
movq %rbx, 8(%rax,%rdx) | |
movq -224(%rbp), %rcx | |
movq -216(%rbp), %rbx | |
movq %rcx, 16(%rax,%rdx) | |
movq %rbx, 24(%rax,%rdx) | |
movq -208(%rbp), %rcx | |
movq -200(%rbp), %rbx | |
movq %rcx, 32(%rax,%rdx) | |
movq %rbx, 40(%rax,%rdx) | |
movq -192(%rbp), %rcx | |
movq -184(%rbp), %rbx | |
movq %rcx, 48(%rax,%rdx) | |
movq %rbx, 56(%rax,%rdx) | |
movq -176(%rbp), %rcx | |
movq -168(%rbp), %rbx | |
movq %rcx, 64(%rax,%rdx) | |
movq %rbx, 72(%rax,%rdx) | |
movq -160(%rbp), %rcx | |
movq -152(%rbp), %rbx | |
movq %rcx, 80(%rax,%rdx) | |
movq %rbx, 88(%rax,%rdx) | |
movq -144(%rbp), %rcx | |
movq -136(%rbp), %rbx | |
movq %rcx, 96(%rax,%rdx) | |
movq %rbx, 104(%rax,%rdx) | |
movq -128(%rbp), %rcx | |
movq -120(%rbp), %rbx | |
movq %rcx, 112(%rax,%rdx) | |
movq %rbx, 120(%rax,%rdx) | |
movq -112(%rbp), %rcx | |
movq -104(%rbp), %rbx | |
movq %rcx, 128(%rax,%rdx) | |
movq %rbx, 136(%rax,%rdx) | |
movq -96(%rbp), %rcx | |
movq -88(%rbp), %rbx | |
movq %rcx, 144(%rax,%rdx) | |
movq %rbx, 152(%rax,%rdx) | |
movq -80(%rbp), %rcx | |
movq -72(%rbp), %rbx | |
movq %rcx, 160(%rax,%rdx) | |
movq %rbx, 168(%rax,%rdx) | |
movq -64(%rbp), %rcx | |
movq -56(%rbp), %rbx | |
movq %rcx, 176(%rax,%rdx) | |
movq %rbx, 184(%rax,%rdx) | |
movq -48(%rbp), %rcx | |
movq -40(%rbp), %rbx | |
movq %rcx, 192(%rax,%rdx) | |
movq %rbx, 200(%rax,%rdx) | |
movzwl -32(%rbp), %ecx | |
movw %cx, 208(%rax,%rdx) | |
addl $1, -260(%rbp) | |
.L33: | |
movl -260(%rbp), %eax | |
cmpl $7, %eax | |
jbe .L34 | |
leaq emails(%rip), %rax | |
movq -24(%rbp), %rbx | |
xorq %fs:40, %rbx | |
je .L36 | |
call __stack_chk_fail@PLT | |
.L36: | |
addq $296, %rsp | |
popq %rbx | |
popq %rbp | |
.cfi_def_cfa 7, 8 | |
ret | |
.cfi_endproc | |
.LFE9: | |
.size planListOfEmailsC, .-planListOfEmailsC | |
.section .rodata | |
.LC17: | |
.string "(null)" | |
.text | |
.globl toJSONC | |
.type toJSONC, @function | |
toJSONC: | |
.LFB10: | |
.cfi_startproc | |
endbr64 | |
pushq %rbp | |
.cfi_def_cfa_offset 16 | |
.cfi_offset 6, -16 | |
movq %rsp, %rbp | |
.cfi_def_cfa_register 6 | |
pushq %rbx | |
subq $264, %rsp | |
.cfi_offset 3, -24 | |
movq %rdi, -264(%rbp) | |
movq %fs:40, %rax | |
movq %rax, -24(%rbp) | |
xorl %eax, %eax | |
movb $0, json(%rip) | |
leaq json(%rip), %rax | |
movq $-1, %rcx | |
movq %rax, %rdx | |
movl $0, %eax | |
movq %rdx, %rdi | |
repnz scasb | |
movq %rcx, %rax | |
notq %rax | |
leaq -1(%rax), %rdx | |
leaq json(%rip), %rax | |
addq %rdx, %rax | |
movw $2651, (%rax) | |
movb $0, 2(%rax) | |
movl $0, -244(%rbp) | |
jmp .L38 | |
.L40: | |
movl -244(%rbp), %eax | |
cltq | |
imulq $210, %rax, %rdx | |
movq -264(%rbp), %rax | |
addq %rdx, %rax | |
movq (%rax), %rcx | |
movq 8(%rax), %rbx | |
movq %rcx, -240(%rbp) | |
movq %rbx, -232(%rbp) | |
movq 16(%rax), %rcx | |
movq 24(%rax), %rbx | |
movq %rcx, -224(%rbp) | |
movq %rbx, -216(%rbp) | |
movq 32(%rax), %rcx | |
movq 40(%rax), %rbx | |
movq %rcx, -208(%rbp) | |
movq %rbx, -200(%rbp) | |
movq 48(%rax), %rcx | |
movq 56(%rax), %rbx | |
movq %rcx, -192(%rbp) | |
movq %rbx, -184(%rbp) | |
movq 64(%rax), %rcx | |
movq 72(%rax), %rbx | |
movq %rcx, -176(%rbp) | |
movq %rbx, -168(%rbp) | |
movq 80(%rax), %rcx | |
movq 88(%rax), %rbx | |
movq %rcx, -160(%rbp) | |
movq %rbx, -152(%rbp) | |
movq 96(%rax), %rcx | |
movq 104(%rax), %rbx | |
movq %rcx, -144(%rbp) | |
movq %rbx, -136(%rbp) | |
movq 112(%rax), %rcx | |
movq 120(%rax), %rbx | |
movq %rcx, -128(%rbp) | |
movq %rbx, -120(%rbp) | |
movq 128(%rax), %rcx | |
movq 136(%rax), %rbx | |
movq %rcx, -112(%rbp) | |
movq %rbx, -104(%rbp) | |
movq 144(%rax), %rcx | |
movq 152(%rax), %rbx | |
movq %rcx, -96(%rbp) | |
movq %rbx, -88(%rbp) | |
movq 160(%rax), %rcx | |
movq 168(%rax), %rbx | |
movq %rcx, -80(%rbp) | |
movq %rbx, -72(%rbp) | |
movq 176(%rax), %rcx | |
movq 184(%rax), %rbx | |
movq %rcx, -64(%rbp) | |
movq %rbx, -56(%rbp) | |
movq 192(%rax), %rcx | |
movq 200(%rax), %rbx | |
movq %rcx, -48(%rbp) | |
movq %rbx, -40(%rbp) | |
movzwl 208(%rax), %eax | |
movw %ax, -32(%rbp) | |
leaq -240(%rbp), %rax | |
addq $30, %rax | |
leaq .LC17(%rip), %rsi | |
movq %rax, %rdi | |
call strcmp@PLT | |
testl %eax, %eax | |
je .L39 | |
leaq json(%rip), %rax | |
movq $-1, %rcx | |
movq %rax, %rdx | |
movl $0, %eax | |
movq %rdx, %rdi | |
repnz scasb | |
movq %rcx, %rax | |
notq %rax | |
leaq -1(%rax), %rdx | |
leaq json(%rip), %rax | |
addq %rdx, %rax | |
movl $8069152, (%rax) | |
leaq json(%rip), %rax | |
movq $-1, %rcx | |
movq %rax, %rdx | |
movl $0, %eax | |
movq %rdx, %rdi | |
repnz scasb | |
movq %rcx, %rax | |
notq %rax | |
leaq -1(%rax), %rdx | |
leaq json(%rip), %rax | |
addq %rdx, %rax | |
movabsq $8243313689321545738, %rbx | |
movq %rbx, (%rax) | |
movl $975334767, 8(%rax) | |
movw $8736, 12(%rax) | |
movb $0, 14(%rax) | |
leaq -240(%rbp), %rax | |
movq %rax, %rsi | |
leaq json(%rip), %rdi | |
call strcat@PLT | |
leaq json(%rip), %rax | |
movq $-1, %rcx | |
movq %rax, %rdx | |
movl $0, %eax | |
movq %rdx, %rdi | |
repnz scasb | |
movq %rcx, %rax | |
notq %rax | |
leaq -1(%rax), %rdx | |
leaq json(%rip), %rax | |
addq %rdx, %rax | |
movabsq $2459000718892870690, %rbx | |
movq %rbx, (%rax) | |
movl $975335284, 8(%rax) | |
movw $8736, 12(%rax) | |
movb $0, 14(%rax) | |
leaq -240(%rbp), %rax | |
addq $30, %rax | |
movq %rax, %rsi | |
leaq json(%rip), %rdi | |
call strcat@PLT | |
leaq json(%rip), %rax | |
movq $-1, %rcx | |
movq %rax, %rdx | |
movl $0, %eax | |
movq %rdx, %rdi | |
repnz scasb | |
movq %rcx, %rax | |
notq %rax | |
leaq -1(%rax), %rdx | |
leaq json(%rip), %rax | |
addq %rdx, %rax | |
movabsq $2459000718892870690, %rbx | |
movabsq $2482718581815670131, %rsi | |
movq %rbx, (%rax) | |
movq %rsi, 8(%rax) | |
movl $2236474, 16(%rax) | |
leaq -240(%rbp), %rax | |
addq $60, %rax | |
movq %rax, %rsi | |
leaq json(%rip), %rdi | |
call strcat@PLT | |
leaq json(%rip), %rax | |
movq $-1, %rcx | |
movq %rax, %rdx | |
movl $0, %eax | |
movq %rdx, %rdi | |
repnz scasb | |
movq %rcx, %rax | |
notq %rax | |
leaq -1(%rax), %rdx | |
leaq json(%rip), %rax | |
addq %rdx, %rax | |
movabsq $2459000718892870690, %rbx | |
movabsq $2459029316284215138, %rsi | |
movq %rbx, (%rax) | |
movq %rsi, 8(%rax) | |
movb $0, 16(%rax) | |
leaq -240(%rbp), %rax | |
addq $110, %rax | |
movq %rax, %rsi | |
leaq json(%rip), %rdi | |
call strcat@PLT | |
leaq json(%rip), %rax | |
movq $-1, %rcx | |
movq %rax, %rdx | |
movl $0, %eax | |
movq %rdx, %rdi | |
repnz scasb | |
movq %rcx, %rax | |
notq %rax | |
leaq -1(%rax), %rdx | |
leaq json(%rip), %rax | |
addq %rdx, %rax | |
movabsq $2863665688611362, %rbx | |
movq %rbx, (%rax) | |
.L39: | |
addl $1, -244(%rbp) | |
.L38: | |
movl -244(%rbp), %eax | |
cmpl $7, %eax | |
jbe .L40 | |
leaq json(%rip), %rax | |
movq $-1, %rcx | |
movq %rax, %rdx | |
movl $0, %eax | |
movq %rdx, %rdi | |
repnz scasb | |
movq %rcx, %rax | |
notq %rax | |
leaq -1(%rax), %rdx | |
leaq json(%rip), %rax | |
addq %rdx, %rax | |
movw $2653, (%rax) | |
movb $0, 2(%rax) | |
leaq json(%rip), %rax | |
movq -24(%rbp), %rsi | |
xorq %fs:40, %rsi | |
je .L42 | |
call __stack_chk_fail@PLT | |
.L42: | |
addq $264, %rsp | |
popq %rbx | |
popq %rbp | |
.cfi_def_cfa 7, 8 | |
ret | |
.cfi_endproc | |
.LFE10: | |
.size toJSONC, .-toJSONC | |
.globl sendEmailsA | |
.type sendEmailsA, @function | |
sendEmailsA: | |
.LFB11: | |
.cfi_startproc | |
endbr64 | |
pushq %rbp | |
.cfi_def_cfa_offset 16 | |
.cfi_offset 6, -16 | |
movq %rsp, %rbp | |
.cfi_def_cfa_register 6 | |
subq $16, %rsp | |
movq %rdi, -8(%rbp) | |
movq -8(%rbp), %rax | |
movq %rax, %rdi | |
call puts@PLT | |
nop | |
leave | |
.cfi_def_cfa 7, 8 | |
ret | |
.cfi_endproc | |
.LFE11: | |
.size sendEmailsA, .-sendEmailsA | |
.globl main | |
.type main, @function | |
main: | |
.LFB12: | |
.cfi_startproc | |
endbr64 | |
pushq %rbp | |
.cfi_def_cfa_offset 16 | |
.cfi_offset 6, -16 | |
movq %rsp, %rbp | |
.cfi_def_cfa_register 6 | |
subq $48, %rsp | |
movl $0, %eax | |
call initDbA | |
movl $0, %eax | |
call fetchSubscribersFromDbA | |
movq %rax, -48(%rbp) | |
movl $0, %eax | |
call fetchCouponsFromDbA | |
movq %rax, -40(%rbp) | |
movq -40(%rbp), %rax | |
movq %rax, %rdi | |
call selectBestCouponsC | |
movq %rax, -32(%rbp) | |
movq -40(%rbp), %rax | |
movq %rax, %rdi | |
call selectGoodCouponsC | |
movq %rax, -24(%rbp) | |
movq -32(%rbp), %rdx | |
movq -24(%rbp), %rcx | |
movq -48(%rbp), %rax | |
movq %rcx, %rsi | |
movq %rax, %rdi | |
call planListOfEmailsC | |
movq %rax, -16(%rbp) | |
movq -16(%rbp), %rax | |
movq %rax, %rdi | |
call toJSONC | |
movq %rax, -8(%rbp) | |
movq -8(%rbp), %rax | |
movq %rax, %rdi | |
call sendEmailsA | |
movl $0, %eax | |
leave | |
.cfi_def_cfa 7, 8 | |
ret | |
.cfi_endproc | |
.LFE12: | |
.size main, .-main | |
.ident "GCC: (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0" | |
.section .note.GNU-stack,"",@progbits | |
.section .note.gnu.property,"a" | |
.align 8 | |
.long 1f - 0f | |
.long 4f - 1f | |
.long 5 | |
0: | |
.string "GNU" | |
1: | |
.align 8 | |
.long 0xc0000002 | |
.long 3f - 2f | |
2: | |
.long 0x3 | |
3: | |
.align 8 | |
4: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<!--Xholon Workbook http://www.primordion.com/Xholon/gwt/ MIT License, Copyright (C) Ken Webb, Mon Dec 21 2020 22:19:41 GMT-0500 (Eastern Standard Time)--> | |
<XholonWorkbook> | |
<Notes><![CDATA[ | |
Xholon | |
------ | |
Title: Grokking Simplicity - book by Eric Normand | |
Description: | |
Url: http://www.primordion.com/Xholon/gwt/ | |
InternalName: 6424d56a48695ad96175a20ef48394ed | |
Keywords: | |
My Notes | |
-------- | |
December 11, 2020 | |
Eric Normand is writing a book on the basics of functional programming (FP). | |
It's programming-language agnostic. | |
All examples use a conservative non-FP version of JavaScript. | |
He claims that programmers who know JavaScript, Java, C, or C# should be able to readally turn the examples into code in their preferred language. | |
In this workbook, I describe my efforts to write executable code in traditional JavaScript, JavaScript ES6, JavaScript Ramdajs, C, and Java. | |
I may also give it a try in Haskell, a new language for me. | |
Specifically, I will implement the CouponDog application, as described in great detail in chapter 3 of the draft of the book [see ref 1 below]. | |
See my .js and other files in: ~/gwtspace/temp/fp/enormand | |
http://127.0.0.1:8080/war/Xholon.html?app=Grokking+Simplicity+-+book+by+Eric+Normand&src=lstr&gui=clsc&jslib=ramda.min | |
MSC | |
--- | |
title Grokking Simplicity - book by Eric Normand | |
# To view sequence diagram, paste this text into http://www.websequencediagrams.com/ | |
# Created by: Xholon http://www.primordion.com/Xholon/ | |
# Date: 1608604745133 Mon Dec 21 21:39:05 GMT-500 2020 | |
two_50->three_51: 1010 | |
two_50->three_51: 1011 | |
two_50->three_51: 1012 | |
two_50->three_51: 1013 | |
two_50->three_51: 1014 | |
two_50->three_51: 1015 | |
two_50->three_51: 1016 | |
two_50->three_51: 1017 | |
two_50->three_51: 1018 | |
two_50->three_51: 1019 | |
two_50->three_51: 10110 | |
two_50->three_51: 10111 | |
two_50->three_51: 10112 | |
two_50->three_51: 10113 | |
two_50->three_51: 10114 | |
two_50->three_51: 10115 | |
two_50->three_51: 10116 | |
two_50->three_51: 10117 | |
two_50->three_51: 10118 | |
two_50->three_51: 10119 | |
three_51->four_52: 102john@coldmail.com,2 | |
two_50->three_51: 10120 | |
four_52->five_53: 103john@coldmail.com,2 | |
two_50->three_51: 10121 | |
two_50->three_51: 10122 | |
two_50->three_51: 10123 | |
two_50->three_51: 10124 | |
References | |
---------- | |
(1) https://livebook.manning.com/book/grokking-simplicity/chapter-3/v-9/ | |
(2) https://gist.github.com/kenwebb/6424d56a48695ad96175a20ef48394ed | |
this Xholon workbook as a gitub gist | |
(3) https://www.primordion.com/Xholon/gwt/Xholon.html?app=6424d56a48695ad96175a20ef48394ed&src=gist&gui=clsc | |
to run the github gist | |
(4) http://127.0.0.1:8080/war/Xholon.html?app=Grokking+Simplicity+-+book+by+Eric+Normand&src=lstr&gui=clsc | |
to run this workbook locally | |
]]></Notes> | |
<_-.XholonClass> | |
<PhysicalSystem/> | |
<CouponDog/> | |
<One/> | |
<Two/> | |
<Three/> | |
<Four/> | |
<Five/> | |
</_-.XholonClass> | |
<xholonClassDetails> | |
</xholonClassDetails> | |
<PhysicalSystem xmlns:xi="http://www.w3.org/2001/XInclude">> | |
<CouponDog> | |
<xi:include href="https://gist.githubusercontent.com/kenwebb/6424d56a48695ad96175a20ef48394ed/raw/e9a36271718ffaa86fd5d9e97a0cde4d63deb1c5/CouponDog.es6.js"/> | |
<xi:include href="https://gist.githubusercontent.com/kenwebb/6424d56a48695ad96175a20ef48394ed/raw/e9a36271718ffaa86fd5d9e97a0cde4d63deb1c5/CouponDog.js"/> | |
<!--<xi:include href="https://gist.githubusercontent.com/kenwebb/6424d56a48695ad96175a20ef48394ed/raw/62bf8fb3edcace2df7e10def9c9f6fdea9481ac1/CouponDog.ramda.js"/>--> | |
<One> | |
<Two/> | |
<Three/> | |
<Four/> | |
<Five/> | |
</One> | |
<InteractionsViewer/> | |
</CouponDog> | |
</PhysicalSystem> | |
<Twobehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[ | |
var me, beh = { | |
postConfigure: function() { | |
me = this.cnode.parent(); | |
//me.println(me.name()); | |
//me.next().msg(101, $wnd.xh.param("TimeStep")); | |
//me.next().msg(102, ); | |
}, | |
act: function() { | |
//me.println(me.name()); | |
me.next().msg(101, $wnd.xh.param("TimeStep"), me); | |
} | |
} | |
//# sourceURL=Twobehavior.js | |
]]></Twobehavior> | |
<Threebehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[ | |
const subscribersRawD = | |
`john@coldmail.com,2 | |
sam@pmail.co,16 | |
linda1989@oal.com,1 | |
jan1940@ahoy.com,0 | |
mrbig@pmail.co,25 | |
lol@lol.lol,0` | |
var me, line, beh = { | |
postConfigure: function() { | |
me = this.cnode.parent(); | |
//me.println(me.name()); | |
line = ""; | |
}, | |
act: function() { | |
//me.println(me.name()); | |
}, | |
processReceivedMessage: function(msg) { | |
//me.println("msg: " + msg.signal + " " + msg.data + " " + Number(msg.data) + " " + typeof msg.data); | |
if (msg.data) { | |
var chr = subscribersRawD.charAt(Number(msg.data)); | |
if (chr == "\n") { | |
me.next().msg(102, line, me); | |
line = ""; | |
} | |
else { | |
line += chr; | |
me.println(line); | |
} | |
} | |
} | |
} | |
//# sourceURL=Threebehavior.js | |
]]></Threebehavior> | |
<Fourbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[ | |
var me, beh = { | |
postConfigure: function() { | |
me = this.cnode.parent(); | |
}, | |
processReceivedMessage: function(msg) { | |
me.println("Four: " + msg.data); | |
me.next().msg(103, msg.data.split(","), me); | |
} | |
} | |
//# sourceURL=Fourbehavior.js | |
]]></Fourbehavior> | |
<Fivebehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[ | |
var me, beh = { | |
postConfigure: function() { | |
me = this.cnode.parent(); | |
}, | |
processReceivedMessage: function(msg) { | |
me.println("Five: " + msg.data[0] + " " + msg.data[1]); | |
} | |
} | |
//# sourceURL=Fivebehavior.js | |
]]></Fivebehavior> | |
<SvgClient><Attribute_String roleName="svgUri"><![CDATA[data:image/svg+xml, | |
<svg width="100" height="50" xmlns="http://www.w3.org/2000/svg"> | |
<g> | |
<title>CouponDog</title> | |
<rect id="PhysicalSystem/CouponDog" fill="#98FB98" height="50" width="50" x="25" y="0"/> | |
</g> | |
</svg> | |
]]></Attribute_String><Attribute_String roleName="setup">${MODELNAME_DEFAULT},${SVGURI_DEFAULT}</Attribute_String></SvgClient> | |
</XholonWorkbook> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment