Browse Source

Merge branch 'master' of https://git.vvvvvvaria.org/then/opencoil-paracity

# Conflicts:
#	website/map/index.php
master
Anton Linus 4 years ago
parent
commit
75ec9f67aa
  1. 14
      website/map/index.php
  2. 309
      works/JODI/otastaImg/data/index.html
  3. 2
      works/JODI/otastaImg/otastaImg.ino
  4. BIN
      works/Rosa Menkman/otastaImg/data/Ariane.gif
  5. 2
      works/Rosa Menkman/otastaImg/data/index.html
  6. 166
      works/Sarah Grant/otastaImg/DNSServer.cpp
  7. 72
      works/Sarah Grant/otastaImg/DNSServer.h
  8. BIN
      works/Sarah Grant/otastaImg/data/.DS_Store
  9. BIN
      works/Sarah Grant/otastaImg/data/img/Berlin_TV_Tower.png
  10. BIN
      works/Sarah Grant/otastaImg/data/img/ES400-1.png
  11. BIN
      works/Sarah Grant/otastaImg/data/img/TIER-scooter-final-1024x1024.png
  12. BIN
      works/Sarah Grant/otastaImg/data/img/berghain.gif
  13. BIN
      works/Sarah Grant/otastaImg/data/img/brandenberg-gate.jpg
  14. BIN
      works/Sarah Grant/otastaImg/data/img/gradient250x250.jpg
  15. BIN
      works/Sarah Grant/otastaImg/data/img/mask.gif
  16. BIN
      works/Sarah Grant/otastaImg/data/img/source.gif
  17. BIN
      works/Sarah Grant/otastaImg/data/img/thumbnail.gif
  18. BIN
      works/Sarah Grant/otastaImg/data/img/tvtower.png
  19. 399
      works/Sarah Grant/otastaImg/data/index.html
  20. 4
      works/Sarah Grant/otastaImg/data/js/howler.min.js
  21. 20
      works/Sarah Grant/otastaImg/data/js/html2canvas.min.js
  22. 2
      works/Sarah Grant/otastaImg/data/js/jquery-3.5.1.slim.min.js
  23. 801
      works/Sarah Grant/otastaImg/data/js/kh.js
  24. BIN
      works/Sarah Grant/otastaImg/data/snd/gabba140.mp3
  25. 98
      works/Sarah Grant/otastaImg/otastaImg.ino

14
website/map/index.php

