added sarah

This commit is contained in:
user 2020-10-16 18:36:19 +02:00
parent 66527b9311
commit 02f2f3836f
20 changed files with 1562 additions and 0 deletions

View File

@ -0,0 +1,166 @@
#include "./DNSServer.h"
#include <lwip/def.h>
#include <Arduino.h>
#define DEBUG
#define DEBUG_OUTPUT Serial
DNSServer::DNSServer()
{
_ttl = htonl(60);
_errorReplyCode = DNSReplyCode::NonExistentDomain;
}
bool DNSServer::start(const uint16_t &port, const String &domainName,
const IPAddress &resolvedIP)
{
_port = port;
_domainName = domainName;
_resolvedIP[0] = resolvedIP[0];
_resolvedIP[1] = resolvedIP[1];
_resolvedIP[2] = resolvedIP[2];
_resolvedIP[3] = resolvedIP[3];
downcaseAndRemoveWwwPrefix(_domainName);
return _udp.begin(_port) == 1;
}
void DNSServer::setErrorReplyCode(const DNSReplyCode &replyCode)
{
_errorReplyCode = replyCode;
}
void DNSServer::setTTL(const uint32_t &ttl)
{
_ttl = htonl(ttl);
}
void DNSServer::stop()
{
_udp.stop();
}
void DNSServer::downcaseAndRemoveWwwPrefix(String &domainName)
{
domainName.toLowerCase();
domainName.replace("www.", "");
domainName.replace("https://", "");
}
void DNSServer::processNextRequest()
{
_currentPacketSize = _udp.parsePacket();
if (_currentPacketSize)
{
_buffer = (unsigned char*)malloc(_currentPacketSize * sizeof(char));
_udp.read(_buffer, _currentPacketSize);
_dnsHeader = (DNSHeader*) _buffer;
if (_dnsHeader->QR == DNS_QR_QUERY &&
_dnsHeader->OPCode == DNS_OPCODE_QUERY &&
requestIncludesOnlyOneQuestion() &&
(_domainName == "*" || getDomainNameWithoutWwwPrefix() == _domainName)
)
{
replyWithIP();
}
else if (_dnsHeader->QR == DNS_QR_QUERY)
{
replyWithCustomCode();
}
free(_buffer);
}
}
bool DNSServer::requestIncludesOnlyOneQuestion()
{
return ntohs(_dnsHeader->QDCount) == 1 &&
_dnsHeader->ANCount == 0 &&
_dnsHeader->NSCount == 0 &&
_dnsHeader->ARCount == 0;
}
String DNSServer::getDomainNameWithoutWwwPrefix()
{
String parsedDomainName = "";
unsigned char *start = _buffer + 12;
if (*start == 0)
{
return parsedDomainName;
}
int pos = 0;
while(true)
{
unsigned char labelLength = *(start + pos);
for(int i = 0; i < labelLength; i++)
{
pos++;
parsedDomainName += (char)*(start + pos);
}
pos++;
if (*(start + pos) == 0)
{
downcaseAndRemoveWwwPrefix(parsedDomainName);
return parsedDomainName;
}
else
{
parsedDomainName += ".";
}
}
}
void DNSServer::replyWithIP()
{
_dnsHeader->QR = DNS_QR_RESPONSE;
_dnsHeader->ANCount = _dnsHeader->QDCount;
_dnsHeader->QDCount = _dnsHeader->QDCount;
//_dnsHeader->RA = 1;
_udp.beginPacket(_udp.remoteIP(), _udp.remotePort());
_udp.write(_buffer, _currentPacketSize);
_udp.write((uint8_t)192); // answer name is a pointer
_udp.write((uint8_t)12); // pointer to offset at 0x00c
_udp.write((uint8_t)0); // 0x0001 answer is type A query (host address)
_udp.write((uint8_t)1);
_udp.write((uint8_t)0); //0x0001 answer is class IN (internet address)
_udp.write((uint8_t)1);
_udp.write((unsigned char*)&_ttl, 4);
// Length of RData is 4 bytes (because, in this case, RData is IPv4)
_udp.write((uint8_t)0);
_udp.write((uint8_t)4);
_udp.write(_resolvedIP, sizeof(_resolvedIP));
_udp.endPacket();
#ifdef DEBUG
DEBUG_OUTPUT.print("DNS responds: ");
DEBUG_OUTPUT.print(_resolvedIP[0]);
DEBUG_OUTPUT.print(".");
DEBUG_OUTPUT.print(_resolvedIP[1]);
DEBUG_OUTPUT.print(".");
DEBUG_OUTPUT.print(_resolvedIP[2]);
DEBUG_OUTPUT.print(".");
DEBUG_OUTPUT.print(_resolvedIP[3]);
DEBUG_OUTPUT.print(" for ");
DEBUG_OUTPUT.println(getDomainNameWithoutWwwPrefix());
#endif
}
void DNSServer::replyWithCustomCode()
{
_dnsHeader->QR = DNS_QR_RESPONSE;
_dnsHeader->RCode = (unsigned char)_errorReplyCode;
_dnsHeader->QDCount = 0;
_udp.beginPacket(_udp.remoteIP(), _udp.remotePort());
_udp.write(_buffer, sizeof(DNSHeader));
_udp.endPacket();
}

View File

