All of the changes that have been sitting on tildepi for ages. For posterity.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3530 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
parent
d6018736d5
commit
d293637741
@ -16,6 +16,8 @@ Tilde Friends is [routinely](https://www.unprompted.com/projects/build/tildefrie
|
||||
scons uv=path/to/libuv v8=path/to/v8
|
||||
```
|
||||
|
||||
Note for Raspberry Pi: http://www.mccarroll.net/blog/v8_pi2/index.html
|
||||
|
||||
## Running
|
||||
Running the built tildefriends executable will start a web server. This is a good starting point: <http://localhost:12345/>.
|
||||
|
||||
|
34
packages/cory/blink/blink.js
Normal file
34
packages/cory/blink/blink.js
Normal file
@ -0,0 +1,34 @@
|
||||
//! {"require": ["libiframe"]}
|
||||
|
||||
// Server-side blink! Woo!
|
||||
|
||||
require("libiframe").iframe({
|
||||
source: `
|
||||
document.body.style.color = '#fff';
|
||||
document.body.style.backgroundColor = '#000';
|
||||
var canvas = document.createElement("canvas");
|
||||
document.body.append(canvas);
|
||||
canvas.width = 640;
|
||||
canvas.height = 480;
|
||||
var context = canvas.getContext("2d");
|
||||
rpc.export({
|
||||
setFillStyle: function(style) { context.fillStyle = style; },
|
||||
fillRect: context.fillRect.bind(context),
|
||||
fillText: context.fillText.bind(context),
|
||||
});`,
|
||||
style: `
|
||||
border: 0;
|
||||
`}).then(draw).catch(terminal.print);
|
||||
|
||||
var blink = true;
|
||||
|
||||
function draw(iframe) {
|
||||
iframe.setFillStyle('#222');
|
||||
iframe.fillRect(0, 0, 640, 480);
|
||||
if (blink) {
|
||||
iframe.setFillStyle('#fff');
|
||||
iframe.fillText("Hello, world!", 50, 50);
|
||||
}
|
||||
blink = !blink;
|
||||
setTimeout(function() { draw(iframe); }, 500);
|
||||
}
|
@ -286,9 +286,9 @@ function updateUsers() {
|
||||
terminal.cork();
|
||||
terminal.split([
|
||||
{type: "horizontal", children: [
|
||||
{name: "windows", basis: "2in", grow: "0", shrink: "0"},
|
||||
{name: "windows", basis: "1in", grow: "0", shrink: "0"},
|
||||
{name: "terminal", grow: "1"},
|
||||
{name: "users", basis: "2in", grow: "0", shrink: "0"},
|
||||
{name: "users", basis: "1in", grow: "0", shrink: "0"},
|
||||
]},
|
||||
]);
|
||||
updateTitle();
|
||||
@ -444,7 +444,7 @@ function printMessage(message) {
|
||||
{class: "base3", value: from},
|
||||
" ",
|
||||
formatMessage(message.message));
|
||||
} else {
|
||||
} else if (message.message) {
|
||||
terminal.print(
|
||||
{class: "base0", value: niceTime(lastTimestamp, now)},
|
||||
" ",
|
||||
@ -453,6 +453,11 @@ function printMessage(message) {
|
||||
{class: "base00", value: ">"},
|
||||
" ",
|
||||
formatMessage(message.message));
|
||||
} else {
|
||||
terminal.print(
|
||||
{class: "base0", value: niceTime(lastTimestamp, now)},
|
||||
" ",
|
||||
{class: "base3", value: JSON.stringify(message)});
|
||||
}
|
||||
lastTimestamp = now;
|
||||
}
|
||||
|
76
packages/cory/chattest/chattest.js
Normal file
76
packages/cory/chattest/chattest.js
Normal file
@ -0,0 +1,76 @@
|
||||
"use strict";
|
||||
|
||||
//! {
|
||||
//! "chat": {
|
||||
//! "version": 1,
|
||||
//! "settings": [
|
||||
//! {"name": "nickname", "type": "text"},
|
||||
//! {"name": "password", "type": "password"}
|
||||
//! ]
|
||||
//! },
|
||||
//! "category": "libraries"
|
||||
//! }
|
||||
|
||||
let gServices = {};
|
||||
|
||||
class ChatService {
|
||||
constructor(options) {
|
||||
let self = this;
|
||||
self._name = options.name;
|
||||
self._callback = options.callback;
|
||||
setTimeout(function() {
|
||||
self._callback({
|
||||
action: "message",
|
||||
from: "service",
|
||||
to: self._name,
|
||||
message: "Hello, world!",
|
||||
conversation: null,
|
||||
});
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
sendMessage(target, message) {
|
||||
let self = this;
|
||||
setTimeout(function() {
|
||||
self._callback({
|
||||
action: "message",
|
||||
from: target,
|
||||
to: self._name,
|
||||
message: "I saw you say: " + message,
|
||||
conversation: target,
|
||||
});
|
||||
}, 500);
|
||||
return self._callback({
|
||||
action: "message",
|
||||
from: self._name,
|
||||
to: target,
|
||||
message: message,
|
||||
conversation: target,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
core.register("onMessage", function(sender, message) {
|
||||
print(message);
|
||||
let service = gServices[message.name];
|
||||
if (!service) {
|
||||
service = new ChatService(message);
|
||||
gServices[message.name] = service;
|
||||
} else {
|
||||
service._callback = message.callback || service._callback;
|
||||
}
|
||||
|
||||
setTimeout(function() {
|
||||
service._callback({
|
||||
action: "message",
|
||||
from: "service",
|
||||
to: service._name,
|
||||
message: "I got your message.",
|
||||
conversation: null,
|
||||
});
|
||||
}, 500);
|
||||
|
||||
return {
|
||||
sendMessage: service.sendMessage.bind(service),
|
||||
};
|
||||
});
|
198
packages/cory/contest/contest.js
Normal file
198
packages/cory/contest/contest.js
Normal file
@ -0,0 +1,198 @@
|
||||
"use strict";
|
||||
|
||||
//! {"require": ["ui"]}
|
||||
|
||||
terminal.setEcho(false);
|
||||
terminal.setTitle("Programming Contest Test");
|
||||
|
||||
let kProblem = {
|
||||
description: "Write a function foo that returns a number.",
|
||||
tests: [
|
||||
[1, 1],
|
||||
[2, 2],
|
||||
[4, 4],
|
||||
],
|
||||
default: `// Problem 1
|
||||
// ${core.user.name}
|
||||
// ${new Date()}
|
||||
|
||||
function foo() {
|
||||
print("hi cory");
|
||||
return 0;
|
||||
}
|
||||
|
||||
foo();`,
|
||||
};
|
||||
|
||||
function back() {
|
||||
terminal.split([{name: "terminal"}]);
|
||||
if (gEditEvent) {
|
||||
gEditEvent.back();
|
||||
}
|
||||
}
|
||||
|
||||
function runScript(script, input) {
|
||||
var results = {};
|
||||
try {
|
||||
var output = [];
|
||||
function print() {
|
||||
for (var i in arguments) {
|
||||
output.push(arguments[i].toString());
|
||||
}
|
||||
output.push("\n");
|
||||
}
|
||||
results.results = eval(script || "");
|
||||
results.output = output.join("");
|
||||
} catch (error) {
|
||||
results.error = error;
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
function sendResults(document) {
|
||||
var results = runScript(document);
|
||||
var message = `${kProblem.description}
|
||||
|
||||
Return value:
|
||||
${results.results}
|
||||
|
||||
Output:
|
||||
${results.output}
|
||||
|
||||
`;
|
||||
|
||||
if (results.error) {
|
||||
message += `Error:
|
||||
${results.error}`;
|
||||
}
|
||||
|
||||
terminal.postMessageToIframe("iframe", { results: message });
|
||||
}
|
||||
|
||||
function loadScript() {
|
||||
return database.get(core.user.name).then(function(script) {
|
||||
return script || kProblem.default;
|
||||
}).catch(function(error) {
|
||||
return kProblem.default;
|
||||
});
|
||||
}
|
||||
|
||||
core.register("onWindowMessage", function(event) {
|
||||
if (event.message.ready) {
|
||||
loadScript().then(function(script) {
|
||||
terminal.postMessageToIframe("iframe", {contents: script});
|
||||
sendResults(script);
|
||||
});
|
||||
} else if (event.message.contents) {
|
||||
database.set(core.user.name, event.message.contents).then(function() {
|
||||
sendResults(event.message.contents);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//if (!core.user.credentials.permissions || !core.user.credentials.permissions.authenticated) {
|
||||
// terminal.print("Please authenticate.");
|
||||
//} else {
|
||||
showEditor();
|
||||
//}
|
||||
|
||||
function showEditor() {
|
||||
terminal.split([{name: "terminal", type: "vertical"}]);
|
||||
terminal.clear();
|
||||
terminal.print({iframe: `<html>
|
||||
<head>
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/codemirror/5.13.2/codemirror.min.js"></script>
|
||||
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/codemirror/5.13.2/codemirror.min.css"></link>
|
||||
<style>
|
||||
html {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#menu {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
#container {
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
background-color: white;
|
||||
}
|
||||
.CodeMirror {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.CodeMirror-scroll {
|
||||
}
|
||||
#edit { background-color: white }
|
||||
#preview {
|
||||
background-color: #ccc;
|
||||
font-family: monospace;
|
||||
}
|
||||
#edit, #preview {
|
||||
display: flex;
|
||||
overflow: auto;
|
||||
flex: 0 0 50%;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
var gEditor;
|
||||
function index() {
|
||||
parent.postMessage({index: true}, "*");
|
||||
}
|
||||
function submit() {
|
||||
parent.postMessage({
|
||||
contents: gEditor.getValue(),
|
||||
}, "*");
|
||||
}
|
||||
function cursorActivity() {
|
||||
var selection = gEditor.listSelections();
|
||||
var key = "test";
|
||||
var a = selection[0].anchor;
|
||||
var b = selection[0].head;
|
||||
if (b.line < a.line || a.line == b.line && b.ch < a.ch) {
|
||||
[a, b] = [b, a];
|
||||
}
|
||||
parent.postMessage({cursor: {start: a, end: b}}, "*");
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
window.addEventListener("message", function(message) {
|
||||
if (message.data.contents) {
|
||||
gEditor.setValue(message.data.contents);
|
||||
} else if (message.data.results) {
|
||||
preview.innerText = message.data.results;
|
||||
}
|
||||
}, false);
|
||||
|
||||
window.addEventListener("load", function() {
|
||||
gEditor = CodeMirror.fromTextArea(document.getElementById("contents"), {
|
||||
lineNumbers: true
|
||||
});
|
||||
|
||||
parent.postMessage({ready: true}, "*");
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="menu">
|
||||
<input type="button" value="Back" onclick="index()">
|
||||
` + (core.user.credentials.permissions && core.user.credentials.permissions.authenticated ? `
|
||||
<input type="button" value="Save" onclick="submit()">
|
||||
` : "") +
|
||||
` </div>
|
||||
<div id="container">
|
||||
<div id="edit"><textarea id="contents"></textarea></div>
|
||||
<div id="preview"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>`, name: "iframe", style: "flex: 1 1 auto; border: 0; width: 100%"});
|
||||
}
|
269
packages/cory/db/db.js
Normal file
269
packages/cory/db/db.js
Normal file
@ -0,0 +1,269 @@
|
||||
//! {"category": "libraries"}
|
||||
|
||||
class DatabaseList {
|
||||
constructor(name) {
|
||||
this._name = name;
|
||||
}
|
||||
|
||||
_getList() {
|
||||
let self = this;
|
||||
return database.get(this._name).then(function(node) {
|
||||
return JSON.parse(node);
|
||||
}).catch(function(error) {
|
||||
return self._emptyNode();
|
||||
});
|
||||
}
|
||||
|
||||
_randomKey() {
|
||||
let kAlphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
let kBytes = 32;
|
||||
let result = "";
|
||||
for (let i = 0; i < kBytes; i++) {
|
||||
result += kAlphabet.charAt(Math.floor(Math.random() * kAlphabet.length));
|
||||
}
|
||||
return this._name + "_" + result;
|
||||
}
|
||||
|
||||
_emptyNode() {
|
||||
return {next: null, previous: null};
|
||||
}
|
||||
|
||||
_getNode() {
|
||||
var self = this;
|
||||
var key = self._randomKey();
|
||||
return database.get(key).then(function(found) {
|
||||
if (!found) {
|
||||
return key;
|
||||
} else {
|
||||
return self._getNode();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_getRelative(node, next, count) {
|
||||
}
|
||||
|
||||
_insertEnd(item, after) {
|
||||
let self = this;
|
||||
return this._getList().then(function(listNode) {
|
||||
let readPromises = [self._getNode()];
|
||||
readPromises.push(listNode.previous ? database.get(listNode.previous).then(JSON.parse) : null);
|
||||
readPromises.push(listNode.next ? database.get(listNode.next).then(JSON.parse) : null);
|
||||
return Promise.all(readPromises).then(function(results) {
|
||||
let newNodeName = results[0];
|
||||
let previousNode = results[1];
|
||||
let nextNode = results[2];
|
||||
let newNode = self._emptyNode();
|
||||
let oldPrevious = listNode.previous;
|
||||
let oldNext = listNode.next;
|
||||
newNode.value = item;
|
||||
newNode.previous = listNode.previous || newNodeName;
|
||||
newNode.next = listNode.next || newNodeName;
|
||||
if (after) {
|
||||
listNode.previous = newNodeName;
|
||||
listNode.next = listNode.next || newNodeName;
|
||||
} else {
|
||||
listNode.next = newNodeName;
|
||||
listNode.previous = listNode.previous || newNodeName;
|
||||
}
|
||||
let writePromises = [
|
||||
database.set(self._name, JSON.stringify(listNode)),
|
||||
database.set(newNodeName, JSON.stringify(newNode)),
|
||||
];
|
||||
if (oldPrevious && oldPrevious == oldNext) {
|
||||
previousNode.next = newNodeName;
|
||||
previousNode.previous = newNodeName;
|
||||
writePromises.push(database.set(oldPrevious, JSON.stringify(previousNode)));
|
||||
} else {
|
||||
if (previousNode) {
|
||||
previousNode.next = newNodeName;
|
||||
writePromises.push(database.set(oldPrevious, JSON.stringify(previousNode)));
|
||||
}
|
||||
if (nextNode) {
|
||||
nextNode.previous = newNodeName;
|
||||
writePromises.push(database.set(oldNext, JSON.stringify(nextNode)));
|
||||
}
|
||||
}
|
||||
return Promise.all(writePromises);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
_removeEnd(after) {
|
||||
let self = this;
|
||||
return this._getList().then(function(listNode) {
|
||||
if (listNode.next) {
|
||||
if (listNode.next == listNode.previous) {
|
||||
return database.get(listNode.next).then(JSON.parse).then(function(removedNode) {
|
||||
let removedName = listNode.next;
|
||||
listNode.next = null;
|
||||
listNode.previous = null;
|
||||
return Promise.all([
|
||||
database.remove(removedName),
|
||||
database.set(self._name, JSON.stringify(listNode)),
|
||||
]).then(function() {
|
||||
return removedNode.value;
|
||||
});
|
||||
});
|
||||
} else {
|
||||
let name1 = listNode.previous;
|
||||
let name2 = listNode.next;
|
||||
return Promise.all([
|
||||
database.get(listNode.previous),
|
||||
database.get(listNode.next),
|
||||
]).then(function(nodes) {
|
||||
var node1 = JSON.parse(nodes[0]);
|
||||
var node2 = JSON.parse(nodes[1]);
|
||||
if (after) {
|
||||
let name0 = node1.previous;
|
||||
return database.get(name0).then(JSON.parse).then(function(node0) {
|
||||
node0.next = name2;
|
||||
node2.previous = name0;
|
||||
listNode.previous = name0;
|
||||
return Promise.all([
|
||||
database.set(name0, JSON.stringify(node0)),
|
||||
database.remove(name1),
|
||||
database.set(name2, JSON.stringify(node2)),
|
||||
database.set(self._name, JSON.stringify(listNode)),
|
||||
])
|
||||
}).then(function() {
|
||||
return node1.value;
|
||||
});
|
||||
} else {
|
||||
let name3 = node2.next;
|
||||
return database.get(name3).then(JSON.parse).then(function(node3) {
|
||||
node1.next = name3;
|
||||
node3.previous = name1;
|
||||
listNode.next = name3;
|
||||
terminal.print(name1, " ", name2, " ", name3, " ", self._name);
|
||||
terminal.print(JSON.stringify(listNode));
|
||||
return Promise.all([
|
||||
database.set(name1, JSON.stringify(node1)),
|
||||
database.remove(name2),
|
||||
database.set(name3, JSON.stringify(node3)),
|
||||
database.set(self._name, JSON.stringify(listNode)),
|
||||
])
|
||||
}).then(function() {
|
||||
return node2.value;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
push(item) {
|
||||
return this._insertEnd(item, true);
|
||||
}
|
||||
|
||||
pop() {
|
||||
return this._removeEnd(true);
|
||||
}
|
||||
|
||||
shift() {
|
||||
return this._removeEnd(false);
|
||||
}
|
||||
|
||||
unshift(item) {
|
||||
return this._insertEnd(item, false);
|
||||
}
|
||||
|
||||
_sliceInternal(head, count, next, end, result) {
|
||||
let self = this;
|
||||
if (head[next] == end && count > 0) {
|
||||
result.push(head.value);
|
||||
return new Promise(function(resolve, reject) { resolve(result); });
|
||||
} else {
|
||||
if (count > 0) {
|
||||
return database.get(head[next]).then(JSON.parse).then(function(retrieved) {
|
||||
return self._sliceInternal(retrieved, count - 1, next, end, result).then(function(result) {
|
||||
result.push(head.value);
|
||||
return result;
|
||||
});
|
||||
});
|
||||
} else {
|
||||
return new Promise(function(resolve, reject) { resolve(result); });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get(count) {
|
||||
let self = this;
|
||||
return self._getList().then(function(listNode) {
|
||||
if (listNode.next) {
|
||||
return database.get(count > 0 ? listNode.next : listNode.previous).then(JSON.parse).then(function(head) {
|
||||
if (head) {
|
||||
return self._sliceInternal(
|
||||
head,
|
||||
Math.abs(count),
|
||||
count > 0 ? "next" : "previous",
|
||||
count > 0 ? listNode.next : listNode.previous,
|
||||
[]).then(function(result) {
|
||||
result.reverse();
|
||||
return result;
|
||||
});
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function wipeDatabase() {
|
||||
let promises = [];
|
||||
return database.getAll().then(function(list) {
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
promises.push(database.remove(list[i]));
|
||||
}
|
||||
});
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
function dumpDatabase() {
|
||||
return database.getAll().then(function(list) {
|
||||
let promises = [];
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
promises.push(database.get(list[i]));
|
||||
}
|
||||
return Promise.all(promises).then(function(values) {
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
terminal.print(list[i], " ", values[i]);
|
||||
}
|
||||
});
|
||||
}).catch(function(error) {
|
||||
terminal.print(error);
|
||||
});
|
||||
}
|
||||
|
||||
if (imports.terminal) {
|
||||
x = new DatabaseList("list");
|
||||
core.register("onInput", function(input) {
|
||||
if (input == "clear") {
|
||||
wipeDatabase().then(function() {
|
||||
terminal.print("Database is now empty.");
|
||||
});
|
||||
} else if (input.substring(0, "push ".length) == "push ") {
|
||||
x.push(input.substring("push ".length)).then(dumpDatabase).catch(terminal.print);
|
||||
} else if (input.substring(0, "unshift ".length) == "unshift ") {
|
||||
x.unshift(input.substring("unshift ".length)).then(dumpDatabase).catch(terminal.print);
|
||||
} else if (input == "pop") {
|
||||
x.pop().then(function(out) {
|
||||
terminal.print("POPPED: ", out);
|
||||
}).then(dumpDatabase).catch(terminal.print);
|
||||
} else if (input == "shift") {
|
||||
x.shift().then(function(out) {
|
||||
terminal.print("SHIFTED: ", out);
|
||||
}).then(dumpDatabase).catch(terminal.print);
|
||||
} else if (input.substring(0, "get ".length) == "get ") {
|
||||
let parts = input.split(" ");
|
||||
x.get(parseInt(parts[1])).then(function(result) {
|
||||
terminal.print(JSON.stringify(result))
|
||||
}).catch(terminal.print);
|
||||
} else {
|
||||
dumpDatabase();
|
||||
}
|
||||
});
|
||||
}
|
201
packages/cory/emojipush/emojipush.js
Normal file
201
packages/cory/emojipush/emojipush.js
Normal file
@ -0,0 +1,201 @@
|
||||
"use strict";
|
||||
|
||||
class Client {
|
||||
async start() {
|
||||
let self = this;
|
||||
terminal.setTitle("Emoji Push");
|
||||
terminal.setSendKeyEvents(true);
|
||||
self.send({action: "ready"});
|
||||
|
||||
core.register("key", function(event) {
|
||||
if (event.type == "keydown") {
|
||||
switch (event.keyCode) {
|
||||
case 37:
|
||||
self.requestMove(-1, 0);
|
||||
break;
|
||||
case 38:
|
||||
self.requestMove(0, -1);
|
||||
break;
|
||||
case 39:
|
||||
self.requestMove(1, 0);
|
||||
break;
|
||||
case 40:
|
||||
self.requestMove(0, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
core.register("onMessage", function(sender, message) {
|
||||
if (message.action == "display") {
|
||||
terminal.cork();
|
||||
terminal.clear();
|
||||
terminal.print(message.board);
|
||||
terminal.uncork();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async send(message) {
|
||||
(await core.getService("server")).postMessage(message);
|
||||
}
|
||||
|
||||
async requestMove(dx, dy) {
|
||||
await this.send({action: "move", delta: [dx, dy]});
|
||||
}
|
||||
}
|
||||
|
||||
class Server {
|
||||
constructor() {
|
||||
this.rows = 17;
|
||||
this.columns = 17;
|
||||
this.players = {};
|
||||
this.objects = [];
|
||||
|
||||
for (let i = 2; i < this.rows - 1; i += 2) {
|
||||
for (let j = 2; j < this.columns - 1; j += 2) {
|
||||
let block = new Entity();
|
||||
block.position = [j, i];
|
||||
block.symbol = '#';
|
||||
this.objects.push(block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async start() {
|
||||
let self = this;
|
||||
core.register("onMessage", function(sender, message) {
|
||||
if (!self.players[sender.index]) {
|
||||
let player = new Entity();
|
||||
player.symbol = '@';
|
||||
player.position = self.findNewPlayerPosition();
|
||||
self.players[sender.index] = player;
|
||||
self.objects.push(player);
|
||||
}
|
||||
switch (message.action) {
|
||||
case "move":
|
||||
self.move(sender.index, message.delta);
|
||||
self.redisplay();
|
||||
break;
|
||||
case "ready":
|
||||
self.redisplay();
|
||||
break;
|
||||
}
|
||||
});
|
||||
core.register("onSessionEnd", function(session) {
|
||||
let player = self.players[session.index];
|
||||
if (player) {
|
||||
delete self.players[session.index];
|
||||
self.objects.splice(self.objects.indexOf(player), 1);
|
||||
self.redisplay();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
occupied(position) {
|
||||
let board = this.getBoard();
|
||||
|
||||
if (position[0] < 0 || position[1] < 0 || position[1] >= board.length || position[0] >= board[position[1]].length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (board[position[1]].charAt(position[0]) != ' ') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.objects.some(x => position[0] == x.position[0] && position[1] == x.position[1])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
move(index, delta) {
|
||||
let newPosition = [
|
||||
this.players[index].position[0] + delta[0],
|
||||
this.players[index].position[1] + delta[1],
|
||||
];
|
||||
if (!this.occupied(newPosition)) {
|
||||
this.players[index].position = newPosition;
|
||||
}
|
||||
}
|
||||
|
||||
findNewPlayerPosition() {
|
||||
let best = null;
|
||||
let bestDistance = -1;
|
||||
let players = Object.values(this.players);
|
||||
|
||||
for (let i = 0; i < this.rows; i++) {
|
||||
for (let j = 0; j < this.columns; j++) {
|
||||
if (!this.occupied([j, i])) {
|
||||
let distance = Math.min.apply(null, players.map(x => Math.sqrt(
|
||||
(x.position[0] - j) * (x.position[0] - j)
|
||||
+ (x.position[1] - i) * (x.position[1] - i))));
|
||||
if (distance > bestDistance) {
|
||||
best = [j, i];
|
||||
bestDistance = distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
redisplay() {
|
||||
let board;
|
||||
try {
|
||||
board = this.getBoardString();
|
||||
} catch (error) {
|
||||
board = error;
|
||||
}
|
||||
core.broadcast({action: "display", board: board});
|
||||
}
|
||||
|
||||
getBoard() {
|
||||
let board = [];
|
||||
for (let i = 0; i < this.rows; i++) {
|
||||
let row = "";
|
||||
for (let j = 0; j < this.columns; j++) {
|
||||
if (i == 0 && j == 0) {
|
||||
row += '┌';
|
||||
} else if (i == 0 && j == this.columns - 1) {
|
||||
row += '┐';
|
||||
} else if (i == this.rows - 1 && j == 0) {
|
||||
row += '└';
|
||||
} else if (i == this.rows - 1 && j == this.columns - 1) {
|
||||
row += '┘';
|
||||
} else if (i == 0 || i == this.rows - 1) {
|
||||
row += '─';
|
||||
} else if (j == 0 || j == this.columns - 1) {
|
||||
row += '│';
|
||||
} else {
|
||||
row += ' ';
|
||||
}
|
||||
}
|
||||
board.push(row);
|
||||
}
|
||||
for (let object of this.objects) {
|
||||
board[object.position[1]] = board[object.position[1]].slice(0, object.position[0]) + object.symbol + board[object.position[1]].slice(object.position[0] + 1);
|
||||
}
|
||||
return board;
|
||||
}
|
||||
|
||||
getBoardString() {
|
||||
let board = this.getBoard();
|
||||
let colors = board.map(x => x.split("").map(y => '#fff'));
|
||||
return board.map((r, row) => r.split("").map((v, column) => ({style: "color: " + colors[row][column], value: v})).concat(["\n"]));
|
||||
}
|
||||
}
|
||||
|
||||
class Entity {
|
||||
constructor() {
|
||||
this.position = [0, 0];
|
||||
this.symbol = '?';
|
||||
this.color = '#fff';
|
||||
}
|
||||
}
|
||||
|
||||
if (imports.terminal) {
|
||||
new Client().start().catch(terminal.print);
|
||||
} else {
|
||||
new Server().start().catch(print);
|
||||
}
|
31
packages/cory/guess/guess.js
Normal file
31
packages/cory/guess/guess.js
Normal file
@ -0,0 +1,31 @@
|
||||
"use strict";
|
||||
|
||||
//! {"category": "sample"}
|
||||
|
||||
async function main() {
|
||||
terminal.print("Hi. What's your name?");
|
||||
let name = await terminal.readLine();
|
||||
terminal.print("Hello, " + name + ".");
|
||||
|
||||
let number = Math.floor(Math.random() * 100);
|
||||
let guesses = 0;
|
||||
while (true) {
|
||||
terminal.print("Guess the number.");
|
||||
try {
|
||||
let guess = parseInt(await terminal.readLine());
|
||||
guesses++;
|
||||
if (guess < number) {
|
||||
terminal.print("Too low.");
|
||||
} else if (guess > number) {
|
||||
terminal.print("Too high.");
|
||||
} else {
|
||||
terminal.print("You got it in " + guesses.toString() + " guesses! It was " + number.toString() + ". Good job, " + name + ".");
|
||||
break;
|
||||
}
|
||||
} catch (error) {
|
||||
terminal.print(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(terminal.print);
|
3
packages/cory/images/images.js
Normal file
3
packages/cory/images/images.js
Normal file
@ -0,0 +1,3 @@
|
||||
core.register("fileDrop", function(event) {
|
||||
terminal.print({image: event.file});
|
||||
});
|
260
packages/cory/invite/invite.js
Normal file
260
packages/cory/invite/invite.js
Normal file
@ -0,0 +1,260 @@
|
||||
"use strict";
|
||||
|
||||
terminal.setEcho(false);
|
||||
terminal.setPrompt("🍔");
|
||||
|
||||
terminal.split([
|
||||
{
|
||||
type: "horizontal",
|
||||
children: [
|
||||
{
|
||||
name: "form",
|
||||
},
|
||||
{
|
||||
type: "vertical",
|
||||
basis: "240px",
|
||||
grow: "0",
|
||||
shrink: "0",
|
||||
children: [
|
||||
{
|
||||
name: "image",
|
||||
basis: "8em",
|
||||
shrink: "0",
|
||||
},
|
||||
{
|
||||
name: "fizzbuzz",
|
||||
grow: "1",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
database.getAll().then(function(data) {
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
database.remove(data[i]);
|
||||
}
|
||||
});
|
||||
|
||||
let kBurger = ` ......
|
||||
/'.'.'.\\
|
||||
&%@%@%@&
|
||||
(######)
|
||||
\\,,,,,,/`;
|
||||
|
||||
terminal.select("image");
|
||||
terminal.print(kBurger);
|
||||
terminal.select("form");
|
||||
|
||||
function countUp() {
|
||||
var current = 0;
|
||||
function countUpNext() {
|
||||
terminal.select("fizzbuzz");
|
||||
++current;
|
||||
var result = "";
|
||||
if (current % 3 == 0) {
|
||||
result += "Fizz";
|
||||
}
|
||||
if (current % 5 == 0) {
|
||||
result += "Buzz";
|
||||
}
|
||||
if (current % 150 == 0) {
|
||||
result += "Grumble";
|
||||
}
|
||||
if (result == "") {
|
||||
result = current.toString();
|
||||
}
|
||||
terminal.print(result);
|
||||
terminal.select("form");
|
||||
setTimeout(countUpNext, 1000);
|
||||
};
|
||||
setTimeout(countUpNext, 1000);
|
||||
}
|
||||
countUp();
|
||||
|
||||
var user = core.user.name;
|
||||
|
||||
let kIntroduction = [
|
||||
{style: "font-size: xx-large; font-family: sans", value: "Summer of Cory"},
|
||||
"Hi, it is warm outside again, and as is tradition, I want you to join me "+
|
||||
"after work for some burgers on my deck. There are some quick questions "+
|
||||
"below to gauge interest and availability. Please answer as best you can "+
|
||||
"by clicking the options below, and I will get back to you with a plan.",
|
||||
[],
|
||||
];
|
||||
|
||||
let kBottom = [
|
||||
{
|
||||
iframe: `<html style="width: 100%; height: 100%; margin: 0; padding: 0">
|
||||
<body style="width: 100%; height: 100%; margin: 0; padding: 0">
|
||||
<textarea id="text" style="left: 0; top: 0; width: 100vw; height: 100vh; resize: none; margin: 0; padding: 0"></textarea>
|
||||
</body>
|
||||
</html>
|
||||
`,
|
||||
style: "border: 0; width: 640px; height: 240px; margin: 0; padding: 0",
|
||||
},
|
||||
];
|
||||
|
||||
let kQuestions = [
|
||||
{text: "Do you want to be a part of the Summer of Cory?", options: ["yes", "no"]},
|
||||
{text: "Tuesday after work works best for me. Does that work for you?", options: ["yes", "no"]},
|
||||
{text: "How often would you expect to join us?", options: ["weekly", "fortnightly", "monthly", "impossible to predict"]},
|
||||
|
||||
//{text: "Pick numbers", options: ["1", "2", "3"], allowMultiple: true},
|
||||
//{text: "Pick a letter", options: ["a", "b", "c", "d"]},
|
||||
//{text: "Pick whatever", options: ["1", "2", "3", "a", "b", "c", "d"], writeIn: true},
|
||||
];
|
||||
|
||||
let choices = [];
|
||||
let writeIn = [];
|
||||
let writingIn = undefined;
|
||||
|
||||
function getOptions(index) {
|
||||
return kQuestions[index].options.concat(writeIn[index] || []);
|
||||
}
|
||||
|
||||
function isChosen(question, choice) {
|
||||
let selected = false;
|
||||
if (kQuestions[question].allowMultiple) {
|
||||
selected = choices[question] && choices[question].indexOf(choice) != -1;
|
||||
} else {
|
||||
selected = choices[question] == choice;
|
||||
}
|
||||
return selected;
|
||||
}
|
||||
|
||||
function readData() {
|
||||
return database.getAll().then(function(keys) {
|
||||
var promises = [];
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
promises.push(database.get(keys[i]));
|
||||
}
|
||||
return Promise.all(promises);
|
||||
}).then(function(allData) {
|
||||
writeIn = [];
|
||||
for (var i = 0; i < allData.length; i++) {
|
||||
if (allData[i]) {
|
||||
var entry = JSON.parse(allData[i]);
|
||||
if (entry && entry.writeIn) {
|
||||
for (var j = 0; j < entry.writeIn.length; j++) {
|
||||
if (writeIn.indexOf(entry.writeIn[j]) == -1) {
|
||||
writeIn.push(entry.writeIn[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return database.get("data_" + user);
|
||||
}).then(function(data) {
|
||||
if (data) {
|
||||
choices = JSON.parse(data).choices;
|
||||
}
|
||||
}).catch(function(error) {
|
||||
terminal.select("image");
|
||||
terminal.print(error);
|
||||
terminal.select("form");
|
||||
});
|
||||
}
|
||||
|
||||
function writeData() {
|
||||
return database.set("data_" + user, JSON.stringify({choices: choices, writeIn: writeIn})).catch(function(error) {
|
||||
terminal.select("image");
|
||||
terminal.print(error);
|
||||
terminal.select("form");
|
||||
});
|
||||
}
|
||||
|
||||
function render() {
|
||||
return readData().then(function() {
|
||||
terminal.cork();
|
||||
try {
|
||||
terminal.clear();
|
||||
for (let line in kIntroduction) {
|
||||
terminal.print(kIntroduction[line]);
|
||||
}
|
||||
let allowFill = writingIn === undefined;
|
||||
for (let i in kQuestions) {
|
||||
let availableOptions = getOptions(i);
|
||||
let options = [];
|
||||
for (let j in availableOptions) {
|
||||
options.push(" ");
|
||||
|
||||
let value = (isChosen(i, availableOptions[j]) ? "☒" : "☐") + availableOptions[j];
|
||||
if (allowFill) {
|
||||
options.push({
|
||||
command: JSON.stringify({action: "toggle", question: i, option: availableOptions[j]}),
|
||||
value: value,
|
||||
});
|
||||
} else {
|
||||
options.push(value);
|
||||
}
|
||||
}
|
||||
if (kQuestions[i].writeIn) {
|
||||
options.push(" or ");
|
||||
if (writingIn !== undefined) {
|
||||
options.push("write in another option below")
|
||||
options.push(" ");
|
||||
options.push({command: JSON.stringify({action: "endWriteIn"}), value: "cancel"});
|
||||
} else {
|
||||
options.push({command: JSON.stringify({action: "beginWriteIn", question: i}), value: "write in another option"});
|
||||
}
|
||||
}
|
||||
terminal.print(kQuestions[i].text, ":", options);
|
||||
terminal.print();
|
||||
}
|
||||
} finally {
|
||||
for (let line in kBottom) {
|
||||
terminal.print(kBottom[line]);
|
||||
}
|
||||
terminal.uncork();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
core.register("onInput", function(input) {
|
||||
if (writingIn !== undefined && input != "cancel") {
|
||||
readData().then(function() {
|
||||
if (!writeIn[writingIn]) {
|
||||
writeIn[writingIn] = [];
|
||||
}
|
||||
if (input && writeIn[writingIn].indexOf(input) == -1) {
|
||||
writeIn[writingIn].push(input);
|
||||
}
|
||||
writingIn = undefined;
|
||||
terminal.setPrompt("> ");
|
||||
return writeData();
|
||||
}).then(render);
|
||||
} else {
|
||||
let command = JSON.parse(input);
|
||||
if (command.action == "toggle") {
|
||||
readData().then(function() {
|
||||
if (kQuestions[command.question].allowMultiple) {
|
||||
if (choices[command.question] && choices[command.question].indexOf(command.option) != -1) {
|
||||
choices[command.question].splice(choices[command.question].indexOf(command.option), 1);
|
||||
} else {
|
||||
if (!choices[command.question]) {
|
||||
choices[command.question] = [];
|
||||
}
|
||||
choices[command.question].push(command.option);
|
||||
}
|
||||
} else {
|
||||
choices[command.question] = command.option;
|
||||
}
|
||||
return writeData();
|
||||
}).then(render);
|
||||
} else if (command.action == "beginWriteIn") {
|
||||
writingIn = command.question;
|
||||
terminal.setPrompt('Enter new option for "' + kQuestions[command.question].text + '": ');
|
||||
render();
|
||||
} else if (command.action == "endWriteIn") {
|
||||
writingIn = undefined;
|
||||
terminal.setPrompt("> ");
|
||||
render();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
render().catch(function(error) {
|
||||
terminal.print(error);
|
||||
});
|
179
packages/cory/invite2/invite2.js
Normal file
179
packages/cory/invite2/invite2.js
Normal file
@ -0,0 +1,179 @@
|
||||
"use strict";
|
||||
|
||||
//! {"require": ["smtp"], "permissions": ["network"]}
|
||||
|
||||
let administrator = core.user.name == core.user.packageOwner;
|
||||
|
||||
function lameHash(value) {
|
||||
let result = 12945;
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
result += value.charCodeAt(i);
|
||||
result *= 31;
|
||||
result &= 0x7fffffff;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
terminal.setEcho(false);
|
||||
if (administrator) {
|
||||
terminal.print({style: "font-size: x-large", value: "Edit", command: "command:" + JSON.stringify("command")});
|
||||
}
|
||||
|
||||
let gInvite = null;
|
||||
|
||||
function display() {
|
||||
return database.get("invite").then(function(data) {
|
||||
if (data) {
|
||||
let invite = JSON.parse(data);
|
||||
let promises = [];
|
||||
for (let i in invite.emails) {
|
||||
promises.push(database.get("rsvp." + lameHash(invite.emails[i])));
|
||||
}
|
||||
return Promise.all(promises).then(function(rsvps) {
|
||||
for (let i in rsvps) {
|
||||
if (rsvps[i]) {
|
||||
rsvps[i] = JSON.parse(rsvps[i]);
|
||||
}
|
||||
}
|
||||
terminal.print({style: "font-size: xx-large", value: invite.title});
|
||||
terminal.print(invite.message);
|
||||
for (let i in invite.food) {
|
||||
let line = [invite.food[i], "?", " ", "+", " ", "-"];
|
||||
// hi
|
||||
terminal.print({style: "font-size: x-large", value: line});
|
||||
}
|
||||
gInvite = invite;
|
||||
});
|
||||
}
|
||||
}).catch(function(error) {
|
||||
terminal.print(error);
|
||||
});
|
||||
}
|
||||
|
||||
core.register("hashChange", function(event) {
|
||||
let hash = event.hash;
|
||||
if (hash && hash.charAt(0) == '#') {
|
||||
hash = hash.substring(1);
|
||||
}
|
||||
if (hash) {
|
||||
let invite = gInvite || {};
|
||||
for (let i in invite.emails) {
|
||||
let email = invite.emails[i];
|
||||
if (lameHash(email).toString() == hash) {
|
||||
terminal.print("hash match!", email);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
core.register("submit", function(event) {
|
||||
let invite = event.value;
|
||||
invite.emails = invite.emails.split(",");
|
||||
invite.food = invite.food.split(",");
|
||||
for (let i in invite.emails) {
|
||||
let url = "https://www.tildefriends.net/~cory/invite2#" + lameHash(invite.emails[i]).toString();
|
||||
terminal.print({href: url});
|
||||
}
|
||||
database.set("invite", JSON.stringify(invite));
|
||||
});
|
||||
|
||||
display();
|
||||
|
||||
core.register("onInput", function(input) {
|
||||
if (input.substring(0, "command:".length) == "command:") {
|
||||
command = JSON.parse(input.substring("command:".length));
|
||||
if (command == "create") {
|
||||
let invite = gInvite || {};
|
||||
terminal.print("Title:", {input: "text", name: "title", style: "width: 512px", value: invite.title});
|
||||
terminal.print("Message:", {input: "text", name: "message", style: "width: 512px", value: invite.message});
|
||||
terminal.print("Email Addresses:", {input: "text", name: "emails", style: "width: 512px", value: invite.emails.join(",")});
|
||||
terminal.print("Food:", {input: "text", name: "food", style: "width: 512px", value: invite.food.join(",")});
|
||||
terminal.print({input: "submit", name: "Create", value: "Create"});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
require("smtp").sendMail({
|
||||
from: core.user.name + "@unprompted.com",
|
||||
to: "test1@unprompted.com",
|
||||
subject: input,
|
||||
body: input,
|
||||
}).then(function() {
|
||||
terminal.print("sent");
|
||||
}).catch(function(error) {
|
||||
terminal.print("error: ", error);
|
||||
});
|
||||
*/
|
||||
|
||||
let kEmojis = [
|
||||
"🍇 Grapes",
|
||||
"🍈 Melon",
|
||||
"🍉 Watermelon",
|
||||
"🍊 Tangerine",
|
||||
"🍋 Lemon",
|
||||
"🍌 Banana",
|
||||
"🍍 Pineapple",
|
||||
"🍎 Red Apple",
|
||||
"🍏 Green Apple",
|
||||
"🍐 Pear",
|
||||
"🍑 Peach",
|
||||
"🍒 Cherries",
|
||||
"🍓 Strawberry",
|
||||
"🍅 Tomato",
|
||||
"🍆 Aubergine",
|
||||
"🌽 Ear of Maize",
|
||||
"🌶 Hot Pepper",
|
||||
"🍄 Mushroom",
|
||||
"🌰 Chestnut",
|
||||
"🍞 Bread",
|
||||
"🧀 Cheese Wedge",
|
||||
"🍖 Meat on Bone",
|
||||
"🍗 Poultry Leg",
|
||||
"🍔 Hamburger",
|
||||
"🍟 French Fries",
|
||||
"🍕 Slice of Pizza",
|
||||
"🌭 Hot Dog",
|
||||
"🌮 Taco",
|
||||
"🌯 Burrito",
|
||||
"🍳 Cooking",
|
||||
"🍲 Pot of Food",
|
||||
"🍿 Popcorn",
|
||||
"🍱 Bento Box",
|
||||
"🍘 Rice Cracker",
|
||||
"🍙 Rice Ball",
|
||||
"🍚 Cooked Rice",
|
||||
"🍛 Curry and Rice",
|
||||
"🍜 Steaming Bowl",
|
||||
"🍝 Spaghetti",
|
||||
"🍠 Roasted Sweet Potato",
|
||||
"🍢 Oden",
|
||||
"🍣 Sushi",
|
||||
"🍤 Fried Shrimp",
|
||||
"🍥 Fish Cake With Swirl Design",
|
||||
"🍡 Dango",
|
||||
"🍦 Soft Ice Cream",
|
||||
"🍧 Shaved Ice",
|
||||
"🍨 Ice Cream",
|
||||
"🍩 Doughnut",
|
||||
"🍪 Cookie",
|
||||
"🎂 Birthday Cake",
|
||||
"🍰 Shortcake",
|
||||
"🍫 Chocolate Bar",
|
||||
"🍬 Candy",
|
||||
"🍭 Lollipop",
|
||||
"🍮 Custard",
|
||||
"🍯 Honey Pot",
|
||||
"🍼 Baby Bottle",
|
||||
"☕ Hot Beverage",
|
||||
"🍵 Teacup Without Handle",
|
||||
"🍶 Sake Bottle and Cup",
|
||||
"🍾 Bottle With Popping Cork",
|
||||
"🍷 Wine Glass",
|
||||
"🍸 Cocktail Glass",
|
||||
"🍹 Tropical Drink",
|
||||
"🍺 Beer Mug",
|
||||
"🍻 Clinking Beer Mugs",
|
||||
"🍽 Fork and Knife With Plate",
|
||||
"🍴 Fork and Knife",
|
||||
];
|
936
packages/cory/ldjam34/ldjam34.js
Normal file
936
packages/cory/ldjam34/ldjam34.js
Normal file
@ -0,0 +1,936 @@
|
||||
imports.terminal.print({iframe: `
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>become a game developer in 60 seconds</title>
|
||||
<script language="javascript">
|
||||
"use strict";
|
||||
|
||||
function ImageEditor() {
|
||||
this.kWidth = 256;
|
||||
this.kHeight = 256;
|
||||
this.kTop = 30;
|
||||
this.kLeft = 640 / 2 - this.kWidth / 2;
|
||||
this.kSpriteSize = 8;
|
||||
this.image = new Array(this.kSpriteSize * this.kSpriteSize);
|
||||
for (var i = 0; i < this.kSpriteSize * this.kSpriteSize; i++) {
|
||||
this.image[i] = 0;
|
||||
}
|
||||
this.pixelsFilled = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
ImageEditor.prototype.update = function() {
|
||||
if (this.title) {
|
||||
var fontSize = 16;
|
||||
gContext.font = 'bold ' + fontSize + 'px courier new';
|
||||
gContext.fillStyle = '#fff';
|
||||
gContext.fillText(this.title, 640 / 2 - gContext.measureText(this.title).width / 2, fontSize);
|
||||
}
|
||||
for (var i = 0; i < this.kSpriteSize; i++) {
|
||||
for (var j = 0; j < this.kSpriteSize; j++) {
|
||||
var p = j * this.kSpriteSize + i;
|
||||
if (this.pixelsFilled > p) {
|
||||
gContext.fillStyle = this.image[p] ? '#fff' : '#000';
|
||||
gContext.fillRect(
|
||||
this.kLeft + (i * this.kWidth / this.kSpriteSize),
|
||||
this.kTop + (j * this.kHeight / this.kSpriteSize),
|
||||
this.kWidth / this.kSpriteSize,
|
||||
this.kHeight / this.kSpriteSize);
|
||||
} else if (this.pixelsFilled == p) {
|
||||
gContext.fillStyle = pulseColor();
|
||||
gContext.fillRect(
|
||||
this.kLeft + (i * this.kWidth / this.kSpriteSize),
|
||||
this.kTop + (j * this.kHeight / this.kSpriteSize),
|
||||
this.kWidth / this.kSpriteSize,
|
||||
this.kHeight / this.kSpriteSize);
|
||||
} else {
|
||||
gContext.strokeStyle = '#fff';
|
||||
gContext.strokeRect(
|
||||
this.kLeft + (i * this.kWidth / this.kSpriteSize),
|
||||
this.kTop + (j * this.kHeight / this.kSpriteSize),
|
||||
this.kWidth / this.kSpriteSize,
|
||||
this.kHeight / this.kSpriteSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.suggested) {
|
||||
var fontSize = 16;
|
||||
gContext.font = fontSize + 'px courier new';
|
||||
gContext.fillStyle = '#fff';
|
||||
gContext.fillText('suggested: ' + this.suggested.substring(this.pixelsFilled, this.pixelsFilled + 8), 10, this.kTop + this.kHeight + 2 * fontSize);
|
||||
}
|
||||
|
||||
if (gKeyPressed['0']) {
|
||||
this.image[this.pixelsFilled++] = 0;
|
||||
} else if (gKeyPressed['1']) {
|
||||
this.image[this.pixelsFilled++] = 1;
|
||||
}
|
||||
|
||||
if (this.pixelsFilled == this.kSpriteSize * this.kSpriteSize && this.completed) {
|
||||
var image = [];
|
||||
for (var i = 0; i < this.kSpriteSize; i++) {
|
||||
var line = '';
|
||||
for (var j = 0; j < this.kSpriteSize; j++) {
|
||||
line += this.image[i * this.kSpriteSize + j] ? '1' : '0';
|
||||
}
|
||||
image.push(line);
|
||||
}
|
||||
this.completed(makeImageData(image, 16));
|
||||
}
|
||||
}
|
||||
|
||||
"use strict";
|
||||
|
||||
function SoundEditor() {
|
||||
this.start = true;
|
||||
this.data = [null, null, null];
|
||||
this.downTime = null;
|
||||
this.part = 0;
|
||||
return this;
|
||||
};
|
||||
|
||||
SoundEditor.prototype.update = function() {
|
||||
if (this.start && (gKeyDown['0'] || gKeyDown['1'])) {
|
||||
return;
|
||||
}
|
||||
this.start = false;
|
||||
var min = [20, 20, 0.001];
|
||||
var max = [20000, 20000, 1.0];
|
||||
|
||||
var fontSize = 16;
|
||||
gContext.font = fontSize + 'px courier new';
|
||||
gContext.fillStyle = '#fff';
|
||||
gContext.fillText("start frequency", 1.5 * 640 / 7 - gContext.measureText('start frequency').width / 2, 2 * fontSize);
|
||||
gContext.fillText("end frequency", 3.5 * 640 / 7 - gContext.measureText('end frequency').width / 2, 2 * fontSize);
|
||||
gContext.fillText("duration", 5.5 * 640 / 7 - gContext.measureText('duration').width / 2, 2 * fontSize);
|
||||
|
||||
for (var i = 0; i < this.data.length; i++) {
|
||||
var kHeight = 240;
|
||||
gContext.strokeStyle = '#fff';
|
||||
gContext.strokeRect((2 * i + 1) * 640 / 7, 3 * fontSize, 640 / 7, kHeight);
|
||||
if (this.data[i] != null) {
|
||||
var v = (this.data[i] - min[i]) / (max[i] - min[i]);
|
||||
gContext.fillStyle = '#fff';
|
||||
gContext.fillRect((2 * i + 1) * 640 / 7, 3 * fontSize + kHeight * (1 - v), 640 / 7, kHeight * v);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.part < this.data.length) {
|
||||
if (gKeyPressed['0']) {
|
||||
this.data[this.part] = Math.random() * (max[this.part] - min[this.part]) + min[this.part];
|
||||
this.part++;
|
||||
} else {
|
||||
var now = Date.now();
|
||||
if (!this.downTime && gKeyDown['1']) {
|
||||
this.downTime = now;
|
||||
}
|
||||
if (this.downTime) {
|
||||
var v = Math.min((now - this.downTime) / 1000.0, 1.0);
|
||||
this.data[this.part] = v * (max[this.part] - min[this.part]) + min[this.part];
|
||||
if (!gKeyDown['1'] || (now - this.downTime) / 1000.0 > 1.0) {
|
||||
this.part++;
|
||||
this.downTime = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
var names = ['start frequency', 'end frequency', 'duration'];
|
||||
gContext.fillStyle = '#fff';
|
||||
gContext.font = 'bold ' + fontSize + 'px courier new';
|
||||
gContext.fillText("set " + names[this.part], 640 / 2 - gContext.measureText('set ' + names[this.part]).width / 2, 320);
|
||||
gContext.font = fontSize + 'px courier new';
|
||||
gContext.fillText("1 hold to set", 640 / 2 - gContext.measureText('1 hold to set').width / 2, 320 + fontSize);
|
||||
gContext.fillText("0 random", 640 / 2 - gContext.measureText('0 random').width / 2, 320 + fontSize * 2);
|
||||
} else {
|
||||
gContext.fillStyle = '#fff';
|
||||
gContext.fillText("1 hear it", 640 / 2 - gContext.measureText('1 hear it').width / 2, 320 + fontSize);
|
||||
gContext.fillText("0 done", 640 / 2 - gContext.measureText('0 done').width / 2, 320 + fontSize * 2);
|
||||
if (gKeyPressed['1']) {
|
||||
tone(this.data[0], this.data[1], this.data[2]);
|
||||
}
|
||||
if (gKeyPressed['0'] && this.completed) {
|
||||
this.completed(this.data);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
"use strict";
|
||||
|
||||
function Game(options) {
|
||||
this.options = {};
|
||||
for (var k in options) {
|
||||
this.options[k] = options[k];
|
||||
}
|
||||
this.velocity = [0, 0];
|
||||
this.position = [0, 0];
|
||||
this.gone = {};
|
||||
this.camera = 10;
|
||||
this.projectile = null;
|
||||
this.gameOver = false;
|
||||
this.start = true;
|
||||
this.countdown = 3;
|
||||
|
||||
this.points = 0;
|
||||
this.kills = 0;
|
||||
|
||||
document.location.hash = store(gGame);
|
||||
document.getElementById("share").href = document.location.href;
|
||||
|
||||
if (this.options.button0 == undefined) {
|
||||
this.options.button0 = 2;
|
||||
}
|
||||
|
||||
if (this.options.button1 == undefined) {
|
||||
this.options.button1 = 0;
|
||||
}
|
||||
|
||||
if (!this.options.score) {
|
||||
this.options.score = 1;
|
||||
}
|
||||
|
||||
if (!this.options.player) {
|
||||
this.options.player = makeImageData([
|
||||
'11111111',
|
||||
'10000001',
|
||||
'10100101',
|
||||
'10000001',
|
||||
'10100101',
|
||||
'10111101',
|
||||
'10000001',
|
||||
'11111111',
|
||||
], 16);
|
||||
}
|
||||
|
||||
if (!this.options.enemy) {
|
||||
this.options.enemy = makeImageData([
|
||||
'11111111',
|
||||
'10000001',
|
||||
'10100101',
|
||||
'10000001',
|
||||
'10111101',
|
||||
'10100101',
|
||||
'10000001',
|
||||
'11111111',
|
||||
], 16);
|
||||
}
|
||||
|
||||
if (!this.options.point) {
|
||||
this.options.point = makeImageData([
|
||||
'00000000',
|
||||
'00000000',
|
||||
'00011000',
|
||||
'00100100',
|
||||
'01011010',
|
||||
'01010010',
|
||||
'00100100',
|
||||
'00011000',
|
||||
], 16);
|
||||
}
|
||||
|
||||
this.background = makeImageData([
|
||||
'1110',
|
||||
'0101',
|
||||
'0011',
|
||||
'1001',
|
||||
], 16);
|
||||
|
||||
this.timer = [
|
||||
makeImageData([
|
||||
'110',
|
||||
'010',
|
||||
'010',
|
||||
'010',
|
||||
'111',
|
||||
], 16),
|
||||
makeImageData([
|
||||
'111',
|
||||
'001',
|
||||
'111',
|
||||
'100',
|
||||
'111',
|
||||
], 16),
|
||||
makeImageData([
|
||||
'111',
|
||||
'001',
|
||||
'011',
|
||||
'001',
|
||||
'111',
|
||||
], 16)
|
||||
];
|
||||
|
||||
if (!this.options.level) {
|
||||
this.options.level = '00102';
|
||||
} else {
|
||||
this.options.level = '0' + this.options.level;
|
||||
}
|
||||
|
||||
if (!this.options.jump) {
|
||||
this.options.jump = [1000, 3000, 0.25];
|
||||
}
|
||||
|
||||
if (!this.options.shoot) {
|
||||
this.options.shoot = [300, 300, 0.1];
|
||||
}
|
||||
|
||||
this.collect = [this.options.shoot[0], this.options.jump[1], (this.options.shoot[2] + this.options.jump[2]) / 2];
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Game.prototype.update = function() {
|
||||
if (this.start && (gKeyDown['0'] || gKeyDown['1'])) {
|
||||
return;
|
||||
}
|
||||
this.start = false;
|
||||
|
||||
if (this.countdown > 0) {
|
||||
this.countdown -= gTimeDelta / 1000;
|
||||
if (this.countdown > 0) {
|
||||
var i = Math.min(Math.floor(this.countdown), 2);
|
||||
gContext.putImageData(this.timer[i], 640 / 2 - 16 * 3, 480 / 2 - 16 * 3);
|
||||
} else {
|
||||
this.countdown = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < this.options.level.length; i++) {
|
||||
if (!this.gone[i]) {
|
||||
var c = this.options.level.charAt(i);
|
||||
if (c == '1') {
|
||||
gContext.putImageData(this.options.enemy, i * 16 * 8 * 2 - this.position[0] + this.camera, 240);
|
||||
} else if (c == '2') {
|
||||
gContext.putImageData(this.options.point, i * 16 * 8 * 2 - this.position[0] + this.camera, 240);
|
||||
}
|
||||
}
|
||||
}
|
||||
var tile = Math.round(this.position[0] / (16 * 8 * 2));
|
||||
if (!this.gone[tile]) {
|
||||
var hit = this.options.level.charAt(tile);
|
||||
if (hit == '1' && this.position[1] <= 16 * 8) {
|
||||
if (this.velocity[1] < 0) {
|
||||
this.gone[tile] = true;
|
||||
this.velocity[1] = 1.5;
|
||||
this.kills++;
|
||||
tone(this.collect[1], this.collect[0], this.collect[2]);
|
||||
} else {
|
||||
this.gameOver = true;
|
||||
this.gone[tile] = true;
|
||||
}
|
||||
} else if (hit == '2' && this.position[1] <= 16 * 8) {
|
||||
tone(this.collect[0], this.collect[1], this.collect[2]);
|
||||
this.points += this.options.score;
|
||||
this.gone[tile] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.projectile != null) {
|
||||
gContext.fillStyle = '#fff';
|
||||
var screenPosition = this.projectile - this.position[0] + this.camera;
|
||||
gContext.fillRect(screenPosition, 240 + 16 * 8 / 2, 16, 16);
|
||||
this.projectile += gTimeDelta;
|
||||
var p = Math.floor(this.projectile / (16 * 8 * 2));
|
||||
var hit = this.options.level.charAt(p);
|
||||
if (hit == '1' && !this.gone[p]) {
|
||||
this.gone[p] = true;
|
||||
this.projectile = null;
|
||||
}
|
||||
if (screenPosition > 640) {
|
||||
this.projectile = null;
|
||||
}
|
||||
}
|
||||
|
||||
gContext.putImageData(this.options.player, this.camera, 240 - this.position[1]);
|
||||
this.position[0] += this.velocity[0] * gTimeDelta;
|
||||
this.position[1] += this.velocity[1] * gTimeDelta;
|
||||
this.velocity[1] -= 0.005 * gTimeDelta;
|
||||
if (this.position[1] <= 0 && !this.gameOver) {
|
||||
this.position[1] = 0;
|
||||
this.velocity[1] = 0;
|
||||
}
|
||||
|
||||
if (this.gameOver) {
|
||||
this.position[0] -= 2 * gTimeDelta;
|
||||
if (this.position[1] > -480) {
|
||||
this.position[1] -= gTimeDelta * 0.1;
|
||||
} else {
|
||||
var fontSize = 16;
|
||||
gContext.fillStyle = '#fff';
|
||||
gContext.font = 'bold ' + fontSize + 'px courier new';
|
||||
gContext.fillText('game over', 640 / 2 - gContext.measureText('game over').width / 2, 240 - 2 * fontSize);
|
||||
gContext.font = fontSize + 'px courier new';
|
||||
gContext.fillText('1 retry', 640 / 2 - gContext.measureText('1 retry').width / 2, 240 + 16 * 8 + 2 * fontSize);
|
||||
gContext.fillText('0 back', 640 / 2 - gContext.measureText('1 retry').width / 2, 240 + 16 * 8 + 3 * fontSize);
|
||||
if (gKeyPressed['1'] && this.completed) {
|
||||
this.completed(1);
|
||||
}
|
||||
if (gKeyPressed['0'] && this.completed) {
|
||||
this.completed(0);
|
||||
}
|
||||
}
|
||||
} else if (tile > this.options.level.length) {
|
||||
var targetCamera = 640 / 2 - (16 * 8) / 2;
|
||||
if (this.camera < targetCamera) {
|
||||
this.camera += gTimeDelta / 5;
|
||||
} else {
|
||||
this.camera = targetCamera;
|
||||
if (this.velocity[1] == 0) {
|
||||
this.velocity[1] = 1.5;
|
||||
}
|
||||
var fontSize = 16;
|
||||
gContext.font = fontSize + 'px courier new';
|
||||
gContext.fillStyle = '#fff';
|
||||
gContext.fillText('1 again', 640 / 2 - gContext.measureText('1 again').width / 2, 240 + 16 * 8 + 2 * fontSize);
|
||||
gContext.fillText('0 back', 640 / 2 - gContext.measureText('1 again').width / 2, 240 + 16 * 8 + 3 * fontSize);
|
||||
|
||||
var results = '';
|
||||
if (this.points) {
|
||||
if (results.length) {
|
||||
results += ', ';
|
||||
}
|
||||
results += this.points + (this.points == 1 ? ' point' : ' points');
|
||||
}
|
||||
if (this.kills) {
|
||||
if (results.length) {
|
||||
results += ', ';
|
||||
}
|
||||
results += this.kills + (this.kills == 1 ? ' enemy vanquished' : ' enemies vanquished');
|
||||
}
|
||||
gContext.fillText(results, 640 / 2 - gContext.measureText(results).width / 2, 240 + 16 * 8 + 5 * fontSize);
|
||||
if (gKeyPressed['1'] && this.completed) {
|
||||
this.completed(1);
|
||||
}
|
||||
if (gKeyPressed['0'] && this.completed) {
|
||||
this.completed(0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (var i = 0; i < 12; i++) {
|
||||
for (var j = 0; j < 2; j++) {
|
||||
gContext.putImageData(this.background, i * 16 * 4 - this.position[0] % (16 * 4), 240 + 16 * 8 + j * 16 * 4);
|
||||
}
|
||||
}
|
||||
var jump = this.velocity[1] == 0 &&
|
||||
(this.options.button0 == 0 && gKeyDown['0'] ||
|
||||
this.options.button1 == 0 && gKeyDown['1']);
|
||||
var shoot = this.projectile == null &&
|
||||
(this.options.button0 == 1 && gKeyDown['0'] ||
|
||||
this.options.button1 == 1 && gKeyDown['1']);
|
||||
var move = this.projectile == null &&
|
||||
(this.options.button0 == 2 && gKeyDown['0'] ||
|
||||
this.options.button1 == 2 && gKeyDown['1'] ||
|
||||
this.options.button0 != 2 && this.options.button1 != 2);
|
||||
if (jump) {
|
||||
this.velocity[1] = 1.5;
|
||||
tone(this.options.jump[0], this.options.jump[1], this.options.jump[2]);
|
||||
}
|
||||
if (shoot) {
|
||||
this.projectile = this.position[0];
|
||||
tone(this.options.shoot[0], this.options.shoot[1], this.options.shoot[2]);
|
||||
}
|
||||
if (move) {
|
||||
this.velocity[0] = 1;
|
||||
} else {
|
||||
this.velocity[0] = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function packImage(imageData) {
|
||||
var result = '';
|
||||
for (var i = 0; i < imageData.width / 16; i++) {
|
||||
for (var j = 0; j < imageData.height / 16; j++) {
|
||||
result += (imageData.data[j * imageData.width * 4 * 16 + i * 4 * 16] ? '1' : '0');
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function unpackImageData(data) {
|
||||
var pixels = [];
|
||||
console.debug(data);
|
||||
for (var i = 0; i < 8; i++) {
|
||||
var line = '';
|
||||
for (var j = 0; j < 8; j++) {
|
||||
line += data.charAt(j * 8 + i);
|
||||
}
|
||||
pixels.push(line);
|
||||
}
|
||||
return makeImageData(pixels, 16);
|
||||
}
|
||||
|
||||
function store(game) {
|
||||
var simple = {};
|
||||
for (var k in game) {
|
||||
if (game[k] instanceof ImageData) {
|
||||
simple[k] = packImage(game[k]);
|
||||
} else {
|
||||
simple[k] = game[k];
|
||||
}
|
||||
}
|
||||
return JSON.stringify(simple);
|
||||
};
|
||||
|
||||
function load(game) {
|
||||
var simple = JSON.parse(game);
|
||||
for (var k in simple) {
|
||||
if (['player', 'enemy'].indexOf(k) != -1) {
|
||||
simple[k] = unpackImageData(simple[k]);
|
||||
}
|
||||
}
|
||||
return simple;
|
||||
};
|
||||
|
||||
"use strict";
|
||||
|
||||
var gAudio = null;
|
||||
var gGain = null;
|
||||
|
||||
function tone(frequency0, frequency1, duration) {
|
||||
var Context = window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.oAudioContext || window.msAudioContext;
|
||||
if (!gAudio && Context) {
|
||||
gAudio = new Context();
|
||||
}
|
||||
if (!gGain && gAudio) {
|
||||
gGain = gAudio.createGain();
|
||||
gGain.connect(gAudio.destination);
|
||||
gGain.gain.value = 0.15;
|
||||
}
|
||||
var now = gAudio.currentTime;
|
||||
var oscillator = gAudio.createOscillator();
|
||||
oscillator.frequency.setValueAtTime(frequency0, now);
|
||||
oscillator.frequency.linearRampToValueAtTime(frequency1, now + duration);
|
||||
oscillator.type = 'sine';
|
||||
oscillator.connect(gGain);
|
||||
oscillator.start(now);
|
||||
oscillator.stop(gAudio.currentTime + duration);
|
||||
}
|
||||
|
||||
"use strict";
|
||||
|
||||
function Menu(configuration) {
|
||||
this.title = configuration.title;
|
||||
this.options = configuration.options;
|
||||
this.footer = configuration.footer;
|
||||
this.image = configuration.image;
|
||||
this.bitsNeeded = 0;
|
||||
this.fontSize = 16;
|
||||
this.bits = '';
|
||||
var count = this.options.length;
|
||||
while (count > 1) {
|
||||
this.bitsNeeded += 1;
|
||||
count /= 2;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
Menu.prototype.update = function() {
|
||||
gContext.font = 'bold ' + this.fontSize + 'px courier new';
|
||||
gContext.fillStyle = '#fff';
|
||||
gContext.fillText(this.title, 640 / 2 - gContext.measureText(this.title).width / 2, this.fontSize);
|
||||
|
||||
var maxWidth = 0;
|
||||
for (var i = 0; i < this.options.length; i++) {
|
||||
maxWidth = Math.max(maxWidth, gContext.measureText(this.options[i]).width);
|
||||
}
|
||||
|
||||
for (var i = 0; i < this.options.length; i++) {
|
||||
gContext.font = this.fontSize + 'px courier new';
|
||||
gContext.fillStyle = '#fff';
|
||||
gContext.fillText(bits(i, this.bitsNeeded) + ' ' + this.options[i], 640 / 2 - maxWidth / 2, this.fontSize * (i + 3));
|
||||
}
|
||||
gContext.font = this.fontSize + 'px courier new';
|
||||
gContext.fillStyle = '#fff';
|
||||
var text = '';
|
||||
for (var i = 0; i < this.bitsNeeded; i++) {
|
||||
text += '0';
|
||||
}
|
||||
gContext.fillText(this.bits, 640 / 2 - maxWidth / 2, this.fontSize * (this.options.length + 4));
|
||||
gContext.fillStyle = blinkColor();
|
||||
gContext.fillRect(640 / 2 - maxWidth / 2 + gContext.measureText(this.bits).width, this.fontSize * (this.options.length + 3), 10, this.fontSize);
|
||||
|
||||
if (this.footer) {
|
||||
gContext.font = this.fontSize + 'px courier new';
|
||||
gContext.fillStyle = '#fff';
|
||||
gContext.fillText(this.footer, 640 / 2 - gContext.measureText(this.footer).width / 2, 480 - this.fontSize);
|
||||
}
|
||||
|
||||
if (this.image) {
|
||||
gContext.putImageData(this.image, 640 / 2 - this.image.width / 2, 480 / 2 - this.image.height / 2);
|
||||
}
|
||||
|
||||
if (gKeyPressed['0']) {
|
||||
this.bits += '0';
|
||||
} else if (gKeyPressed['1']) {
|
||||
this.bits += '1';
|
||||
}
|
||||
|
||||
if (this.bits.length >= this.bitsNeeded && this.completed) {
|
||||
var result = 0;
|
||||
for (var i = 0; i < this.bits.length; i++) {
|
||||
result *= 2;
|
||||
if (this.bits.charAt(i) == '1') {
|
||||
result |= 1;
|
||||
}
|
||||
}
|
||||
this.completed(result);
|
||||
}
|
||||
}
|
||||
|
||||
"use strict";
|
||||
var gContext;
|
||||
var gKeyDown = {}
|
||||
var gKeyPressed = {}
|
||||
var gMode;
|
||||
var gTimeDelta = 0;
|
||||
var gLastFrame = Date.now();
|
||||
var gTimer;
|
||||
|
||||
var gGame = {};
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
var canvas = document.getElementById("canvas");
|
||||
gContext = canvas.getContext("2d");
|
||||
|
||||
if (document.location.hash) {
|
||||
try {
|
||||
gGame = load(document.location.hash.substring(1));
|
||||
} catch (e) {
|
||||
console.debug(e);
|
||||
}
|
||||
}
|
||||
|
||||
document.body.onkeydown = function(event) {
|
||||
if (event.which == 48 || event.which == 96) {
|
||||
gKeyDown['0'] = true;
|
||||
}
|
||||
if (event.which == 49 || event.which == 97) {
|
||||
gKeyDown['1'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
document.body.onkeyup = function(event) {
|
||||
if (event.which == 48 || event.which == 96) {
|
||||
gKeyDown['0'] = false;
|
||||
}
|
||||
if (event.which == 49 || event.which == 97) {
|
||||
gKeyDown['1'] = false;
|
||||
}
|
||||
}
|
||||
|
||||
document.body.onkeypress = function(event) {
|
||||
if (event.which == 48 || event.which == 96) {
|
||||
gKeyPressed['0'] = true;
|
||||
}
|
||||
if (event.which == 49 || event.which == 97) {
|
||||
gKeyPressed['1'] = true;
|
||||
}
|
||||
if ((event.which == 48 || event.which == 49 || event.which == 96 || event.which == 97) &&
|
||||
!(gMode instanceof Game) &&
|
||||
!(gMode instanceof SoundEditor)) {
|
||||
|
||||
var min = 40;
|
||||
var max = 2000;
|
||||
var f = Math.random() * (max - min) + min;
|
||||
tone(f, f, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
makeMainMenu();
|
||||
window.requestAnimationFrame(update);
|
||||
});
|
||||
|
||||
function makeMainMenu() {
|
||||
var menu = new Menu({
|
||||
title: 'become a game developer in 60 seconds',
|
||||
options: ['create', 'test'],
|
||||
footer: 'buttons: 0 and 1',
|
||||
image: makeImageData([
|
||||
'11001110110011101100111',
|
||||
'01001010010010100100101',
|
||||
'01001010010010100100101',
|
||||
'01001010010010100100101',
|
||||
'11101110111011101110111',
|
||||
'00000000000000000000000',
|
||||
'00111100100100010111000',
|
||||
'00100001010110110100000',
|
||||
'00101101110101010110000',
|
||||
'00100101010100010100000',
|
||||
'00111101010100010111000',
|
||||
], 16)}
|
||||
);
|
||||
menu.completed = function(result) {
|
||||
if (result == 0) {
|
||||
gTimer = 60;
|
||||
makeCreateMenu();
|
||||
} else {
|
||||
gTimer = undefined;
|
||||
makeGame();
|
||||
}
|
||||
};
|
||||
gMode = menu;
|
||||
}
|
||||
|
||||
function makeCreateMenu() {
|
||||
var menu = new Menu({title: 'make game', options: [
|
||||
'[' + (gGame.player ? 'x' : ' ') + '] player',
|
||||
'[' + (gGame.enemy ? 'x' : ' ') + '] enemy',
|
||||
'[' + (gGame.score ? 'x' : ' ') + '] score',
|
||||
'[' + (gGame.jump ? 'x' : ' ') + '] jump',
|
||||
'[' + (gGame.shoot ? 'x' : ' ') + '] shoot',
|
||||
'[' + (gGame.button0 != undefined ? 'x' : ' ') + '] buttons',
|
||||
'[' + (gGame.level ? 'x' : ' ') + '] level',
|
||||
' ship it',
|
||||
]});
|
||||
menu.completed = function(result) {
|
||||
if (result == 0) {
|
||||
makeImageEditor('player',
|
||||
'00111100'+
|
||||
'00111100'+
|
||||
'00111100'+
|
||||
'10011001'+
|
||||
'11111111'+
|
||||
'00011000'+
|
||||
'00100100'+
|
||||
'00100100');
|
||||
} else if (result == 1) {
|
||||
makeImageEditor('enemy',
|
||||
'00111100'+
|
||||
'01000010'+
|
||||
'10000001'+
|
||||
'10100101'+
|
||||
'10000001'+
|
||||
'11011011'+
|
||||
'01011010'+
|
||||
'01111110');
|
||||
} else if (result == 2) {
|
||||
gGame.score = 1;
|
||||
makeScoreEditor();
|
||||
} else if (result == 3) {
|
||||
makeSoundEditor('jump');
|
||||
} else if (result == 4) {
|
||||
makeSoundEditor('shoot');
|
||||
} else if (result == 5) {
|
||||
makeButtonsMenu();
|
||||
} else if (result == 6) {
|
||||
gGame.level = '';
|
||||
makeLevelEditor();
|
||||
} else if (result == 7) {
|
||||
gTimer = undefined;
|
||||
makeGame();
|
||||
}
|
||||
}
|
||||
gMode = menu;
|
||||
}
|
||||
|
||||
function makeImageEditor(what, suggested) {
|
||||
var editor = new ImageEditor();
|
||||
editor.suggested = suggested;
|
||||
editor.title = 'draw ' + what + ' by pressing 1 and 0';
|
||||
editor.completed = function(result) {
|
||||
gGame[what] = result;
|
||||
makeCreateMenu();
|
||||
};
|
||||
gMode = editor;
|
||||
}
|
||||
|
||||
function makeSoundEditor(what) {
|
||||
var editor = new SoundEditor();
|
||||
editor.completed = function(result) {
|
||||
gGame[what] = result;
|
||||
makeCreateMenu();
|
||||
};
|
||||
gMode = editor;
|
||||
}
|
||||
|
||||
function makeButtonMenu(button) {
|
||||
var menu = new Menu({title: 'what does ' + button + ' do?', options: [
|
||||
'jump',
|
||||
'shoot',
|
||||
'move',
|
||||
'nothing',
|
||||
]});
|
||||
return menu;
|
||||
}
|
||||
|
||||
function makeButtonsMenu(button) {
|
||||
var menu = makeButtonMenu('0');
|
||||
menu.completed = function(result) {
|
||||
gGame['button0'] = result;
|
||||
menu = makeButtonMenu('1');
|
||||
menu.completed = function(result) {
|
||||
gGame['button1'] = result;
|
||||
makeCreateMenu();
|
||||
}
|
||||
gMode = menu;
|
||||
};
|
||||
gMode = menu;
|
||||
}
|
||||
|
||||
function update() {
|
||||
gContext.fillStyle = '#000';
|
||||
gContext.fillRect(0, 0, 640, 480);
|
||||
|
||||
var now = Date.now();
|
||||
gTimeDelta = now - gLastFrame;
|
||||
gLastFrame = now;
|
||||
|
||||
if (gTimer != undefined) {
|
||||
if (gTimer > 0) {
|
||||
gTimer -= gTimeDelta / 1000;
|
||||
} else {
|
||||
gTimer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (gMode) {
|
||||
gMode.update();
|
||||
} else {
|
||||
gContext.fillStyle = pulseColor();
|
||||
gContext.fillRect(0, 0, 640, 480);
|
||||
}
|
||||
|
||||
for (var i in gKeyPressed) {
|
||||
gKeyPressed[i] = false;
|
||||
}
|
||||
|
||||
if (!(gMode instanceof Game) && gTimer !== undefined) {
|
||||
var fontSize = 16;
|
||||
gContext.font = 'bold ' + fontSize + 'px courier new';
|
||||
gContext.fillStyle = '#fff';
|
||||
var remaining = Math.round(gTimer);
|
||||
if (gTimer <= 0) {
|
||||
remaining = 'OUT OF TIME! SHIP IT! OUT OF TIME! SHIP IT! OUT OF TIME! 111!';
|
||||
gContext.fillStyle = pulseColor();
|
||||
}
|
||||
gContext.fillText(remaining, 640 - gContext.measureText(remaining).width - 1, 480 - 1);
|
||||
}
|
||||
|
||||
window.requestAnimationFrame(update);
|
||||
}
|
||||
|
||||
function pulseColor() {
|
||||
var pulse = (Math.sin(15 * Date.now() / 1000) + 1) / 2;
|
||||
var value = Math.floor(255 * pulse).toString();
|
||||
return 'rgb(' + value + ',' + value + ',' + value + ')';
|
||||
}
|
||||
|
||||
function blinkColor() {
|
||||
var blink = (Math.floor(4 * Date.now() / 1000) & 1) == 0;
|
||||
var value = Math.floor(255 * blink).toString();
|
||||
return 'rgb(' + value + ',' + value + ',' + value + ')';
|
||||
}
|
||||
|
||||
function bits(value, count) {
|
||||
var result = '';
|
||||
for (var i = 0; i < count; i++) {
|
||||
if ((value & (1 << i)) != 0) {
|
||||
result = '1' + result;
|
||||
} else {
|
||||
result = '0' + result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function makeImageData(pixels, scale) {
|
||||
var height = pixels.length;
|
||||
var width = pixels[0].length;
|
||||
|
||||
var data = gContext.createImageData(width * scale, height * scale);
|
||||
for (var i = 0; i < width * scale; i++) {
|
||||
for (var j = 0; j < height * scale; j++) {
|
||||
var v = pixels[Math.floor(j / scale)].charAt(Math.floor(i / scale)) == '1';
|
||||
data.data[4 * (j * width * scale + i) + 0] = v ? 255 : 0;
|
||||
data.data[4 * (j * width * scale + i) + 1] = v ? 255 : 0;
|
||||
data.data[4 * (j * width * scale + i) + 2] = v ? 255 : 0;
|
||||
data.data[4 * (j * width * scale + i) + 3] = 255;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
function makeGame() {
|
||||
var game = new Game(gGame);
|
||||
game.completed = function(result) {
|
||||
if (result == 1) {
|
||||
makeGame();
|
||||
} else {
|
||||
makeMainMenu();
|
||||
}
|
||||
};
|
||||
gMode = game;
|
||||
}
|
||||
|
||||
function makeLevelEditor() {
|
||||
var menu = new Menu({title: 'choose object for location ' + gGame.level.length, options: [
|
||||
'nothing',
|
||||
'enemy',
|
||||
'points',
|
||||
'finish',
|
||||
]});
|
||||
menu.completed = function(result) {
|
||||
if (result == 0) {
|
||||
gGame.level += '0';
|
||||
makeLevelEditor();
|
||||
} else if (result == 1) {
|
||||
gGame.level += '1';
|
||||
makeLevelEditor();
|
||||
} else if (result == 2) {
|
||||
gGame.level += '2';
|
||||
makeLevelEditor();
|
||||
} else if (result == 3) {
|
||||
makeCreateMenu();
|
||||
}
|
||||
};
|
||||
gMode = menu;
|
||||
}
|
||||
|
||||
function makeScoreEditor() {
|
||||
var menu = new Menu({title: 'how many points?: ' + gGame.score, options: [
|
||||
'more',
|
||||
'done',
|
||||
]});
|
||||
menu.completed = function(result) {
|
||||
if (result == 0) {
|
||||
gGame.score *= 10;
|
||||
if (gGame.score < 10000000000000000000) {
|
||||
makeScoreEditor();
|
||||
} else {
|
||||
makeCreateMenu();
|
||||
}
|
||||
} else if (result == 1) {
|
||||
makeCreateMenu();
|
||||
}
|
||||
};
|
||||
gMode = menu;
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
body {
|
||||
background-color: #444;
|
||||
color: #fff;
|
||||
}
|
||||
canvas {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
display: block;
|
||||
width: 640px;
|
||||
}
|
||||
#share {
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="canvas" width="640" height="480"></canvas>
|
||||
<div><a id="share" href="http://www.unprompted.com/ldjam/compo34/">share link, updated on test</a></div>
|
||||
</body>
|
||||
</html>
|
||||
`,
|
||||
width: 720,
|
||||
height: 512,
|
||||
});
|
@ -23,6 +23,7 @@ function parseUrl(url) {
|
||||
function parseResponse(data) {
|
||||
var firstLine;
|
||||
var headers = {};
|
||||
var headerArray = [];
|
||||
|
||||
while (true) {
|
||||
var endLine = data.indexOf("\r\n");
|
||||
@ -33,11 +34,14 @@ function parseResponse(data) {
|
||||
break;
|
||||
} else {
|
||||
var colon = line.indexOf(":");
|
||||
headers[line.substring(0, colon).toLowerCase()] = line.substring(colon + 1).trim();
|
||||
var key = line.substring(0, colon);
|
||||
var value = line.substring(colon + 1).trim();
|
||||
headers[key.toLowerCase()] = value;
|
||||
headerArray.push([key, value]);
|
||||
}
|
||||
data = data.substring(endLine + 2);
|
||||
}
|
||||
return {body: data, headers: headers};
|
||||
return {body: data, headers: headers, headerArray: headerArray};
|
||||
}
|
||||
|
||||
function get(url) {
|
||||
|
137
packages/cory/libiframe/libiframe.js
Normal file
137
packages/cory/libiframe/libiframe.js
Normal file
@ -0,0 +1,137 @@
|
||||
"use strict";
|
||||
|
||||
//! {"category": "libraries"}
|
||||
|
||||
const kRpcSource = `
|
||||
class RPC {
|
||||
constructor() {
|
||||
this._functions = [];
|
||||
this.exports = null;
|
||||
this.sendCallback = null;
|
||||
}
|
||||
|
||||
export(functions) {
|
||||
return this._send(["export", functions]);
|
||||
}
|
||||
|
||||
_call(index) {
|
||||
return this._send(["call", index, Array.prototype.slice.call(arguments, 1)]);
|
||||
}
|
||||
|
||||
_send(message) {
|
||||
var serialized = this._serialize(message);
|
||||
if (this.sendCallback) {
|
||||
return this.sendCallback(serialized);
|
||||
}
|
||||
return serialized;
|
||||
}
|
||||
|
||||
deliver(message) {
|
||||
var deserialized = this._deserialize(message);
|
||||
if (deserialized[0] == "export") {
|
||||
this.exports = deserialized[1];
|
||||
} else if (deserialized[0] == "call") {
|
||||
var f = this._functions[deserialized[1]];
|
||||
f.apply(null, deserialized[2]);
|
||||
}
|
||||
}
|
||||
|
||||
_deserialize(data) {
|
||||
var result = null;
|
||||
if (data[0] == "array") {
|
||||
result = new Array(data[1].length);
|
||||
for (var i = 0; i < data[1].length; i++) {
|
||||
result[i] = this._deserialize(data[1][i]);
|
||||
}
|
||||
} else if (data[0] == "object") {
|
||||
result = {};
|
||||
for (var i in data[1]) {
|
||||
result[i] = this._deserialize(data[1][i]);
|
||||
}
|
||||
} else if (data[0] == "number" || data[0] == "boolean" || data[0] == "string") {
|
||||
result = data[1];
|
||||
} else if (data[0] == "function") {
|
||||
result = this._call.bind(this, data[1]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
_serialize(data) {
|
||||
var result = null;
|
||||
if (Array.isArray(data)) {
|
||||
result = ["array", data.map(x => this._serialize(x, this.functions))];
|
||||
} else if (typeof data == "function") {
|
||||
var index = this._functions.indexOf(data);
|
||||
if (index == -1) {
|
||||
index = this._functions.length;
|
||||
this._functions.push(data);
|
||||
}
|
||||
result = ["function", index];
|
||||
} else if (typeof data == "object") {
|
||||
var fields = {};
|
||||
while (data) {
|
||||
var own = Object.getOwnPropertyNames(data);
|
||||
for (var i = 0; i < own.length; i++) {
|
||||
var name = own[i];
|
||||
if (name != "constructor") {
|
||||
var descriptor = Object.getOwnPropertyDescriptor(data, name);
|
||||
if (descriptor&& typeof descriptor.value == "function") {
|
||||
fields[name] = this._serialize(descriptor.value, this.functions);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (data.__proto__ == Object.prototype) {
|
||||
break;
|
||||
}
|
||||
data = Object.getPrototypeOf(data);
|
||||
}
|
||||
result = ["object", fields];
|
||||
} else {
|
||||
result = [typeof data, data];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}`
|
||||
|
||||
exports.iframe = function(options) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var iframeName = options.name || "iframe";
|
||||
var RPC = eval(kRpcSource);
|
||||
var rpc = new RPC();
|
||||
rpc.sendCallback = terminal.postMessageToIframe.bind(null, iframeName);
|
||||
|
||||
core.register("onWindowMessage", function(message) {
|
||||
if (message.message == "ready") {
|
||||
resolve(rpc.exports);
|
||||
} else {
|
||||
rpc.deliver(message.message);
|
||||
}
|
||||
});
|
||||
|
||||
terminal.split([{name: "terminal", type: "vertical"}]);
|
||||
terminal.print({
|
||||
iframe: `
|
||||
<!DOCTYPE html>
|
||||
<body style="background-color: #fff"></body>
|
||||
<script language="javascript">
|
||||
${kRpcSource}
|
||||
window.addEventListener("load", function() {
|
||||
parent.postMessage("ready", "*");
|
||||
});
|
||||
let rpc = new RPC();
|
||||
window.addEventListener("message", function(event) {
|
||||
rpc.deliver(event.data);
|
||||
});
|
||||
rpc.sendCallback = function(data) {
|
||||
parent.postMessage(data, "*");
|
||||
}
|
||||
${options.source}
|
||||
</script>
|
||||
`,
|
||||
name: iframeName,
|
||||
style: "flex: 1 1; " + options.style,
|
||||
width: null,
|
||||
height: null,
|
||||
});
|
||||
});
|
||||
}
|
@ -98,6 +98,8 @@ class IrcService {
|
||||
let person = prefix.split('!')[0];
|
||||
let conversation = parts[1];
|
||||
this._service.notifyPresenceChanged(conversation, person, "unavailable");
|
||||
} else if (parts[0] == "PONG") {
|
||||
// this._service.notifyMessageReceived("", {from: prefix, message: "RTT: " + (new Date().getTime() - parseInt(parts[2]))});
|
||||
} else if (parts[0] == "QUIT") {
|
||||
let person = prefix.split('!')[0];
|
||||
let conversations = this._service.getConversations();
|
||||
@ -164,9 +166,15 @@ class IrcService {
|
||||
self._service.notifyStateChanged("connected");
|
||||
self._send("USER " + options.user + " 0 * :" + options.realName);
|
||||
self._send("NICK " + options.nick);
|
||||
self._sendPing();
|
||||
}).catch(self._service.reportError);
|
||||
}
|
||||
|
||||
_sendPing() {
|
||||
this._send("PING :" + new Date().getTime());
|
||||
setTimeout(this._sendPing.bind(this), 3000);
|
||||
}
|
||||
|
||||
sendMessage(target, text) {
|
||||
if (!target) {
|
||||
this._socket.write(text + "\r\n");
|
||||
|
@ -771,11 +771,11 @@ class XmppService {
|
||||
} else if (stanza.attributes.id == "session0") {
|
||||
self._socket.write("<presence to='chadhappyfuntime@conference.jabber.troubleimpact.com/" + userName + "'><priority>1</priority><x xmlns='http://jabber.org/protocol/muc'/></presence>");
|
||||
self._schedulePing();
|
||||
//self._conversations["chadhappyfuntime@conference.jabber.troubleimpact.com"] = {participants: [], history: []};
|
||||
} else if (stanza.children.length && stanza.children[0].name == "ping") {
|
||||
// Ping response.
|
||||
} else {
|
||||
self._service.notifyMessageReceived(null, {unknown: stanza});
|
||||
self._socket.write(`<iq id="${stanza.attributes.id}" type="error" from="${stanza.attributes.to}" to="${stanza.attributes.from}"><error type="cancel"><item-not-found xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/></error></iq>`);
|
||||
}
|
||||
} else if (stanza.name == "message") {
|
||||
let message = self._convertMessage(stanza);
|
||||
|
128
packages/cory/meetup/meetup.js
Normal file
128
packages/cory/meetup/meetup.js
Normal file
@ -0,0 +1,128 @@
|
||||
//! {"permissions": ["network"], "require": ["libencoding", "libhttp"]}
|
||||
|
||||
let libhttp = require("libhttp");
|
||||
|
||||
async function getEvents() {
|
||||
let now = new Date();
|
||||
let cacheVersion = "1";
|
||||
let useCache = await database.get("cacheVersion") == cacheVersion;
|
||||
let events = [];
|
||||
let url = "https://api.meetup.com/The-Most-Informal-Running-Club-Ever-TMIRCE-Upstate/events?&sign=true&photo-host=public&status=past";
|
||||
let done = false;
|
||||
while (!done) {
|
||||
let response;
|
||||
if (useCache) {
|
||||
response = await database.get(url);
|
||||
if (response) {
|
||||
response = JSON.parse(response);
|
||||
}
|
||||
}
|
||||
if (!response) {
|
||||
response = await libhttp.get(url);
|
||||
await database.set(url, JSON.stringify(response));
|
||||
}
|
||||
let nextLink;
|
||||
let theseEvents = JSON.parse(response.body);
|
||||
for (let j in theseEvents) {
|
||||
if (new Date(theseEvents[j].time) < now) {
|
||||
events.push(theseEvents[j]);
|
||||
} else {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (let j in response.headerArray) {
|
||||
let link = response.headerArray[j];
|
||||
if (link[0] == "Link" && link[1].split("; ")[1] == 'rel="next"') {
|
||||
link = link[1].split("; ")[0];
|
||||
link = link.substring(1, link.length - 1);
|
||||
nextLink = link;
|
||||
}
|
||||
}
|
||||
if (nextLink) {
|
||||
url = nextLink;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
await database.set("cacheVersion", cacheVersion);
|
||||
return events;
|
||||
}
|
||||
|
||||
async function trackWorkouts(events) {
|
||||
for (let i in events) {
|
||||
let event = events[i];
|
||||
if (event && event.venue && event.venue.name
|
||||
&& new Date(event.time).getDay() == 1) {
|
||||
let match = /follow (?:my|our) (.*?) workout/.exec(event.description);
|
||||
let workout;
|
||||
if (match) {
|
||||
workout = match[1];
|
||||
} else if (/snowshoe/.exec(event.description)
|
||||
|| /No run/.exec(event.description)) {
|
||||
// nothing
|
||||
} else {
|
||||
terminal.print(event.description);
|
||||
}
|
||||
if (workout) {
|
||||
terminal.print(workout);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function locationByDay(day, events) {
|
||||
for (let i in events) {
|
||||
let event = events[i];
|
||||
if (event && event.venue && event.venue.name
|
||||
&& new Date(event.time).getDay() == day) {
|
||||
terminal.print(event.venue.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function redisplay(action, actions, events) {
|
||||
terminal.clear();
|
||||
if (actions[action]) {
|
||||
terminal.setHash(action);
|
||||
terminal.print({style: "font-size: xx-large", value: action});
|
||||
}
|
||||
for (let i in actions) {
|
||||
terminal.print({command: i});
|
||||
}
|
||||
if (actions[action]) {
|
||||
await actions[action](events);
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
terminal.print("loading events...");
|
||||
let events = await getEvents();
|
||||
terminal.print("loaded ", events.length.toString(), " events");
|
||||
|
||||
let actions = {
|
||||
"Sunday Locations": locationByDay.bind(null, 0),
|
||||
"Monday Track Workouts": trackWorkouts,
|
||||
"Tuesday Locations": locationByDay.bind(null, 2),
|
||||
"Wednesday Locations": locationByDay.bind(null, 3),
|
||||
"Thursday Locations": locationByDay.bind(null, 4),
|
||||
"Friday Locations": locationByDay.bind(null, 5),
|
||||
"Saturday Locations": locationByDay.bind(null, 6),
|
||||
}
|
||||
|
||||
core.register("hashChange", function(event) {
|
||||
if (event.hash && event.hash[0] == '#') {
|
||||
terminal.clear();
|
||||
let hash = event.hash.substring(1);
|
||||
redisplay(hash, actions, events);
|
||||
}
|
||||
});
|
||||
|
||||
let action = null;
|
||||
while (true) {
|
||||
redisplay(action, actions, events);
|
||||
action = await terminal.readLine();
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(terminal.print);
|
15
packages/cory/messages/messages.js
Normal file
15
packages/cory/messages/messages.js
Normal file
@ -0,0 +1,15 @@
|
||||
if (imports.terminal) {
|
||||
core.register("onMessage", function(sender, message) {
|
||||
terminal.print(JSON.stringify(core.user.index), " ", message);
|
||||
});
|
||||
|
||||
core.register("onInput", function(input) {
|
||||
core.getService("global").then(function(service) {
|
||||
service.postMessage(input);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
core.register("onMessage", function(sender, message) {
|
||||
core.broadcast(message);
|
||||
});
|
||||
}
|
30
packages/cory/reminder/reminder.js
Normal file
30
packages/cory/reminder/reminder.js
Normal file
@ -0,0 +1,30 @@
|
||||
"use strict";
|
||||
|
||||
//! {"category": "tests"}
|
||||
|
||||
|
||||
terminal.print("Time to buy a new life jacket.");
|
||||
/*
|
||||
terminal.print("hi");
|
||||
terminal.print("here is some svg:");
|
||||
terminal.print({svg: {
|
||||
attributes: {
|
||||
width: 32,
|
||||
height: 32,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: "circle",
|
||||
attributes: {
|
||||
cx: 16,
|
||||
cy: 16,
|
||||
r: 15,
|
||||
stroke: "green",
|
||||
"stroke-width": "4",
|
||||
fill: "yellow",
|
||||
},
|
||||
},
|
||||
],
|
||||
}});
|
||||
|
||||
terminal.print("end of svg");*/
|
33
packages/cory/splits/splits.js
Normal file
33
packages/cory/splits/splits.js
Normal file
@ -0,0 +1,33 @@
|
||||
"use strict";
|
||||
|
||||
//! {"category": "tests"}
|
||||
|
||||
terminal.print("Hello, world!");
|
||||
terminal.split([
|
||||
{name: "h1", grow: 4},
|
||||
{name: "h2", grow: 1},
|
||||
{type: "vertical", children: [
|
||||
{name: "h3.v1"},
|
||||
{name: "h3.v2"},
|
||||
{type: "horizontal", children: [
|
||||
{name: "h3.v3.h1"},
|
||||
{name: "h3.v3.h2"},
|
||||
{name: "h3.v3.h3"},
|
||||
]},
|
||||
{name: "h3.v4"},
|
||||
]},
|
||||
{name: "h4"}
|
||||
]);
|
||||
|
||||
function multiprint(text) {
|
||||
var terminals = ["h1", "h2", "h3.v1", "h3.v2", "h3.v3.h1", "h3.v3.h2", "h3.v3.h3", "h3.v4", "h4"];
|
||||
for (var i = 0; i < terminals.length; i++) {
|
||||
terminal.select(terminals[i]);
|
||||
terminal.print({style: "color: red", value: terminals[i]}, " ", text);
|
||||
}
|
||||
}
|
||||
|
||||
multiprint("hello");
|
||||
core.register("onInput", function(input) {
|
||||
multiprint(input);
|
||||
});
|
208
packages/cory/tanks/tanks.js
Normal file
208
packages/cory/tanks/tanks.js
Normal file
@ -0,0 +1,208 @@
|
||||
"use strict";
|
||||
|
||||
//! {"require": ["libiframe"]}
|
||||
|
||||
let isClient = imports.terminal != null;
|
||||
if (isClient) {
|
||||
require("libiframe").iframe({
|
||||
source: `
|
||||
document.documentElement.setAttribute("style", "width: 100%; height: 100%; margin: 0; padding: 0");
|
||||
document.body.setAttribute("style", "display: flex; flex-direction: column; height: 100%; width: 100%; margin: 0; padding: 0");
|
||||
document.body.style.color = '#fff';
|
||||
document.body.style.backgroundColor = '#000';
|
||||
|
||||
var canvas = document.createElement("canvas");
|
||||
canvas.setAttribute("style", "flex: 1 1; image-rendering: pixelated");
|
||||
canvas.width = 128;
|
||||
canvas.height = 128;
|
||||
document.body.append(canvas);
|
||||
|
||||
var buttonBar = document.createElement("div");
|
||||
buttonBar.setAttribute("style", "flex: 0 1 1in; display: flex; flex-direction: row");
|
||||
var buttons = ["<", "^", "v", ">", "Fire!"];
|
||||
for (var i = 0; i < buttons.length; i++) {
|
||||
var button = document.createElement("input");
|
||||
button.setAttribute("type", "button");
|
||||
button.setAttribute("style", "flex: 1 1");
|
||||
button.value = buttons[i];
|
||||
button.onclick = buttonClicked.bind(null, buttons[i]);
|
||||
buttonBar.append(button);
|
||||
}
|
||||
document.body.append(buttonBar);
|
||||
|
||||
var buttonCallback;
|
||||
function buttonClicked(button) {
|
||||
if (buttonCallback) {
|
||||
buttonCallback(button);
|
||||
}
|
||||
}
|
||||
|
||||
var kExportNames = [
|
||||
"beginPath",
|
||||
"fill",
|
||||
"save",
|
||||
"restore",
|
||||
"scale",
|
||||
"rotate",
|
||||
"translate",
|
||||
"transform",
|
||||
"arc",
|
||||
"moveTo",
|
||||
"lineTo",
|
||||
"fillRect",
|
||||
"fillText",
|
||||
"stroke",
|
||||
];
|
||||
var context = canvas.getContext("2d");
|
||||
var exports = {};
|
||||
for (var i = 0; i < kExportNames.length; i++) {
|
||||
exports[kExportNames[i]] = context[kExportNames[i]].bind(context);
|
||||
}
|
||||
exports.setButtonCallback = function(callback) { buttonCallback = callback; };
|
||||
exports.setFillStyle = function(style) { context.fillStyle = style; };
|
||||
exports.setStrokeStyle = function(style) { context.strokeStyle = style; };
|
||||
exports.setLineWidth = function(width) { context.lineWidth = width; };
|
||||
rpc.export(exports);
|
||||
`,
|
||||
style: `
|
||||
border: 0;
|
||||
`}).then(initialize).catch(terminal.print);
|
||||
|
||||
function initialize(iframe) {
|
||||
iframe.setButtonCallback(click);
|
||||
draw(iframe);
|
||||
core.register("onMessage", onMessage.bind(null, iframe));
|
||||
core.getService("server").then(function(server) {
|
||||
server.postMessage({ready: true});
|
||||
});
|
||||
}
|
||||
|
||||
async function click(button) {
|
||||
(await core.getService("server")).postMessage({button: button});
|
||||
}
|
||||
|
||||
function draw(iframe) {
|
||||
iframe.setFillStyle('#222');
|
||||
iframe.fillRect(0, 0, 640, 480);
|
||||
}
|
||||
|
||||
function drawTank(iframe, x, y, color, angle) {
|
||||
iframe.save();
|
||||
iframe.setLineWidth(1);
|
||||
iframe.setFillStyle(color);
|
||||
iframe.setStrokeStyle(color);
|
||||
iframe.translate(x, y);
|
||||
iframe.beginPath();
|
||||
iframe.arc(0, 0, 4, Math.PI, 2 * Math.PI);
|
||||
iframe.fill();
|
||||
iframe.beginPath();
|
||||
var radians = Math.PI + angle * Math.PI / 180.0;
|
||||
iframe.moveTo(Math.cos(radians) * 2, Math.sin(radians) * 2 - 0.5);
|
||||
iframe.lineTo(Math.cos(radians) * 10, Math.sin(radians) * 10 - 0.5);
|
||||
iframe.stroke();
|
||||
iframe.restore();
|
||||
}
|
||||
|
||||
function onMessage(iframe, sender, message) {
|
||||
iframe.setFillStyle('#222');
|
||||
iframe.fillRect(0, 0, 640, 480);
|
||||
|
||||
for (let i = 0; i < message.users.length; i++) {
|
||||
var tank = message.users[i];
|
||||
drawTank(iframe, tank.position.x, tank.position.y, tank.user == core.user.index ? '#f00' : '#0f0', tank.angle);
|
||||
}
|
||||
iframe.setFillStyle('#0f0');
|
||||
for (let i = 0; i < message.terrain.length; i++) {
|
||||
let h = message.terrain[i];
|
||||
iframe.fillRect(i, 128 - h, i + 1, h);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let users = {};
|
||||
let terrain = new Array(128);
|
||||
let updating = false;
|
||||
|
||||
function startUpdating() {
|
||||
if (!updating) {
|
||||
setTimeout(100, update);
|
||||
updating = true;
|
||||
}
|
||||
}
|
||||
|
||||
function update() {
|
||||
updating = false;
|
||||
for (let u of Object.values(users)) {
|
||||
user.position.y++;
|
||||
updating = true;
|
||||
}
|
||||
broadcastUsers();
|
||||
if (updating) {
|
||||
setTimeout(100, update);
|
||||
}
|
||||
}
|
||||
|
||||
function initializeTerrain() {
|
||||
for (let i = 0; i < terrain.length; i++) {
|
||||
terrain[i] = 32;
|
||||
}
|
||||
}
|
||||
|
||||
function broadcastUsers() {
|
||||
core.broadcast({
|
||||
users: Object.keys(users).map(x => ({user: x, position: users[x].position, angle: users[x].angle})),
|
||||
terrain: terrain,
|
||||
});
|
||||
}
|
||||
|
||||
function placeNewUser() {
|
||||
let positions = Object.keys(users).map(x => users[x].position.x);
|
||||
var best = 128 / 2;
|
||||
var bestDistance = -1;
|
||||
if (positions.length) {
|
||||
for (var i = 10; i < 118; i++) {
|
||||
var thisDistance = Math.min.apply(null, positions.map(x => Math.abs(i - x)));
|
||||
if (thisDistance > bestDistance) {
|
||||
bestDistance = thisDistance;
|
||||
best = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return {x: best, y: 10, d: bestDistance};
|
||||
}
|
||||
|
||||
initializeTerrain();
|
||||
|
||||
core.register("onMessage", function(sender, message) {
|
||||
if (message.ready) {
|
||||
users[sender.index] = {
|
||||
user: sender,
|
||||
angle: 0,
|
||||
velocity: 100,
|
||||
position: placeNewUser(),
|
||||
};
|
||||
broadcastUsers();
|
||||
startUpdating();
|
||||
} else if (message.button) {
|
||||
switch (message.button) {
|
||||
case "<":
|
||||
users[sender.index].angle = Math.round(Math.max(users[sender.index].angle - 5.0, 0.0));
|
||||
break;
|
||||
case ">":
|
||||
users[sender.index].angle = Math.round(Math.min(users[sender.index].angle + 5.0, 180.0));
|
||||
break;
|
||||
case "^":
|
||||
users[sender.index].velocity++;
|
||||
break;
|
||||
case "v":
|
||||
users[sender.index].velocity--;
|
||||
break;
|
||||
}
|
||||
broadcastUsers();
|
||||
}
|
||||
});
|
||||
|
||||
core.register("onSessionEnd", function(user) {
|
||||
delete users[user.index];
|
||||
broadcastUsers();
|
||||
});
|
||||
}
|
13
packages/cory/test/test.js
Normal file
13
packages/cory/test/test.js
Normal file
@ -0,0 +1,13 @@
|
||||
async function main() {
|
||||
terminal.print("Hello, world!");
|
||||
|
||||
terminal.print("Please enter your name:");
|
||||
var name = await terminal.readLine();
|
||||
terminal.print("Hello, " + name + ".");
|
||||
|
||||
for (var i = 0; i < 5; i++) {
|
||||
terminal.print(i.toString());
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(terminal.print);
|
187
packages/cory/tmirce/tmirce.js
Normal file
187
packages/cory/tmirce/tmirce.js
Normal file
@ -0,0 +1,187 @@
|
||||
"use strict";
|
||||
|
||||
//! {"permissions": ["network"], "require": ["libencoding", "libhttp"]}
|
||||
|
||||
let libhttp = require("libhttp");
|
||||
|
||||
async function getEvents() {
|
||||
let now = new Date();
|
||||
let cacheVersion = "1-" + now.toDateString();
|
||||
if (await database.get("cacheVersion") != cacheVersion) {
|
||||
terminal.print("Refreshing database...");
|
||||
let keys = await database.getAll();
|
||||
await Promise.all(keys.map(x => database.remove(x)));
|
||||
await database.set("cacheVersion", cacheVersion);
|
||||
}
|
||||
let events = [];
|
||||
let url = "https://api.meetup.com/The-Most-Informal-Running-Club-Ever-TMIRCE-Upstate/events?&sign=true&photo-host=public&status=past";
|
||||
let done = false;
|
||||
while (!done) {
|
||||
let response;
|
||||
response = await database.get(url);
|
||||
if (response) {
|
||||
response = JSON.parse(response);
|
||||
}
|
||||
if (!response) {
|
||||
response = await libhttp.get(url);
|
||||
await database.set(url, JSON.stringify(response));
|
||||
}
|
||||
let nextLink;
|
||||
let theseEvents = JSON.parse(response.body);
|
||||
for (let j in theseEvents) {
|
||||
if (new Date(theseEvents[j].time) < now) {
|
||||
events.push(theseEvents[j]);
|
||||
} else {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (let j in response.headerArray) {
|
||||
let link = response.headerArray[j];
|
||||
if (link[0] == "Link" && link[1].split("; ")[1] == 'rel="next"') {
|
||||
link = link[1].split("; ")[0];
|
||||
link = link.substring(1, link.length - 1);
|
||||
nextLink = link;
|
||||
}
|
||||
}
|
||||
if (nextLink) {
|
||||
url = nextLink;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
async function trackWorkouts(events) {
|
||||
let results = [];
|
||||
for (let i in events) {
|
||||
let event = events[i];
|
||||
if (event && event.venue && event.venue.name
|
||||
&& new Date(event.time).getDay() == 1) {
|
||||
let match = /follow (?:my|our) (.*?) workout/.exec(event.description);
|
||||
let workout;
|
||||
if (match) {
|
||||
workout = match[1];
|
||||
} else if (/snowshoe/.exec(event.description)
|
||||
|| /No run/.exec(event.description)) {
|
||||
// nothing
|
||||
} else {
|
||||
results.push(event.description);
|
||||
}
|
||||
if (workout) {
|
||||
results.push(workout);
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
async function locationByDay(day, events) {
|
||||
let results = [];
|
||||
for (let i in events) {
|
||||
let event = events[i];
|
||||
if (event && event.venue && event.venue.name
|
||||
&& new Date(event.time).getDay() == day) {
|
||||
results.push(event.venue.name);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
async function redisplay(action, filter, actions, filters, events) {
|
||||
//terminal.cork();
|
||||
terminal.clear();
|
||||
if (actions[action]) {
|
||||
terminal.setHash(action);
|
||||
terminal.print({style: "font-size: xx-large", value: action});
|
||||
}
|
||||
terminal.print("What:");
|
||||
for (let i in actions) {
|
||||
terminal.print(action == i ? "-> " : " * ", {command: i});
|
||||
}
|
||||
terminal.print("How:");
|
||||
for (let i in filters) {
|
||||
terminal.print(filter == i ? "-> " : " * ", {command: i});
|
||||
}
|
||||
terminal.print("--");
|
||||
if (actions[action]) {
|
||||
filters[filter](await actions[action](events));
|
||||
}
|
||||
//terminal.uncork();
|
||||
}
|
||||
|
||||
function rawFilter(items) {
|
||||
for (let i in items) {
|
||||
terminal.print(items[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function histogramFilter(items) {
|
||||
let table = {};
|
||||
for (let i in items) {
|
||||
if (!table[items[i]]) {
|
||||
table[items[i]] = 0;
|
||||
}
|
||||
table[items[i]] += 1;
|
||||
}
|
||||
|
||||
let results = [];
|
||||
for (let i in table) {
|
||||
results.push([table[i], i]);
|
||||
}
|
||||
results.sort((x, y) => y[0] - x[0]);
|
||||
|
||||
for (let i in results) {
|
||||
terminal.print(results[i][0].toString(), " ", results[i][1]);
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
terminal.print("loading events...");
|
||||
let events = await getEvents();
|
||||
terminal.print("loaded ", events.length.toString(), " events");
|
||||
|
||||
let actions = {
|
||||
"Sunday Locations": locationByDay.bind(null, 0),
|
||||
"Monday Track Workouts": trackWorkouts,
|
||||
"Tuesday Locations": locationByDay.bind(null, 2),
|
||||
"Wednesday Locations": locationByDay.bind(null, 3),
|
||||
"Thursday Locations": locationByDay.bind(null, 4),
|
||||
"Friday Locations": locationByDay.bind(null, 5),
|
||||
"Saturday Locations": locationByDay.bind(null, 6),
|
||||
}
|
||||
|
||||
let filters = {
|
||||
"Chronological": rawFilter,
|
||||
"Histogram": histogramFilter,
|
||||
};
|
||||
|
||||
let action = null;
|
||||
let filter = "Chronological";
|
||||
|
||||
core.register("hashChange", function(event) {
|
||||
if (event.hash && event.hash[0] == '#') {
|
||||
terminal.clear();
|
||||
let hash = event.hash.substring(1);
|
||||
if (filters[hash]) {
|
||||
filter = hash;
|
||||
} else if (actions[hash]) {
|
||||
action = hash;
|
||||
}
|
||||
redisplay(action, filter, actions, filters, events);
|
||||
}
|
||||
});
|
||||
|
||||
while (true) {
|
||||
redisplay(action, filter, actions, filters, events);
|
||||
let command = await terminal.readLine();
|
||||
if (filters[command]) {
|
||||
filter = command;
|
||||
} else if (actions[command]) {
|
||||
action = command;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(terminal.print);
|
143
packages/cory/whatnext/whatnext.js
Normal file
143
packages/cory/whatnext/whatnext.js
Normal file
@ -0,0 +1,143 @@
|
||||
"use strict";
|
||||
|
||||
//! {"require": ["ui"]}
|
||||
|
||||
terminal.setEcho(false);
|
||||
terminal.setTitle("What Next?");
|
||||
|
||||
let gEditEvent = null;
|
||||
|
||||
function back() {
|
||||
terminal.split([{name: "terminal"}]);
|
||||
if (gEditEvent) {
|
||||
gEditEvent.back();
|
||||
}
|
||||
}
|
||||
|
||||
core.register("onWindowMessage", function(event) {
|
||||
if (event.message.ready) {
|
||||
terminal.postMessageToIframe("iframe", {title: gEditEvent.name, contents: gEditEvent.value});
|
||||
} else if (event.message.index) {
|
||||
back();
|
||||
} else {
|
||||
gEditEvent.save(event.message.title, event.message.contents).then(back);
|
||||
}
|
||||
});
|
||||
|
||||
function editPage(event) {
|
||||
gEditEvent = event;
|
||||
terminal.split([{name: "terminal", type: "vertical"}]);
|
||||
terminal.clear();
|
||||
terminal.print({iframe: `<html>
|
||||
<head>
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/codemirror/5.13.2/codemirror.min.js"></script>
|
||||
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/codemirror/5.13.2/codemirror.min.css"></link>
|
||||
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/codemirror/5.13.2/theme/base16-dark.min.css"></link>
|
||||
<style>
|
||||
html {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#menu {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
#container {
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
background-color: white;
|
||||
}
|
||||
.CodeMirror {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.CodeMirror-scroll {
|
||||
}
|
||||
|
||||
.cm-tab {
|
||||
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAYAAAAkuj5RAAAAAXNSR0IArs4c6QAAAGFJREFUSMft1LsRQFAQheHPowAKoACx3IgEKtaEHujDjORSgWTH/ZOdnZOcM/sgk/kFFWY0qV8foQwS4MKBCS3qR6ixBJvElOobYAtivseIE120FaowJPN75GMu8j/LfMwNjh4HUpwg4LUAAAAASUVORK5CYII=);
|
||||
background-position: right;
|
||||
background-repeat: no-repeat;
|
||||
-webkit-filter: invert(100%);
|
||||
filter: invert(100%);
|
||||
}
|
||||
|
||||
.cm-trailingspace {
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAACCAYAAAB/qH1jAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QUXCToH00Y1UgAAACFJREFUCNdjPMDBUc/AwNDAAAFMTAwMDA0OP34wQgX/AQBYgwYEx4f9lQAAAABJRU5ErkJggg==);
|
||||
background-position: bottom left;
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
#edit { background-color: white }
|
||||
#preview { background-color: white }
|
||||
#edit, #preview {
|
||||
display: flex;
|
||||
overflow: auto;
|
||||
flex: 0 0 50%;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
var gEditor;
|
||||
function index() {
|
||||
parent.postMessage({index: true}, "*");
|
||||
}
|
||||
function submit() {
|
||||
var contents = gEditor.getValue();
|
||||
var lines = contents.split("\\n");
|
||||
var title = lines[0].trim();
|
||||
parent.postMessage({
|
||||
title: title,
|
||||
contents: contents,
|
||||
}, "*");
|
||||
}
|
||||
function textChanged() {
|
||||
var preview = document.getElementById("preview");
|
||||
preview.innerText = gEditor.getValue();
|
||||
}
|
||||
window.addEventListener("message", function(message) {
|
||||
gEditor.setValue(message.data.contents);
|
||||
textChanged();
|
||||
}, false);
|
||||
|
||||
window.addEventListener("load", function() {
|
||||
gEditor = CodeMirror.fromTextArea(document.getElementById("contents"), {
|
||||
theme: 'base16-dark',
|
||||
lineNumbers: true,
|
||||
tabSize: 4,
|
||||
intentUnit: 4,
|
||||
indentWithTabs: true,
|
||||
showTrailingSpace: true,
|
||||
});
|
||||
gEditor.on("change", textChanged);
|
||||
});
|
||||
|
||||
parent.postMessage({ready: true}, "*");
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="menu">
|
||||
<input type="button" value="Back" onclick="index()">
|
||||
` + (core.user.credentials.permissions && core.user.credentials.permissions.authenticated ? `
|
||||
<input type="button" value="Save" onclick="submit()">
|
||||
` : "") + `
|
||||
</div>
|
||||
<div id="container">
|
||||
<div id="edit"><textarea id="contents" oninput="textChanged()"></textarea></div>
|
||||
<div id="preview"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>`, name: "iframe", style: "flex: 1 1 auto; border: 0; width: 100%"});
|
||||
}
|
||||
|
||||
require("ui").fileList({
|
||||
title: "What Next?",
|
||||
edit: editPage,
|
||||
});
|
@ -32,6 +32,7 @@ function editPage(event) {
|
||||
<head>
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/codemirror/5.13.2/codemirror.min.js"></script>
|
||||
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/codemirror/5.13.2/codemirror.min.css"></link>
|
||||
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/codemirror/5.13.2/theme/base16-dark.min.css"></link>
|
||||
<style>
|
||||
html {
|
||||
height: 100%;
|
||||
@ -61,6 +62,20 @@ function editPage(event) {
|
||||
}
|
||||
.CodeMirror-scroll {
|
||||
}
|
||||
|
||||
.cm-tab {
|
||||
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAYAAAAkuj5RAAAAAXNSR0IArs4c6QAAAGFJREFUSMft1LsRQFAQheHPowAKoACx3IgEKtaEHujDjORSgWTH/ZOdnZOcM/sgk/kFFWY0qV8foQwS4MKBCS3qR6ixBJvElOobYAtivseIE120FaowJPN75GMu8j/LfMwNjh4HUpwg4LUAAAAASUVORK5CYII=);
|
||||
background-position: right;
|
||||
background-repeat: no-repeat;
|
||||
-webkit-filter: invert(100%);
|
||||
filter: invert(100%);
|
||||
}
|
||||
|
||||
.cm-trailingspace {
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAACCAYAAAB/qH1jAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QUXCToH00Y1UgAAACFJREFUCNdjPMDBUc/AwNDAAAFMTAwMDA0OP34wQgX/AQBYgwYEx4f9lQAAAABJRU5ErkJggg==);
|
||||
background-position: bottom left;
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
#edit { background-color: white }
|
||||
#preview { background-color: white }
|
||||
#edit, #preview {
|
||||
@ -98,7 +113,12 @@ function editPage(event) {
|
||||
|
||||
window.addEventListener("load", function() {
|
||||
gEditor = CodeMirror.fromTextArea(document.getElementById("contents"), {
|
||||
lineNumbers: true
|
||||
theme: 'base16-dark',
|
||||
lineNumbers: true,
|
||||
tabSize: 4,
|
||||
intentUnit: 4,
|
||||
indentWithTabs: true,
|
||||
showTrailingSpace: true,
|
||||
});
|
||||
gEditor.on("change", textChanged);
|
||||
});
|
||||
|
176
packages/cory/xmas2016/xmas2016.js
Normal file
176
packages/cory/xmas2016/xmas2016.js
Normal file
@ -0,0 +1,176 @@
|
||||
"use strict";
|
||||
|
||||
const kWidth = 15;
|
||||
const kHeight = 10;
|
||||
|
||||
class Client {
|
||||
async start() {
|
||||
let self = this;
|
||||
terminal.setTitle("Xmas 2016");
|
||||
terminal.setSendKeyEvents(true);
|
||||
terminal.split([{name: "terminal", style: "text-align: center"}]);
|
||||
self.send({action: "ready"});
|
||||
|
||||
core.register("key", function(event) {
|
||||
if (event.type == "keydown") {
|
||||
switch (event.keyCode) {
|
||||
case 37:
|
||||
self.requestMove(-1, 0);
|
||||
break;
|
||||
case 38:
|
||||
self.requestMove(0, -1);
|
||||
break;
|
||||
case 39:
|
||||
self.requestMove(1, 0);
|
||||
break;
|
||||
case 40:
|
||||
self.requestMove(0, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
core.register("onMessage", function(sender, message) {
|
||||
if (message.action == "display") {
|
||||
terminal.cork();
|
||||
terminal.clear();
|
||||
terminal.print(message.board);
|
||||
terminal.uncork();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async send(message) {
|
||||
(await core.getService("server")).postMessage(message);
|
||||
}
|
||||
|
||||
async requestMove(dx, dy) {
|
||||
this.send({action: "move", delta: [dx, dy]});
|
||||
}
|
||||
}
|
||||
|
||||
class Server {
|
||||
constructor() {
|
||||
this.players = {};
|
||||
}
|
||||
|
||||
async start() {
|
||||
let self = this;
|
||||
core.register("onMessage", function(sender, message) {
|
||||
if (!self.players[sender.index]) {
|
||||
self.players[sender.index] = [Math.floor(Math.random() * 8) + 1, 8];
|
||||
}
|
||||
switch (message.action) {
|
||||
case "move":
|
||||
self.move(sender.index, message.delta);
|
||||
self.redisplay();
|
||||
break;
|
||||
case "ready":
|
||||
self.redisplay();
|
||||
break;
|
||||
}
|
||||
});
|
||||
core.register("onSessionEnd", function(session) {
|
||||
delete self.players[session.index];
|
||||
self.redisplay();
|
||||
});
|
||||
}
|
||||
|
||||
occupied(position) {
|
||||
if (position[0] < 1 || position[1] < 1 || position[0] >= kWidth - 1 || position[1] >= kHeight - 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Object.values(this.players).some(x => position[0] == x[0] && position[1] == x[1])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
move(index, delta) {
|
||||
let newPosition = [
|
||||
this.players[index][0] + delta[0],
|
||||
this.players[index][1] + delta[1],
|
||||
];
|
||||
let pushPosition = [
|
||||
this.players[index][0] + 2 * delta[0],
|
||||
this.players[index][1] + 2 * delta[1],
|
||||
];
|
||||
if (!this.occupied(newPosition)) {
|
||||
this.players[index] = newPosition;
|
||||
} else if (this.occupied(newPosition) && !this.occupied(pushPosition)) {
|
||||
for (var i in this.players) {
|
||||
if (this.players[i][0] == newPosition[0] && this.players[i][1] == newPosition[1]) {
|
||||
this.players[i] = pushPosition;
|
||||
}
|
||||
}
|
||||
this.players[index] = newPosition;
|
||||
}
|
||||
}
|
||||
|
||||
redisplay() {
|
||||
core.broadcast({action: "display", board: this.getBoard()});
|
||||
}
|
||||
|
||||
getBoard() {
|
||||
let board = [
|
||||
"┌─────────────┐",
|
||||
"│ . │",
|
||||
"│ .#. │",
|
||||
"│ .%##. │",
|
||||
"│ .##%##. │",
|
||||
"│ .%###%##. │",
|
||||
"│ .##%###%##. │",
|
||||
"│.#%##%###%##.│",
|
||||
"│ | │",
|
||||
"└─────────────┘",
|
||||
];
|
||||
let merry = false;
|
||||
let colors = board.map(x => x.split("").map(y => '#fff'));
|
||||
for (let i in this.players) {
|
||||
let player = this.players[i];
|
||||
merry = merry || (player[0] == 7 && player[1] == 1);
|
||||
let character = player[0] == 7 && player[1] == 1 ? '*' : '@';
|
||||
board[player[1]] = board[player[1]].slice(0, player[0]) + character + board[player[1]].slice(player[0] + 1);
|
||||
}
|
||||
if (merry) {
|
||||
for (let i = 0; i < colors.length; i++) {
|
||||
for (let j = 0; j < colors[i].length; j++) {
|
||||
switch (board[i].charAt(j)) {
|
||||
case '#':
|
||||
case '.':
|
||||
colors[i][j] = '#080';
|
||||
break;
|
||||
case '%':
|
||||
colors[i][j] = '#f00';
|
||||
break;
|
||||
case '|':
|
||||
colors[i][j] = '#880';
|
||||
break;
|
||||
case '*':
|
||||
colors[i][j] = '#ff0';
|
||||
break;
|
||||
case '@':
|
||||
{
|
||||
const palette = ['#f88', '#8f8', '#88f', '#fff'];
|
||||
colors[i][j] = palette[(i * colors.length + j) % palette.length];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let result = board.map((r, row) => r.split("").map((v, column) => ({style: "color: " + colors[row][column], value: v})).concat(["\n"]));
|
||||
if (merry) {
|
||||
result.push("Merry Christmas!");
|
||||
} else {
|
||||
result.push("use ←↑→↓");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (imports.terminal) {
|
||||
new Client().start().catch(terminal.print);
|
||||
} else {
|
||||
new Server().start().catch(print);
|
||||
}
|
63
packages/cory/youtube/youtube.js
Normal file
63
packages/cory/youtube/youtube.js
Normal file
@ -0,0 +1,63 @@
|
||||
terminal.print({iframe: `
|
||||
<style>
|
||||
html, body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
<!-- 1. The <iframe> (and video player) will replace this <div> tag. -->
|
||||
<div id="player"></div>
|
||||
|
||||
<script>
|
||||
// 2. This code loads the IFrame Player API code asynchronously.
|
||||
var tag = document.createElement('script');
|
||||
|
||||
tag.src = "https://www.youtube.com/iframe_api";
|
||||
var firstScriptTag = document.getElementsByTagName('script')[0];
|
||||
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
|
||||
|
||||
// 3. This function creates an <iframe> (and YouTube player)
|
||||
// after the API code downloads.
|
||||
var player;
|
||||
function onYouTubeIframeAPIReady() {
|
||||
player = new YT.Player('player', {
|
||||
height: '390',
|
||||
width: '640',
|
||||
videoId: 'M7lc1UVf-VE',
|
||||
events: {
|
||||
'onReady': onPlayerReady,
|
||||
'onStateChange': onPlayerStateChange
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 4. The API will call this function when the video player is ready.
|
||||
function onPlayerReady(event) {
|
||||
event.target.playVideo();
|
||||
}
|
||||
|
||||
// 5. The API calls this function when the player's state changes.
|
||||
// The function indicates that when playing a video (state=1),
|
||||
// the player should play for six seconds and then stop.
|
||||
var done = false;
|
||||
function onPlayerStateChange(event) {
|
||||
parent.postMessage({
|
||||
state: event.data,
|
||||
url: event.target.getVideoUrl(),
|
||||
}, "*");
|
||||
if (event.data == YT.PlayerState.PLAYING && !done) {
|
||||
setTimeout(stopVideo, 6000);
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
function stopVideo() {
|
||||
player.stopVideo();
|
||||
}
|
||||
</script>
|
||||
`, width: 640, height: 390, style: "padding: 0; margin: 0; border: 0"});
|
||||
|
||||
terminal.print("hi");
|
||||
core.register("onWindowMessage", function(event) {
|
||||
terminal.print("message", JSON.stringify(event.message));
|
||||
});
|
14
src/Tls.cpp
14
src/Tls.cpp
@ -67,11 +67,23 @@ TlsSession* TlsContext_openssl::createSession() {
|
||||
return new TlsSession_openssl(this);
|
||||
}
|
||||
|
||||
#include <iostream>
|
||||
|
||||
TlsContext_openssl::TlsContext_openssl() {
|
||||
SSL_library_init();
|
||||
SSL_load_error_strings();
|
||||
|
||||
_context = SSL_CTX_new(SSLv23_method());
|
||||
const SSL_METHOD* method = SSLv23_method();
|
||||
if (!method)
|
||||
{
|
||||
std::cerr << "SSLv23_method returned NULL\n";
|
||||
}
|
||||
|
||||
_context = SSL_CTX_new(method);
|
||||
if (!_context)
|
||||
{
|
||||
std::cerr << "SSL_CTX_new returned NULL\n";
|
||||
}
|
||||
SSL_CTX_set_default_verify_paths(_context);
|
||||
}
|
||||
|
||||
|
@ -22,3 +22,4 @@ certbot renew \
|
||||
--work-dir data/global/letsencrypt/work \
|
||||
--cert-path data/global/httpd/certificate.pem \
|
||||
--key-path data/global/httpd/privatekey.pem \
|
||||
$*
|
||||
|
Loading…
Reference in New Issue
Block a user