@ -6,6 +6,7 @@ $scooters = array(
//array('https://opencoil.show/test-json.php?scooterID=1', 'artist name 0', 'title 0', 'desciption 0' ),
//array('https://opencoil.show/test-json.php?scooterID=2', 'artist name 1', 'title 1', 'desciption 1' ),
//array('https://opencoil.show/test-json.php?scooterID=3', 'artist name 2', 'title 2', 'desciption 2' ),
<<<<<<< HEAD
array('https://platform.tier-services.io/v1/vehicle/024449e3-8061-4cf5-88b9-546a95df8b33', 'Aram Bartholl', 'Fossils of late capitalism', 'Aram Bartholl has salvaged rental bikes and scooters from the Spree River and is now exhibiting them as material relics of the platform economy.'),
array('https://platform.tier-services.io/v1/vehicle/857af6ef-457d-49bb-841f-1b63de59ae4c', '!Mediengruppe Bitnik', 'Follow the Rider ƪ(ړײ)ƪ', 'Follow the next person you see on an e-scooter. 👠 Keep distance but don\'t lose your guide.'),
array('https://platform.tier-services.io/v1/vehicle/5f57b04b-7048-40d7-8e68-13fd302277d8', 'Jonas Lund', 'Hello Capitalism', '\'Hello Capitalism\' is a text-based work by Jonas Lund, exploring a wide range of different types of capitalistic systems.'),
@ -17,6 +18,19 @@ $scooters = array(
array('https://platform.tier-services.io/v1/vehicle/54aaed50-dd24-4c10-9580-b05b3bfc6985', 'Danja Vasiliev', 'need4speed', 'desciption'),
array('https://platform.tier-services.io/v1/vehicle/481f9ae7-bca5-469f-b4c0-91c3140aafc8', 'Constant Dullaart', 'constant time', 'Your network, your home, as temporary as seconds on the clock. Reconnect.'),
array('https://platform.tier-services.io/v1/vehicle/fb0f58d0-c231-4bba-94d7-f12c8544ae6c', 'Dennis de Bel & Anton Jehle', 'Paracity Gallery v0.41', 'HOW TO: diy scooter gallery'),
=======
array('https://platform.tier-services.io/v1/vehicle/1cdccfec-60c3-4b9e-ad18-40861a3a9ab2', 'Aram Bartholl', 'Fossils of late capitalism', 'Aram Bartholl has salvaged rental bikes and scooters from the Spree River and is now exhibiting them as material relics of the platform economy.'),
array('https://platform.tier-services.io/v1/vehicle/ec9437d8-b105-4c94-bcdd-8653f629d476', '!Mediengruppe Bitnik', 'Follow the Rider ƪ(ړײ)ƪ', 'Follow the next person you see on an e-scooter. 👠 Keep distance but don\'t lose your guide.'),
array('https://platform.tier-services.io/v1/vehicle/bfe887ad-cb89-4311-836f-dfb804b46269', 'Jonas Lund', 'Hello Capitalism', '\'Hello Capitalism\' is a text-based work by Jonas Lund, exploring a wide range of different types of capitalistic systems.'),
array('https://platform.tier-services.io/v1/vehicle/808decca-3537-41ad-96c0-45f29c57349d', 'Martin Howse', 'wok_the_cables', 'Adventure game for psychogeophysical divination of portals, realtime instructions to follow #wokthecables'),
array('https://platform.tier-services.io/v1/vehicle/54aaed50-dd24-4c10-9580-b05b3bfc6985', 'Sofya Aleynikova', 'followers', 'Eine weibliche Protagonistin manifestiert sich als Meme im Web und stellt die richtigen Fragen.'),
array('https://platform.tier-services.io/v1/vehicle/d794fac2-5c3e-4f2b-aed1-f70ef82f67d8', 'JODI', '#4b38$R0ut.IDx', '██████████████████████████████████████████████████▒▒'),
array('https://platform.tier-services.io/v1/vehicle/86219ae1-416a-4b36-897a-c738397d7210', 'Rosa Menkmann', 'Ariane', 'Ariane is a famous Shutterstock model. She also worries about getting older.'),
array('https://platform.tier-services.io/v1/vehicle/0b939caf-80e9-4d6b-8454-4a7f8eaf088c', 'Sarah Grant', 'vibe', 'tba'),
array('https://platform.tier-services.io/v1/vehicle/0f7fa267-4bc1-439a-8fd0-43b98b9ffba7', 'Danja Vasiliev', 'need4speed', 'desciption'),
array('https://platform.tier-services.io/v1/vehicle/8732f342-df2f-475f-b0f6-c0032743a944', 'Constant Dullaart', 'constant time', 'Your network, your home, as temporary as seconds on the clock. Reconnect.'),
array('https://platform.tier-services.io/v1/vehicle/511c3984-3f81-4022-acc2-8e22646a5e01', 'Dennis de Bel & Anton Jehle', 'Paracity Gallery v0.41', 'HOW TO: diy scooter gallery'),
>>>>>>> 02f2f3836f01a361d6f10d18c7ea63422c64df22
);

309
works/JODI/otastaImg/data/index.html

File diff suppressed because one or more lines are too long

2
works/JODI/otastaImg/otastaImg.ino

@ -15,7 +15,7 @@
ESP8266WebServer server(80);
#ifndef STASSID
#define STASSID "%Location????????"
#define STASSID "#4b38$R0ut.IDx"
//#define STASPSK "mypassword"
#endif

BIN
works/Rosa Menkman/otastaImg/data/Ariane.gif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 1.5 MiB

2
works/Rosa Menkman/otastaImg/data/index.html

@ -15,7 +15,7 @@ body {
<body>
<div> <center>
<img src="Ariane.gif" width="100%"></center>
<img src="Ariane.gif" height="100%"></center>
</div>
</body>

166
works/Sarah Grant/otastaImg/DNSServer.cpp

@ -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();
}

72
works/Sarah Grant/otastaImg/DNSServer.h

@ -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

BIN
works/Sarah Grant/otastaImg/data/.DS_Store

Binary file not shown.

BIN
works/Sarah Grant/otastaImg/data/img/Berlin_TV_Tower.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
works/Sarah Grant/otastaImg/data/img/ES400-1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

BIN
works/Sarah Grant/otastaImg/data/img/TIER-scooter-final-1024x1024.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

BIN
works/Sarah Grant/otastaImg/data/img/berghain.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 KiB

BIN
works/Sarah Grant/otastaImg/data/img/brandenberg-gate.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

BIN
works/Sarah Grant/otastaImg/data/img/gradient250x250.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
works/Sarah Grant/otastaImg/data/img/mask.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 357 KiB

BIN
works/Sarah Grant/otastaImg/data/img/source.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

BIN
works/Sarah Grant/otastaImg/data/img/thumbnail.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

BIN
works/Sarah Grant/otastaImg/data/img/tvtower.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

399
works/Sarah Grant/otastaImg/data/index.html

@ -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>

4
works/Sarah Grant/otastaImg/data/js/howler.min.js

File diff suppressed because one or more lines are too long

20
works/Sarah Grant/otastaImg/data/js/html2canvas.min.js

File diff suppressed because one or more lines are too long

2
works/Sarah Grant/otastaImg/data/js/jquery-3.5.1.slim.min.js

File diff suppressed because one or more lines are too long

801
works/Sarah Grant/otastaImg/data/js/kh.js

@ -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
});
}

BIN
works/Sarah Grant/otastaImg/data/snd/gabba140.mp3

Binary file not shown.

98
works/Sarah Grant/otastaImg/otastaImg.ino

@ -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;
}
Loading…
Cancel
Save