@ -0,0 +1,72 @@
#ifndef DNSServer_h
#define DNSServer_h
#include <WiFiUdp.h>
#define DNS_QR_QUERY 0
#define DNS_QR_RESPONSE 1
#define DNS_OPCODE_QUERY 0
enum class DNSReplyCode
{
NoError = 0,
FormError = 1,
ServerFailure = 2,
NonExistentDomain = 3,
NotImplemented = 4,
Refused = 5,
YXDomain = 6,
YXRRSet = 7,
NXRRSet = 8
};
struct DNSHeader
{
uint16_t ID; // identification number
unsigned char RD : 1; // recursion desired
unsigned char TC : 1; // truncated message
unsigned char AA : 1; // authoritive answer
unsigned char OPCode : 4; // message_type
unsigned char QR : 1; // query/response flag
unsigned char RCode : 4; // response code
unsigned char Z : 3; // its z! reserved
unsigned char RA : 1; // recursion available
uint16_t QDCount; // number of question entries
uint16_t ANCount; // number of answer entries
uint16_t NSCount; // number of authority entries
uint16_t ARCount; // number of resource entries
};
class DNSServer
{
public:
DNSServer();
void processNextRequest();
void setErrorReplyCode(const DNSReplyCode &replyCode);
void setTTL(const uint32_t &ttl);
// Returns true if successful, false if there are no sockets available
bool start(const uint16_t &port,
const String &domainName,
const IPAddress &resolvedIP);
// stops the DNS server
void stop();
private:
WiFiUDP _udp;
uint16_t _port;
String _domainName;
unsigned char _resolvedIP[4];
int _currentPacketSize;
unsigned char* _buffer;
DNSHeader* _dnsHeader;
uint32_t _ttl;
DNSReplyCode _errorReplyCode;
void downcaseAndRemoveWwwPrefix(String &domainName);
String getDomainNameWithoutWwwPrefix();
bool requestIncludesOnlyOneQuestion();
void replyWithIP();
void replyWithCustomCode();
};
#endif

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 357 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

View File

@ -0,0 +1,399 @@
<!doctype html>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
h1 {
font-size: 3em;
}
img {
max-width: 100%;
/*position: absolute;*/
}
.rel {
position: relative;
}
#capture {
height: 100vh;
}
.text {
position: absolute;
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
z-index: -1;
}
.text > div {
/*font-size: 20px;*/
font-family: monospace;
color: #695858;
letter-spacing: .1em;
padding: 13px;
transform: rotate(355deg);
}
#button-wrapper {
position: fixed;
top: 300px;
left: 0;
width: 250px;
animation: translate 20s infinite linear;
z-index: 9999;
}
#imgButton {
background: linear-gradient(to right, #CB3066, #16BFFD);
background-size: 300% 300%;
color: #fff;
font-size: 18px;
line-height: 30px;
padding: 10px 30px;
text-decoration: none;
display: inline-block;
text-transform: uppercase;
position: absolute;
left: -300px;
border: 0;
outline: 0;
box-shadow: 0 5px 10px 0 rgba(205, 209, 215, 0.8);
animation: gradient 2.5s ease infinite, inmotion 1.5s alternate infinite ease-in-out;
}
@keyframes translate {
to { transform: translateX(200%); }
}
@keyframes inmotion {
to { transform: translateY(100px); }
}
@keyframes gradient {
0% { background-position: 0% 50% }
50% { background-position: 100% 50% }
100% { background-position: 0% 50% }
}
</style>
</div>
<body id="capture">
<div id="button-wrapper">
<button id="imgButton">CLICK TO SAVE YOUR KATAMARI</button>
</div>
<div class="text">
<div>Bouchéstraße</div>
<div>Alt-Treptow</div>
<div>Berlin</div>
<div>Kiefholzstraße</div>
<div>Elsenstraße</div>
<div>Harzer Straße</div>
<div>Wildenbruchstraße</div>
<div>Heidelberger Straße</div>
<div>Karl-Kunger-Straße</div>
<div>Sülzhayner Straße</div>
<div>Schmollerstraße</div>
<div>Mengerzeile</div>
<div>Am Treptower Park</div>
<div>Puschkinallee</div>
<div>Martin-Hoffman-Straße</div>
<div>Eichenstraße</div>
<div>Fanny-Zobel-Straße</div>
<div>Matthesstraße</div>
<div>Beermannstraße</div>
<div>Jordanstraße</div>
<div>Lohmühlenstraße</div>
<div>Am Flutgraben</div>
<div>Schleusenufer</div>
<div>Landwehr Canal</div>
<div>Spree</div>
<div>Treptower Park</div>
<div>Rummelsburger See</div>
<div>Schlesisches Tor</div>
<div>Skalitzer Straße</div>
<div>Köpenicker Straße</div>
<div>Brückenstraße</div>
<div>Rungestraße</div>
<div>Ohmstraße</div>
<div>Michaelkirchstraße</div>
<div>Michaelkirchplatz</div>
<div>Heinrich-Heine-Straße</div>
<div>Jannowitzbrücke</div>
<div>Schlesisches Straße</div>
<div>Cuvrystraße</div>
<div>Wrangelstraße</div>
<div>Taborstraße</div>
<div>Heckmannufer</div>
<div>Görlitzer Ufer</div>
<div>Görlitzer Park</div>
<div>Falckenstein Straße</div>
<div>Oppelner Straße</div>
<div>Sorauer Straße</div>
<div>Lübbener Straße</div>
<div>Plesser Straße</div>
<div>Krüllsstraße</div>
<div>Kiehlufer</div>
<div>Treptower Straße</div>
<div>Hüttenroder Weg</div>
<div>Onckenstraße</div>
<div>Lexisstraße</div>
<div>Grabowstraße</div>
<div>Wiener Straße</div>
<div>Reichenberger Straße</div>
<div>Paul-Lincke-Ufer</div>
<div>Glogauer Straße</div>
<div>Liegnitzer Straße</div>
<div>Forster Straße</div>
<div>Ohlauer Straße</div>
<div>Lausitzer Straße</div>
<div>Manteuffelstraße</div>
<div>Mariannenstraße</div>
<div>Muskauer Straße</div>
<div>Warschauer Straße</div>
<div>Revaler Straße</div>
<div>Simon-Dach-Straße</div>
<div>Boxhagener Platz</div>
<div>Kreuzberg</div>
<div>Neukölln</div>
<div>Bouchéstraße</div>
<div>Alt-Treptow</div>
<div>Berlin</div>
<div>Kiefholzstraße</div>
<div>Elsenstraße</div>
<div>Harzer Straße</div>
<div>Wildenbruchstraße</div>
<div>Heidelberger Straße</div>
<div>Karl-Kunger-Straße</div>
<div>Sülzhayner Straße</div>
<div>Schmollerstraße</div>
<div>Mengerzeile</div>
<div>Am Treptower Park</div>
<div>Puschkinallee</div>
<div>Martin-Hoffman-Straße</div>
<div>Eichenstraße</div>
<div>Fanny-Zobel-Straße</div>
<div>Matthesstraße</div>
<div>Beermannstraße</div>
<div>Jordanstraße</div>
<div>Lohmühlenstraße</div>
<div>Am Flutgraben</div>
<div>Schleusenufer</div>
<div>Landwehr Canal</div>
<div>Spree</div>
<div>Treptower Park</div>
<div>Rummelsburger See</div>
<div>Schlesisches Tor</div>
<div>Skalitzer Straße</div>
<div>Köpenicker Straße</div>
<div>Brückenstraße</div>
<div>Rungestraße</div>
<div>Ohmstraße</div>
<div>Michaelkirchstraße</div>
<div>Michaelkirchplatz</div>
<div>Heinrich-Heine-Straße</div>
<div>Jannowitzbrücke</div>
<div>Schlesisches Straße</div>
<div>Cuvrystraße</div>
<div>Wrangelstraße</div>
<div>Taborstraße</div>
<div>Heckmannufer</div>
<div>Görlitzer Ufer</div>
<div>Görlitzer Park</div>
<div>Falckenstein Straße</div>
<div>Oppelner Straße</div>
<div>Sorauer Straße</div>
<div>Lübbener Straße</div>
<div>Plesser Straße</div>
<div>Krüllsstraße</div>
<div>Kiehlufer</div>
<div>Treptower Straße</div>
<div>Hüttenroder Weg</div>
<div>Onckenstraße</div>
<div>Lexisstraße</div>
<div>Grabowstraße</div>
<div>Wiener Straße</div>
<div>Reichenberger Straße</div>
<div>Paul-Lincke-Ufer</div>
<div>Glogauer Straße</div>
<div>Liegnitzer Straße</div>
<div>Forster Straße</div>
<div>Ohlauer Straße</div>
<div>Lausitzer Straße</div>
<div>Manteuffelstraße</div>
<div>Mariannenstraße</div>
<div>Muskauer Straße</div>
<div>Warschauer Straße</div>
<div>Revaler Straße</div>
<div>Simon-Dach-Straße</div>
<div>Boxhagener Platz</div>
<div>Kreuzberg</div>
<div>Neukölln</div>
<div>Bouchéstraße</div>
<div>Alt-Treptow</div>
<div>Berlin</div>
<div>Kiefholzstraße</div>
<div>Elsenstraße</div>
<div>Harzer Straße</div>
<div>Wildenbruchstraße</div>
<div>Heidelberger Straße</div>
<div>Karl-Kunger-Straße</div>
<div>Sülzhayner Straße</div>
<div>Schmollerstraße</div>
<div>Mengerzeile</div>
<div>Am Treptower Park</div>
<div>Puschkinallee</div>
<div>Martin-Hoffman-Straße</div>
<div>Eichenstraße</div>
<div>Fanny-Zobel-Straße</div>
<div>Matthesstraße</div>
<div>Beermannstraße</div>
<div>Jordanstraße</div>
<div>Lohmühlenstraße</div>
<div>Am Flutgraben</div>
<div>Schleusenufer</div>
<div>Landwehr Canal</div>
<div>Spree</div>
<div>Treptower Park</div>
<div>Rummelsburger See</div>
<div>Schlesisches Tor</div>
<div>Skalitzer Straße</div>
<div>Köpenicker Straße</div>
<div>Brückenstraße</div>
<div>Rungestraße</div>
<div>Ohmstraße</div>
<div>Michaelkirchstraße</div>
<div>Michaelkirchplatz</div>
<div>Heinrich-Heine-Straße</div>
<div>Jannowitzbrücke</div>
<div>Schlesisches Straße</div>
<div>Cuvrystraße</div>
<div>Wrangelstraße</div>
<div>Taborstraße</div>
<div>Heckmannufer</div>
<div>Görlitzer Ufer</div>
<div>Görlitzer Park</div>
<div>Falckenstein Straße</div>
<div>Oppelner Straße</div>
<div>Sorauer Straße</div>
<div>Lübbener Straße</div>
<div>Plesser Straße</div>
<div>Krüllsstraße</div>
<div>Kiehlufer</div>
<div>Treptower Straße</div>
<div>Hüttenroder Weg</div>
<div>Onckenstraße</div>
<div>Lexisstraße</div>
<div>Grabowstraße</div>
<div>Wiener Straße</div>
<div>Reichenberger Straße</div>
<div>Paul-Lincke-Ufer</div>
<div>Glogauer Straße</div>
<div>Liegnitzer Straße</div>
<div>Forster Straße</div>
<div>Ohlauer Straße</div>
<div>Lausitzer Straße</div>
<div>Manteuffelstraße</div>
<div>Mariannenstraße</div>
<div>Muskauer Straße</div>
<div>Warschauer Straße</div>
<div>Revaler Straße</div>
<div>Simon-Dach-Straße</div>
<div>Boxhagener Platz</div>
<div>Kreuzberg</div>
<div>Neukölln</div>
<div>Bouchéstraße</div>
<div>Alt-Treptow</div>
<div>Berlin</div>
<div>Kiefholzstraße</div>
<div>Elsenstraße</div>
<div>Harzer Straße</div>
<div>Wildenbruchstraße</div>
<div>Heidelberger Straße</div>
<div>Karl-Kunger-Straße</div>
<div>Sülzhayner Straße</div>
<div>Schmollerstraße</div>
<div>Mengerzeile</div>
<div>Am Treptower Park</div>
<div>Puschkinallee</div>
<div>Martin-Hoffman-Straße</div>
<div>Eichenstraße</div>
<div>Fanny-Zobel-Straße</div>
<div>Matthesstraße</div>
<div>Beermannstraße</div>
<div>Jordanstraße</div>
<div>Lohmühlenstraße</div>
<div>Am Flutgraben</div>
<div>Schleusenufer</div>
<div>Landwehr Canal</div>
<div>Spree</div>
<div>Treptower Park</div>
<div>Rummelsburger See</div>
<div>Schlesisches Tor</div>
<div>Skalitzer Straße</div>
<div>Köpenicker Straße</div>
<div>Brückenstraße</div>
<div>Rungestraße</div>
<div>Ohmstraße</div>
<div>Michaelkirchstraße</div>
<div>Michaelkirchplatz</div>
<div>Heinrich-Heine-Straße</div>
<div>Jannowitzbrücke</div>
<div>Schlesisches Straße</div>
<div>Cuvrystraße</div>
<div>Wrangelstraße</div>
<div>Taborstraße</div>
<div>Heckmannufer</div>
<div>Görlitzer Ufer</div>
<div>Görlitzer Park</div>
<div>Falckenstein Straße</div>
<div>Oppelner Straße</div>
<div>Sorauer Straße</div>
<div>Lübbener Straße</div>
<div>Plesser Straße</div>
<div>Krüllsstraße</div>
<div>Kiehlufer</div>
<div>Treptower Straße</div>
<div>Hüttenroder Weg</div>
<div>Onckenstraße</div>
<div>Lexisstraße</div>
<div>Grabowstraße</div>
<div>Wiener Straße</div>
<div>Reichenberger Straße</div>
<div>Paul-Lincke-Ufer</div>
<div>Glogauer Straße</div>
<div>Liegnitzer Straße</div>
<div>Forster Straße</div>
<div>Ohlauer Straße</div>
<div>Lausitzer Straße</div>
<div>Manteuffelstraße</div>
<div>Mariannenstraße</div>
<div>Muskauer Straße</div>
<div>Warschauer Straße</div>
<div>Revaler Straße</div>
<div>Simon-Dach-Straße</div>
<div>Boxhagener Platz</div>
<div>Kreuzberg</div>
<div>Neukölln</div>
</div>
<div>
<marquee><i><h1>PLAGUE RAVE 2020&nbsp;<progress></progress></h1></i></marquee>
<div class="rel">
<img src="img/mask.gif" />
<br/>
<img src="img/berghain.gif" />
</br>
<img src="img/TIER-scooter-final-1024x1024.png" />
</div>
<marquee><i><h1><progress></progress>&nbsp;PLAGUE RAVE 2020</h1></i></marquee>
<div class="rel">
<img src="img/source.gif" />
<img class="left" src="img/thumbnail.gif" />
<img src="img/Berlin_TV_Tower.png" />
</div>
<marquee><i><h1><progress></progress>&nbsp;PLAGUE RAVE 2020</h1></i></marquee>
</div>
<script type='text/javascript' src='js/jquery-3.5.1.slim.min.js'></script>
<script type='text/javascript' src='js/howler.min.js'></script>
<script type='text/javascript' src='js/html2canvas.min.js'></script>
<script type='text/javascript' src='js/kh.js'></script>
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,801 @@
/* PLAGUE RAVE 2020 by chootka for e-ridin`dirty / OPENCOIL 2020 * Dennis de Bel * Anton ???
Adapted from kathack.com, Alex Leone, David Nufer, David Truong, &copy; 2011-03-11 */
var CSS_TRANSFORM = null,
CSS_TRANSFORM_ORIGIN = null,
POSSIBLE_TRANSFORM_PREFIXES = ['-webkit-', '-moz-', '-o-', '-ms-', ''],
khFirst = false,
vibrateInterval = null;
/* When running twice on one page, update pick-uppable nodes instead of
* creating more.
*/
if (!window.khNodes) {
khFirst = true;
window.khNodes = new StickyNodes();
}
function getCssTransform() {
var i, d = document.createElement('div'), pre;
for (i = 0; i < POSSIBLE_TRANSFORM_PREFIXES.length; i++) {
pre = POSSIBLE_TRANSFORM_PREFIXES[i];
d.style.setProperty(pre + 'transform', 'rotate(1rad) scaleX(2)', null);
if (d.style.getPropertyValue(pre + 'transform')) {
CSS_TRANSFORM = pre + 'transform';
CSS_TRANSFORM_ORIGIN = pre + 'transform-origin';
return;
}
}
alert("Your browser doesn't support CSS tranforms!");
throw "Your browser doesn't support CSS tranforms!";
}
getCssTransform();
/**
* Vibration support
*/
// Starts vibration at passed in level
function startVibrate(duration) {
navigator.vibrate(duration);
}
// Stops vibration
function stopVibrate() {
// Clear interval and stop persistent vibrating
if(vibrateInterval) clearInterval(vibrateInterval);
navigator.vibrate(0);
}
// Start persistent vibration at given duration and interval
// Assumes a number value is given
function startPeristentVibrate(duration, interval) {
vibrateInterval = setInterval(function() {
startVibrate(duration);
}, interval);
}
/**
* Returns true if the circle intersects the element rectangle.
* 0 | 1 | 2
* ------------------
* 3 | 4 | 5
* ------------------
* 6 | 7 | 9
*/
function circleGridObjInt(cx, cy, cr, cr2, go) {
var dx, dy;
if (cx < go.left) {
dx = go.left - cx;
if (cy < go.top) { /* zone 0. */
dy = go.top - cy;
return ((dx * dx + dy * dy) <= cr2);
} else if (cy <= go.bottom) { /* zone 3. */
return (dx <= cr);
} else { /* zone 6. */
dy = cy - go.bottom;
return ((dx * dx + dy * dy) <= cr2);
}
} else if (cx <= go.right) {
if (cy < go.top) { /* zone 1. */
return ((go.top - cy) <= cr);
} else if (cy <= go.bottom) { /* zone 4. */
return true;
} else { /* zone 7. */
return ((cy - go.bottom) <= cr);
}
} else {
dx = cx - go.right;
if (cy < go.top) { /* zone 2. */
dy = go.top - cy;
return ((dx * dx + dy * dy) <= cr2);
} else if (cy <= go.bottom) { /* zone 5. */
return (dx <= cr);
} else { /* zone 9. */
dy = cy - go.bottom;
return ((dx * dx + dy * dy) <= cr2);
}
}
}
/**
* Returns [x,y] where the rectangle is closest to (cx, cy).
* 0 | 1 | 2
* ------------------
* 3 | 4 | 5
* ------------------
* 6 | 7 | 9
*/
function getClosestPoint(cx, cy, go) {
var dx, dy;
if (cx < go.left) {
dx = go.left - cx;
if (cy < go.top) { /* zone 0. */
return [go.left, go.top];
} else if (cy <= go.bottom) { /* zone 3. */
return [go.left, cy];
} else { /* zone 6. */
return [go.left, go.bottom];
}
} else if (cx <= go.right) {
if (cy < go.top) { /* zone 1. */
return [cx, go.top];
} else if (cy <= go.bottom) { /* zone 4. */
return [cx, cy];
} else { /* zone 7. */
return [cx, go.bottom];
}
} else {
dx = cx - go.right;
if (cy < go.top) { /* zone 2. */
return [go.right, go.top];
} else if (cy <= go.bottom) { /* zone 5. */
return [go.right, cy];
} else { /* zone 9. */
return [go.right, go.bottom];
}
}
}
/**
* Returns the "volume" of the grid object.
*/
function gridObjVol(go) {
return go.w * go.h * Math.min(go.w, go.h);
}
function StickyNodes() {
var domNodes = [],
grid = [],
GRIDX = 100,
GRIDY = 100,
REPLACE_WORDS_IN = {
a: 1, b: 1, big: 1, body: 1, cite:1, code: 1, dd: 1, div: 1,
dt: 1, em: 1, font: 1, h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1,
i: 1, label: 1, legend: 1, li: 1, p: 1, pre: 1, small: 1,
span: 1, strong: 1, sub: 1, sup: 1, td: 1, th: 1, tt: 1
};
function addDomNode(el) {
if (el !== undefined && el !== null) {
el.khIgnore = true;
domNodes.push(el);
}
}
this.addDomNode = addDomNode;
this.addWords = function (el) {
var textEls = [];
function shouldAddChildren(el) {
return el.tagName && REPLACE_WORDS_IN[el.tagName.toLowerCase()];
}
function buildTextEls(el, shouldAdd) {
var i, len;
if (shouldAdd && el.nodeType === Node.TEXT_NODE &&
el.nodeValue.trim().length > 0) {
textEls.push(el);
return;
}
if (!el.childNodes || el.khIgnore) {
return;
}
shouldAdd = shouldAddChildren(el);
for (i = 0, len = el.childNodes.length; i < len; i++) {
buildTextEls(el.childNodes[i], shouldAdd);
}
}
function wordsToSpans(textEl) {
var p = textEl.parentNode,
words = textEl.nodeValue.split(/\s+/),
ws = textEl.nodeValue.split(/\S+/),
i, n, len = Math.max(words.length, ws.length);
/* preserve whitespace for pre tags. */
if (ws.length > 0 && ws[0].length === 0) {
ws.shift();
}
for (i = 0; i < len; i++) {
if (i < words.length && words[i].length > 0) {
n = document.createElement('span');
n.innerHTML = words[i];
p.insertBefore(n, textEl);
addDomNode(n);
}
if (i < ws.length && ws[i].length > 0) {
n = document.createTextNode(ws[i]);
p.insertBefore(n, textEl);
}
}
p.removeChild(textEl);
}
buildTextEls(el, shouldAddChildren(el));
textEls.map(wordsToSpans);
};
/* includes el. */
this.addTagNames = function (el, tagNames) {
var tname = el.tagName && el.tagName.toLowerCase(),
i, j, els, len;
if (el.khIgnore) {
return;
}
if (tagNames.indexOf(tname) !== -1) {
addDomNode(el);
}
if (!el.getElementsByTagName) {
return;
}
for (i = 0; i < tagNames.length; i++) {
els = el.getElementsByTagName(tagNames[i]);
for (j = 0, len = els.length; j < len; j++) {
if (!els[j].khIgnore) {
addDomNode(els[j]);
}
}
}
};
this.finalize = function (docW, docH) {
var xi, yi, i, len, startXI, startYI, el, go, off, w, h,
endXI = Math.floor(docW / GRIDX) + 1,
endYI = Math.floor(docH / GRIDY) + 1;
/* initialize grid. */
grid = new Array(endXI);
for (xi = 0; xi < endXI; xi++) {
grid[xi] = new Array(endYI);
}
/* add nodes into grid. */
for (i = 0, len = domNodes.length; i < len; i++) {
el = domNodes[i];
if (el.khPicked) {
continue;
}
off = jQuery(el).offset();
w = jQuery(el).width();
h = jQuery(el).height();
go = {
el: domNodes[i], /* dom element. */
left: off.left,
right: off.left + w,
top: off.top,
bottom: off.top + h,
w: w,
h: h,
x: off.left + (w / 2), /* center x. */
y: off.top + (h / 2), /* center y. */
diag: Math.sqrt(((w * w) + (h * h)) / 4), /* center to corner */
/* these are for removing ourselves from the grid. */
arrs: [], /* which arrays we're in (grid[x][y]). */
idxs: [] /* what indexes. */
};
startXI = Math.floor(go.left / GRIDX);
startYI = Math.floor(go.top / GRIDY);
endXI = Math.floor((go.left + go.w) / GRIDX) + 1;
endYI = Math.floor((go.top + go.h) / GRIDY) + 1;
for (xi = startXI; xi < endXI; xi++) {
for (yi = startYI; yi < endYI; yi++) {
if (grid[xi] === undefined) {
grid[xi] = [];
}
if (grid[xi][yi] === undefined) {
grid[xi][yi] = [go];
} else {
grid[xi][yi].push(go);
}
go.arrs.push(grid[xi][yi]);
go.idxs.push(grid[xi][yi].length - 1);
}
}
}
};
function removeGridObj(go) {
var i;
for (i = 0; i < go.arrs.length; i++) {
go.arrs[i][go.idxs[i]] = undefined;
}
go.el.style.visibility = "hidden";
go.el.khPicked = true;
delete go.arrs;
delete go.idxs;
}
/**
* cb(gridObj) -> boolean true if the object should be removed.
*/
this.removeIntersecting = function (x, y, r, cb) {
var xi, yi, arr, i, r2 = r * r, go,
startXI = Math.floor((x - r) / GRIDX),
startYI = Math.floor((y - r) / GRIDY),
endXI = Math.floor((x + r) / GRIDX) + 1,
endYI = Math.floor((y + r) / GRIDY) + 1;
for (xi = startXI; xi < endXI; xi++) {
if (grid[xi] === undefined) {
continue;
}
for (yi = startYI; yi < endYI; yi++) {
arr = grid[xi][yi];
if (arr === undefined) {
continue;
}
for (i = 0; i < arr.length; i++) {
go = arr[i];
if (go !== undefined &&
circleGridObjInt(x, y, r, r2, go) &&
cb(go)) {
removeGridObj(go);
}
}
}
}
};
}
function PlayerBall(parentNode, stickyNodes, ballOpts) {
var x = 300, y = 300,
vx = 0, vy = 0,
radius = 20,
lastR = 0, /**< optimization: only resize when necessary. */
docW = 10000, docH = 10000,
attached = [],
attachedDiv, /* div to put attached nodes into. */
canvas_el,
canvas_ctx,
color = ballOpts.color,
accelTargetX = 0, accelTargetY = 0,
accel = false,
VOL_MULT = ballOpts.VOL_MULT,
MAX_ATTACHED_VISIBLE = ballOpts.MAX_ATTACHED_VISIBLE,
CHECK_VOLS = ballOpts.CHECK_VOLS,
/**
* which direction the ball is facing in the xy axis, in radians.
* th: 0 is facing dead East
* th: 1/2 PI is facing dead South
* note that this is like regular th on a graph with y inverted.
* Same rotation as css transform.
*/
th = 0,
/**
* Ball angle in the rotation axis / z plane, in radians.
* phi: 0 is pointing in the direction the ball is rolling.
* phi: 1/2 PI is pointing straight up (out of the page).
* note that forward rotation means phi -= 0.1.
*/
phi = 0;
this.init = function () {
canvas_el = document.createElement('canvas');
canvas_el.width = radius * 2;
canvas_el.height = radius * 2;
canvas_el.style.cssText = 'position: absolute; z-index: 500;';
parentNode.appendChild(canvas_el);
canvas_ctx = canvas_el.getContext('2d');
attachedDiv = document.createElement('div');
// attachedDiv.setAttribute("id", "capture")
parentNode.appendChild(attachedDiv);
};
this.setRadius = function (r) {
radius = r;
};
this.getState = function () {
return {
x: x,
y: y,
vx: vx,
vy: vy,
radius: radius,
th: th,
phi: phi,
};
};
this.setState = function (s) {
x = s.x;
y = s.y;
vx = s.vx;
vy = s.vy;
radius = s.radius;
th = s.th;
phi = s.phi;
};
this.setXY = function (sx, sy) {
x = sx;
y = sy;
};
this.setTh = function (sth) {
th = sth;
};
this.setPhi = function (sphi) {
phi = sphi;
};
this.setColor = function (c) {
color = c;
};
this.setDocSize = function (w, h) {
docW = w;
docH = h;
};
this.setAccel = function (bool) {
accel = bool;
};
this.setAccelTarget = function (tx, ty) {
accelTargetX = tx;
accelTargetY = ty;
};
function getVol() {
return (4 * Math.PI * radius * radius * radius / 3);
}
function grow(go) {
var newVol = getVol() + gridObjVol(go) * VOL_MULT;
radius = Math.pow(newVol * 3 / (4 * Math.PI), 1 / 3);
}
function attachGridObj(go) {
var attXY = getClosestPoint(x, y, go),
dx = attXY[0] - x,
dy = attXY[1] - y,w
r = Math.sqrt(dx * dx + dy * dy),
attTh = 0 - th,
offLeft = attXY[0] - go.left,
offTop = attXY[1] - go.top,
offTh = Math.atan2(dy, dx) - th,
attX = r * Math.cos(offTh),
attY = r * Math.sin(offTh),
el = go.el.cloneNode(true),
go_jel = jQuery(go.el),
newAtt = {
el: el,
attX: attX,
attY: attY,
attT: 'translate(' + Math.round(attX) + 'px,' +
Math.round(attY) + 'px) ' +
'rotate(' + attTh + 'rad)',
r: r,
offTh: offTh,
offPhi: 0 - phi,
diag: go.diag,
removeR: r + go.diag,
visible: false,
display: go_jel.css('display')
};
attached.push(newAtt);
// grow(go);
el.style.position = 'absolute';
el.style.left = (-offLeft) + 'px';
el.style.top = (-offTop) + 'px';
el.style.setProperty(CSS_TRANSFORM_ORIGIN,
offLeft + 'px ' + offTop + 'px', null);
el.style.display = 'none';
/* copy computed styles from old object. */
el.style.color = go_jel.css('color');
el.style.textDecoration = go_jel.css('text-decoration');
el.style.fontSize = go_jel.css('font-size');
el.style.fontWeight = go_jel.css('font-weight');
el.khIgnore = true;
attachedDiv.appendChild(el);
}
/**
* @return true if the object should be removed from stickyNodes.
*/
function removeIntCb(go) {
if (CHECK_VOLS && gridObjVol(go) > getVol()) {
return false;
}
attachGridObj(go);
return true;
}
this.updatePhysics = function () {
var oldX = x, oldY = y, dx, dy,
bounce = false,
accelTh;
if (accel) {
accelTh = Math.atan2(accelTargetY - y, accelTargetX - x);
vx += Math.cos(accelTh) * 0.5;
vy += Math.sin(accelTh) * 0.5;
} else {
vx *= 0.95;
vy *= 0.95;
}
x += vx;
y += vy;
/* bounce ball on edges of document. */
if (x - radius < 0) {
bounce = true;
x = radius + 1;
vx = -vx;
} else if (x + radius > docW) {
bounce = true;
x = docW - radius - 1;
vx = -vx;
}
if (y - radius < 0) {
bounce = true;
y = radius + 1;
vy = -vy;
} else if (y + radius > docH) {
bounce = true;
y = docH - radius - 1;
vy = -vy;
}
if (vx !== 0 || vy !== 0) {
th = Math.atan2(vy, vx);
dx = x - oldX;
dy = y - oldY;
/* arclen = th * r, so th = arclen / r. */
phi -= Math.sqrt(dx * dx + dy * dy) / radius;
}
stickyNodes.removeIntersecting(x, y, radius, removeIntCb);
this.draw();
};
function drawBall() {
var sx1, sy1, sx2, sy2, dx, dy, i, pct1, pct2, z1, z2;
/* move/resize canvas element. */
canvas_el.style.left = (x - radius) + 'px';
canvas_el.style.top = (y - radius) + 'px';
if (radius != lastR) {
canvas_el.width = 2 * radius + 1;
canvas_el.height = 2 * radius + 1;
lastR = radius;
}
/* draw white circle. */
canvas_ctx.clearRect(0, 0, 2 * radius, 2 * radius);
canvas_ctx.fillStyle = "#ff0000";
canvas_ctx.beginPath();
canvas_ctx.arc(radius, radius, radius - 1, 0, Math.PI * 2, true);
canvas_ctx.fill();
/* draw outer border. */
canvas_ctx.strokeStyle = color;
canvas_ctx.beginPath();
canvas_ctx.arc(radius, radius, radius - 1, 0, Math.PI * 2, true);
canvas_ctx.stroke();
/* draw stripes. */
canvas_ctx.fillStyle = color;
sx1 = radius + radius * Math.cos(th + Math.PI / 16);
sy1 = radius + radius * Math.sin(th + Math.PI / 16);
sx2 = radius + radius * Math.cos(th - Math.PI / 16);
sy2 = radius + radius * Math.sin(th - Math.PI / 16);
dx = (radius + radius * Math.cos(th + Math.PI * 15 / 16)) - sx1;
dy = (radius + radius * Math.sin(th + Math.PI * 15 / 16)) - sy1;
for (i = 0; i < Math.PI * 2; i += Math.PI / 7) {
pct1 = (-Math.cos(phi + i) + 1) / 2;
pct2 = (-Math.cos(phi + i + Math.PI / 32) + 1) / 2;
z1 = Math.sin(phi + i);
z2 = Math.sin(phi + i + Math.PI / 32);
if (z1 > 0 && z2 > 0) {
canvas_ctx.beginPath();
canvas_ctx.moveTo(sx1 + pct1 * dx, sy1 + pct1 * dy);
canvas_ctx.lineTo(sx1 + pct2 * dx, sy1 + pct2 * dy);
canvas_ctx.lineTo(sx2 + pct2 * dx, sy2 + pct2 * dy);
canvas_ctx.lineTo(sx2 + pct1 * dx, sy2 + pct1 * dy);
canvas_ctx.fill();
}
}
}
/**
* @return true if the attached object is roughly visible.
*/
function drawAttached(att) {
var oth = th + att.offTh,
ophi = phi + att.offPhi,
ox = att.r * Math.cos(oth),
oy = att.r * Math.sin(oth),
dx = (att.r * Math.cos((th - att.offTh) + Math.PI)) - ox,
dy = (att.r * Math.sin((th - att.offTh) + Math.PI)) - oy,
pct = (-Math.cos(ophi) + 1) / 2,
cx = ox + pct * dx,
cy = oy + pct * dy,
oz = att.r * Math.sin(ophi);
if (oz < 0 && Math.sqrt(cx * cx + cy * cy) + att.diag < radius) {
/* hidden behind circle. */
if (att.visible) {
att.visible = false;
att.el.style.display = "none";
}
return false;
}
/* attached node is visible. */
if (!att.visible) {
att.visible = true;
att.el.style.display = att.display;
}
//att.el.style.zIndex = 500 + Math.round(oz);
att.el.style.zIndex = (oz > 0)? 501 : 499;
att.el.style.setProperty(
CSS_TRANSFORM,
'translate(' + x + 'px,' + y + 'px) ' +
'rotate(' + th + 'rad) ' +
'scaleX(' + Math.cos(ophi) + ') ' +
att.attT, null);
return true;
}
function onAttachedRemoved(att) {
attachedDiv.removeChild(att.el);
delete att.el;
}
this.draw = function () {
var i, att, numAttachedVisible = 0;
drawBall();
for (i = attached.length; --i >= 0;) {
att = attached[i];
if (att.removeR < radius) {
attached.splice(i, 1).map(onAttachedRemoved);
} else if (drawAttached(att)) {
if (++numAttachedVisible > MAX_ATTACHED_VISIBLE) {
/* remove older items and stop. */
attached.splice(0, i).map(onAttachedRemoved);
break;
}
}
}
};
}
function preventDefault(event) {
event.preventDefault();
event.returnValue = false;
return false;
}
function Game(gameDiv, stickyNodes, ballOpts) {
var stickyNodes, player1, physicsInterval, resizeInterval, listeners = [];
player1 = new PlayerBall(gameDiv, stickyNodes, ballOpts, false);
player1.init();
player1.setXY(300, 300);
window.scrollTo(0, 200);
function on_resize() {
player1.setDocSize(jQuery(document).width() - 5,
jQuery(document).height() - 5);
}
on_resize();
player1.setAccel(true)
// if (ballOpts.MOUSEB === -5) {
document.addEventListener('touchstart', function (event) {
if (event.touches.length === 1) {
player1.setAccel(true);
return preventDefault(event);
}
}, true);
document.addEventListener('touchmove', function (event) {
player1.setAccelTarget(event.touches[0].pageX,
event.touches[0].pageY);
}, true);
document.addEventListener('touchend', function (event) {
if (event.touches.length === 0) {
player1.setAccel(false);
return preventDefault(event);
}
}, true);
// }
// else {
// /* mouse buttons */
// document.addEventListener('mousemove', function (event) {
// player1.setAccelTarget(event.pageX, event.pageY);
// }, true);
// document.addEventListener('mousedown', function (event) {
// if (event.button === ballOpts.MOUSEB) {
// player1.setAccel(true);
// return preventDefault(event);
// }
// }, true);
// document.addEventListener('mouseup', function (event) {
// if (event.button === ballOpts.MOUSEB) {
// player1.setAccel(false);
// return preventDefault(event);
// }
// }, true);
// }
physicsInterval = setInterval(function () {
player1.accelTargetX = Math.random()*window.innerHeight;
player1.accelTargetY = Math.random()*window.innerWidth;
player1.updatePhysics();
}, 25);
resizeInterval = setInterval(on_resize, 1000);
}
function whenAllLoaded(gameDiv, stickyNodes) {
stickyNodes.finalize(jQuery(document).width(), jQuery(document).height());
var game, ballOpts;
ballOpts = {
color: 0x00FF00,
VOL_MULT: 1.0,
MAX_ATTACHED_VISIBLE: 9000,
CHECK_VOLS: false,
MOUSEB: 0 // 0 FOR DESKTOP OR -5 FOR MOBILE
};
game = new Game(gameDiv, stickyNodes, ballOpts);
// Download image
var btn = document.getElementById('imgButton');
btn.addEventListener("touchend", function(event) {
console.log("capture", document.getElementById("capture"));
html2canvas(document.getElementById("capture")).then(function(canvas) {
var link = document.createElement("a");
document.body.appendChild(link);
link.download = "ridindirtyberlin.png";
link.href = canvas.toDataURL("image/png");
link.target = '_blank';
link.click();
});
})
startPeristentVibrate(300, 430);
}
function main() {
var gameDiv, checkInterval, stickyNodes, dlbtn;
gameDiv = document.createElement('div');
gameDiv.khIgnore = true;
dlbtn = document.getElementById("button-wrapper");
dlbtn.khIgnore = true;
document.body.appendChild(gameDiv);
setTimeout(function () {
var i, len, el;
window.khNodes.addWords(document.body);
for (i = 0, len = document.body.childNodes.length; i < len; i++) {
el = document.body.childNodes[i];
window.khNodes.addTagNames(el, [
'canvas', 'iframe', 'img', 'input', 'select',
'textarea', 'video', 'marquee', 'progress'
]);
}
checkInterval = setInterval(function () {
if (window.jQuery) {
clearInterval(checkInterval);
whenAllLoaded(gameDiv, window.khNodes);
}
}, 100);
}, 0);
}
if (!window.noMain) {
main();
var sound = new Howl({
src: ['snd/gabba140.mp3'],
autoplay: true,
loop: true,
volume: 1
});
}

Binary file not shown.

View File

@ -0,0 +1,98 @@
// Captive portal with (arduino) OTA + SPIFFS
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h> // Over-the-Air updates
#include <ESP8266WebServer.h>
#include "./DNSServer.h" // Dns server
#include <FS.h> // SPIFFS
DNSServer dnsServer;
const byte DNS_PORT = 53;
ESP8266WebServer server(80);
#ifndef STASSID
#define STASSID "Plague Rave 2020"
//#define STASPSK "mypassword"
#endif
IPAddress apIP(192, 168, 4, 1);
const char* ssid = STASSID;
//const char* password = STAPSK;
void setup() {
Serial.begin(115200);
Serial.println("Booting");
WiFi.mode(WIFI_AP);
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
WiFi.softAP(ssid);
dnsServer.start(DNS_PORT, "*", apIP); // redirect dns request to AP ip
MDNS.begin("opencoil", WiFi.softAPIP());
Serial.println("Ready");
Serial.print("IP address: ");
Serial.println(WiFi.softAPIP());
//Over-the-Air updates
ArduinoOTA.setHostname("opencoil");
//ArduinoOTA.setPassword("change-me"); //disabled to allow data uploads
ArduinoOTA.begin();
SPIFFS.begin();
//redirect all traffic to index.html
server.onNotFound([]() {
if(!handleFileRead(server.uri())){
const char *metaRefreshStr = "<head><meta http-equiv=\"refresh\" content=\"0; url=http://192.168.4.1/index.html\" /></head><body><p>redirecting...</p></body>";
server.send(200, "text/html", metaRefreshStr);
}
});
server.begin();
}
void loop() {
dnsServer.processNextRequest();
ArduinoOTA.handle();
server.handleClient();
delay(50);
}
String getContentType(String filename){
if(server.hasArg("download")) return "application/octet-stream";
else if(filename.endsWith(".htm")) return "text/html";
else if(filename.endsWith(".html")) return "text/html";
else if(filename.endsWith(".css")) return "text/css";
else if(filename.endsWith(".js")) return "application/javascript";
else if(filename.endsWith(".png")) return "image/png";
else if(filename.endsWith(".gif")) return "image/gif";
else if(filename.endsWith(".jpg")) return "image/jpeg";
else if(filename.endsWith(".ico")) return "image/x-icon";
else if(filename.endsWith(".xml")) return "text/xml";
else if(filename.endsWith(".mp4")) return "video/mp4";
else if(filename.endsWith(".pdf")) return "application/x-pdf";
else if(filename.endsWith(".zip")) return "application/x-zip";
else if(filename.endsWith(".gz")) return "application/x-gzip";
return "text/plain";
}
//Given a file path, look for it in the SPIFFS file storage. Returns true if found, returns false if not found.
bool handleFileRead(String path){
if(path.endsWith("/")) path += "index.html";
String contentType = getContentType(path);
String pathWithGz = path + ".gz";
if(SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)){
if(SPIFFS.exists(pathWithGz))
path += ".gz";
File file = SPIFFS.open(path, "r");
size_t sent = server.streamFile(file, contentType);
file.close();
return true;
}
return false;
}