├── Server ├── .gitignore ├── config.js.sample ├── package.json ├── index.js ├── playlist.js └── package-lock.json ├── .gitignore ├── README.md ├── Firmware ├── .gitignore ├── src │ ├── config.h.sample │ ├── MQTTManager.h │ ├── RFIDReader.h │ ├── TouchManager.h │ ├── HTTPManager.h │ ├── LedController.h │ ├── RFIDReader.cpp │ ├── HTTPManager.cpp │ ├── MQTTManager.cpp │ ├── LedController.cpp │ ├── main.cpp │ └── TouchManager.cpp ├── test │ └── README ├── platformio.ini ├── lib │ └── README ├── include │ └── README └── .travis.yml └── DXF Files ├── MUSICUBES_LAYER_2-4.dxf ├── MUSICUBES_LAYER_1.dxf └── MUSICUBES_LAYER_0.dxf /Server/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | config.js -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.AppleDouble 2 | .DS_Store 3 | ._* 4 | Thumbs.db -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MusiCubes 2 | 3 | Work in progress. See http://michaelteeuw.nl/tagged/musicubes for more info. -------------------------------------------------------------------------------- /Firmware/.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .pioenvs 3 | .piolibdeps 4 | .vscode/.browse.c_cpp.db* 5 | .vscode/c_cpp_properties.json 6 | .vscode/launch.json 7 | .vscode 8 | src/config.h -------------------------------------------------------------------------------- /Server/config.js.sample: -------------------------------------------------------------------------------- 1 | const config = { 2 | http: { 3 | port: 8282 4 | }, 5 | sonos: { 6 | baseUrl: 'http://localhost:5005', 7 | room: 'Livingroom' 8 | } 9 | } 10 | 11 | module.exports = config -------------------------------------------------------------------------------- /Firmware/src/config.h.sample: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_H 2 | #define CONFIG_H 3 | 4 | struct Config { 5 | const char* mqtt_server = "mqtt.server.net"; 6 | const char* mqtt_user = "username"; 7 | const char* mqtt_password = "password"; 8 | const char* http_server = "192.168.0.100"; 9 | const char* http_port = "8282"; 10 | }; 11 | 12 | #endif -------------------------------------------------------------------------------- /Server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "musiccube", 3 | "version": "1.0.0", 4 | "description": "A music cube player.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "axios": "^0.18.0", 13 | "express": "^4.16.4", 14 | "log-timestamp": "^0.3.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Firmware/test/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for PIO Unit Testing and project tests. 3 | 4 | Unit Testing is a software testing method by which individual units of 5 | source code, sets of one or more MCU program modules together with associated 6 | control data, usage procedures, and operating procedures, are tested to 7 | determine whether they are fit for use. Unit testing finds problems early 8 | in the development cycle. 9 | 10 | More information about PIO Unit Testing: 11 | - https://docs.platformio.org/page/plus/unit-testing.html 12 | -------------------------------------------------------------------------------- /Firmware/platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [env:nodemcuv2] 12 | platform = espressif8266 13 | board = nodemcuv2 14 | ;board = d1_mini_pro 15 | framework = arduino 16 | ; upload_port = 192.168.0.126 17 | upload_speed = 921600 18 | lib_deps = 19 | elapsedMillis 20 | WifiManager 21 | PubSubClient 22 | MFRC522 23 | FastLED 24 | Adafruit MPR121 -------------------------------------------------------------------------------- /Firmware/src/MQTTManager.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "config.h" 5 | 6 | enum PlayState { 7 | Playing, 8 | Stopped, 9 | Transitioning 10 | }; 11 | 12 | typedef void (*PlayStateChangedCallback)(PlayState playState); 13 | 14 | class MQTTManager { 15 | public: 16 | MQTTManager(); 17 | void init(); 18 | void handle(); 19 | void publishCubeIdentifier(String cubeUID); 20 | void publishButtonState(uint8_t buttonIndex, bool state); 21 | void setPlayStateChangedCallback(PlayStateChangedCallback callback); 22 | 23 | private: 24 | Config _config; 25 | WiFiClient _espClient; 26 | PubSubClient _client; 27 | PlayStateChangedCallback _playStateChangedCallback; 28 | void checkConnection(); 29 | void messageCallback(char* topic, byte* payload, unsigned int length); 30 | }; -------------------------------------------------------------------------------- /Firmware/src/RFIDReader.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define RFID_DEBUG true 7 | 8 | #define MFRC522_RST_PIN D4 9 | #define MFRC522_SS_PIN D3 10 | 11 | #define RFID_READ_INTERVAL 100 12 | #define RFID_CHECK_REPEAT 3 13 | #define NO_CUBE_IDENTIFIER "00:00:00:00" 14 | 15 | typedef void (*CubeChangeCallback)(String cubeUID); 16 | 17 | class RFIDReader { 18 | public: 19 | RFIDReader(); 20 | void init(); 21 | void handle(); 22 | void setCubeChangeCallback(CubeChangeCallback callback); 23 | bool cubePresent(); 24 | elapsedMillis changeTimer; 25 | 26 | 27 | private: 28 | MFRC522 _mfrc522; 29 | elapsedMillis _readTimer; 30 | String _currentCube; 31 | CubeChangeCallback _cubeChangedCallback; 32 | int8_t _checkCount; 33 | void readCube(); 34 | bool isChanged(String cubeUID); 35 | void cubeChanged(String cubeUID); 36 | void changeCubeIfDifferent(String cubeUID); 37 | }; -------------------------------------------------------------------------------- /Firmware/src/TouchManager.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Adafruit_MPR121.h" 3 | #include 4 | 5 | #define TOUCH_DEBUG true 6 | 7 | #define TOUCH_SDA D1 8 | #define TOUCH_SCL D2 9 | #define TOUCH_SENSORS 2 10 | #define TOUCH_THRESHOLD_TOUCH 255 11 | #define TOUCH_THRESHOLD_RELEASE 1 12 | #define TOUCH_CHECK_INTERVAL 5 13 | 14 | #define TOUCH_SHORTPRESS 40 15 | #define TOUCH_LONGPRESS 500 16 | 17 | #define MINIMUM_NUM_OF_FIELDS_ACTIVE 1 18 | 19 | typedef void (*ButtonPressCallback)(uint8_t button, bool longPress); 20 | 21 | class TouchManager { 22 | public: 23 | TouchManager(); 24 | void init(); 25 | void handle(); 26 | void setButtonPressCallback(ButtonPressCallback callback); 27 | 28 | private: 29 | uint16_t _sensorAddresses[TOUCH_SENSORS] = {0x5A, 0x5B}; 30 | bool _lastStates[TOUCH_SENSORS]; 31 | uint8_t _lastFields[TOUCH_SENSORS]; 32 | elapsedMillis _intervalTimer; 33 | elapsedMillis _touchTimers[TOUCH_SENSORS]; 34 | ButtonPressCallback _buttonPressCallback; 35 | Adafruit_MPR121 _sensors[TOUCH_SENSORS]; 36 | void configureSensors(); 37 | void checkStates(); 38 | uint8_t activeFields(uint8_t sensorIndex); 39 | }; -------------------------------------------------------------------------------- /Firmware/lib/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link into executable file. 4 | 5 | The source code of each library should be placed in a an own separate directory 6 | ("lib/your_library_name/[here are source files]"). 7 | 8 | For example, see a structure of the following two libraries `Foo` and `Bar`: 9 | 10 | |--lib 11 | | | 12 | | |--Bar 13 | | | |--docs 14 | | | |--examples 15 | | | |--src 16 | | | |- Bar.c 17 | | | |- Bar.h 18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html 19 | | | 20 | | |--Foo 21 | | | |- Foo.c 22 | | | |- Foo.h 23 | | | 24 | | |- README --> THIS FILE 25 | | 26 | |- platformio.ini 27 | |--src 28 | |- main.c 29 | 30 | and a contents of `src/main.c`: 31 | ``` 32 | #include 33 | #include 34 | 35 | int main (void) 36 | { 37 | ... 38 | } 39 | 40 | ``` 41 | 42 | PlatformIO Library Dependency Finder will find automatically dependent 43 | libraries scanning project source files. 44 | 45 | More information about PlatformIO Library Dependency Finder 46 | - https://docs.platformio.org/page/librarymanager/ldf.html 47 | -------------------------------------------------------------------------------- /Firmware/src/HTTPManager.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "config.h" 4 | 5 | #define STATE_UPDATE_INTERVAL 1000 6 | #define HTTP_DEBUG false 7 | 8 | enum PlayState { 9 | Playing, 10 | Stopped, 11 | Transitioning 12 | }; 13 | 14 | enum VolumeChange { 15 | Up, 16 | Down 17 | }; 18 | 19 | enum SkipDirection { 20 | Next, 21 | Previous 22 | }; 23 | 24 | typedef void (*PlayStateChangedCallback)(PlayState playState); 25 | 26 | class HTTPManager { 27 | public: 28 | HTTPManager(); 29 | void init(); 30 | void handle(); 31 | void publishCubeIdentifier(String cubeUID); 32 | void publishButtonState(uint8_t buttonIndex, bool state); 33 | void setPlayStateChangedCallback(PlayStateChangedCallback callback); 34 | void changeVolume(VolumeChange change); 35 | void skipSong(SkipDirection direction); 36 | void log(String string); 37 | PlayState playState; 38 | 39 | private: 40 | Config _config; 41 | PlayStateChangedCallback _playStateChangedCallback; 42 | elapsedMillis _stateUpdateTimer; 43 | String _lastState; 44 | void checkState(); 45 | String serverUrl(String endpoint); 46 | String makeRequest(String uri); 47 | void setPlayState(PlayState state); 48 | }; -------------------------------------------------------------------------------- /Firmware/src/LedController.h: -------------------------------------------------------------------------------- 1 | #define FASTLED_ALLOW_INTERRUPTS 0 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define NUM_LEDS 125 8 | #define RESET_DELAY 2000 9 | #define FADE_SPEED 8 10 | #define SPARKLE_SPEED 150 11 | 12 | struct Colors { 13 | CRGB newCube = CRGB(0, 0, 255); 14 | CRGB cubeRemoved = CRGB(255, 0, 0); 15 | CRGB playing = CRGB(255, 0, 255); 16 | CRGB stopped = CRGB(0, 0, 0); 17 | CRGB volumeUp = CRGB(0, 255, 255); 18 | CRGB volumeDown = CRGB(0, 255, 0); 19 | CRGB nextSong = CRGB(255, 255, 0); 20 | CRGB previousSong = CRGB(255, 128, 0); 21 | CRGB transitioning = CRGB(128, 0, 255); 22 | }; 23 | 24 | enum Effect { 25 | Sparkle 26 | }; 27 | 28 | class LedController { 29 | public: 30 | LedController(); 31 | void init(); 32 | void handle(); 33 | void flashColor(CRGB color); 34 | void setBaseColor(CRGB color); 35 | void setEffectColor(CRGB color); 36 | void setEffect(Effect effect); 37 | 38 | private: 39 | CRGB _leds[NUM_LEDS]; 40 | CRGB _targetColors[NUM_LEDS]; 41 | CRGB _baseColor; 42 | CRGB _effectColor; 43 | bool _needsUpdate; 44 | Effect _effect; 45 | uint8_t _tick; 46 | void fadePixels(); 47 | void sparkle(); 48 | }; 49 | -------------------------------------------------------------------------------- /Firmware/include/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project header files. 3 | 4 | A header file is a file containing C declarations and macro definitions 5 | to be shared between several project source files. You request the use of a 6 | header file in your project source file (C, C++, etc) located in `src` folder 7 | by including it, with the C preprocessing directive `#include'. 8 | 9 | ```src/main.c 10 | 11 | #include "header.h" 12 | 13 | int main (void) 14 | { 15 | ... 16 | } 17 | ``` 18 | 19 | Including a header file produces the same results as copying the header file 20 | into each source file that needs it. Such copying would be time-consuming 21 | and error-prone. With a header file, the related declarations appear 22 | in only one place. If they need to be changed, they can be changed in one 23 | place, and programs that include the header file will automatically use the 24 | new version when next recompiled. The header file eliminates the labor of 25 | finding and changing all the copies as well as the risk that a failure to 26 | find one copy will result in inconsistencies within a program. 27 | 28 | In C, the usual convention is to give header files names that end with `.h'. 29 | It is most portable to use only letters, digits, dashes, and underscores in 30 | header file names, and at most one dot. 31 | 32 | Read more about using header files in official GCC documentation: 33 | 34 | * Include Syntax 35 | * Include Operation 36 | * Once-Only Headers 37 | * Computed Includes 38 | 39 | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html 40 | -------------------------------------------------------------------------------- /Firmware/src/RFIDReader.cpp: -------------------------------------------------------------------------------- 1 | #include "RFIDReader.h" 2 | 3 | RFIDReader::RFIDReader() : _mfrc522(MFRC522_SS_PIN, MFRC522_RST_PIN){ 4 | _currentCube = NO_CUBE_IDENTIFIER; 5 | _checkCount = 0; 6 | } 7 | 8 | void RFIDReader::init() { 9 | SPI.begin(); 10 | delay(50); 11 | _mfrc522.PCD_Reset(); 12 | delay(50); 13 | _mfrc522.PCD_Init(); 14 | } 15 | 16 | void RFIDReader::handle() { 17 | if (_readTimer > RFID_READ_INTERVAL) { 18 | readCube(); 19 | 20 | _readTimer = 0; 21 | } 22 | } 23 | 24 | void RFIDReader::setCubeChangeCallback(CubeChangeCallback callback) { 25 | _cubeChangedCallback = callback; 26 | } 27 | 28 | bool RFIDReader::cubePresent() { 29 | return _currentCube != NO_CUBE_IDENTIFIER; 30 | } 31 | 32 | void RFIDReader::readCube() { 33 | if (_checkCount > RFID_CHECK_REPEAT) { 34 | changeCubeIfDifferent(NO_CUBE_IDENTIFIER); 35 | _checkCount = 0; 36 | return; 37 | } 38 | 39 | if ( !_mfrc522.PICC_IsNewCardPresent() || !_mfrc522.PICC_ReadCardSerial()) { 40 | _checkCount++; 41 | return; 42 | } 43 | 44 | _checkCount = 0; 45 | char uid[16]; 46 | sprintf(uid, "%02x:%02x:%02x:%02x", _mfrc522.uid.uidByte[0], _mfrc522.uid.uidByte[1], _mfrc522.uid.uidByte[2], _mfrc522.uid.uidByte[3]); 47 | changeCubeIfDifferent(String(uid)); 48 | } 49 | 50 | bool RFIDReader::isChanged(String cubeUID) { 51 | return strcmp(cubeUID.c_str(), _currentCube.c_str()) != 0; 52 | } 53 | 54 | void RFIDReader::cubeChanged(String cubeUID) { 55 | if (RFID_DEBUG) { 56 | Serial.println(String("CubeUID: " + cubeUID)); 57 | } 58 | changeTimer = 0; 59 | _currentCube = cubeUID; 60 | _cubeChangedCallback(cubeUID); 61 | } 62 | 63 | void RFIDReader::changeCubeIfDifferent(String cubeUID) { 64 | if (isChanged(cubeUID)) { 65 | cubeChanged(cubeUID); 66 | } 67 | } -------------------------------------------------------------------------------- /Firmware/.travis.yml: -------------------------------------------------------------------------------- 1 | # Continuous Integration (CI) is the practice, in software 2 | # engineering, of merging all developer working copies with a shared mainline 3 | # several times a day < https://docs.platformio.org/page/ci/index.html > 4 | # 5 | # Documentation: 6 | # 7 | # * Travis CI Embedded Builds with PlatformIO 8 | # < https://docs.travis-ci.com/user/integration/platformio/ > 9 | # 10 | # * PlatformIO integration with Travis CI 11 | # < https://docs.platformio.org/page/ci/travis.html > 12 | # 13 | # * User Guide for `platformio ci` command 14 | # < https://docs.platformio.org/page/userguide/cmd_ci.html > 15 | # 16 | # 17 | # Please choose one of the following templates (proposed below) and uncomment 18 | # it (remove "# " before each line) or use own configuration according to the 19 | # Travis CI documentation (see above). 20 | # 21 | 22 | 23 | # 24 | # Template #1: General project. Test it using existing `platformio.ini`. 25 | # 26 | 27 | # language: python 28 | # python: 29 | # - "2.7" 30 | # 31 | # sudo: false 32 | # cache: 33 | # directories: 34 | # - "~/.platformio" 35 | # 36 | # install: 37 | # - pip install -U platformio 38 | # - platformio update 39 | # 40 | # script: 41 | # - platformio run 42 | 43 | 44 | # 45 | # Template #2: The project is intended to be used as a library with examples. 46 | # 47 | 48 | # language: python 49 | # python: 50 | # - "2.7" 51 | # 52 | # sudo: false 53 | # cache: 54 | # directories: 55 | # - "~/.platformio" 56 | # 57 | # env: 58 | # - PLATFORMIO_CI_SRC=path/to/test/file.c 59 | # - PLATFORMIO_CI_SRC=examples/file.ino 60 | # - PLATFORMIO_CI_SRC=path/to/test/directory 61 | # 62 | # install: 63 | # - pip install -U platformio 64 | # - platformio update 65 | # 66 | # script: 67 | # - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N 68 | -------------------------------------------------------------------------------- /Firmware/src/HTTPManager.cpp: -------------------------------------------------------------------------------- 1 | #include "HTTPManager.h" 2 | #include 3 | 4 | 5 | HTTPManager::HTTPManager() { 6 | } 7 | 8 | void HTTPManager::init() { 9 | } 10 | 11 | void HTTPManager::handle() { 12 | if (_stateUpdateTimer > STATE_UPDATE_INTERVAL) { 13 | checkState(); 14 | _stateUpdateTimer = 0; 15 | } 16 | } 17 | 18 | void HTTPManager::publishCubeIdentifier(String cubeUID) { 19 | makeRequest("cube/" + cubeUID); 20 | } 21 | 22 | void HTTPManager::setPlayStateChangedCallback(PlayStateChangedCallback callback) { 23 | _playStateChangedCallback = callback; 24 | } 25 | 26 | void HTTPManager::changeVolume(VolumeChange change) { 27 | makeRequest("volume/" + String(change == Up ? "up" : "down")); 28 | } 29 | 30 | void HTTPManager::skipSong(SkipDirection direction) { 31 | makeRequest("skip/" + String(direction == Next ? "next" : "previous")); 32 | } 33 | 34 | void HTTPManager::log(String string) { 35 | makeRequest("log/" + string); 36 | } 37 | 38 | void HTTPManager::checkState() { 39 | String state = makeRequest("state"); 40 | if (state != "" && state != _lastState) { 41 | Serial.println(state); 42 | 43 | if (state == String("PLAYING")) { 44 | setPlayState(Playing); 45 | } else if (state == String("TRANSITIONING")) { 46 | setPlayState(Transitioning); 47 | } else { 48 | setPlayState(Stopped); 49 | } 50 | 51 | _lastState = state; 52 | } 53 | } 54 | 55 | void HTTPManager::setPlayState(PlayState state) { 56 | playState = state; 57 | _playStateChangedCallback(state); 58 | } 59 | 60 | String HTTPManager::serverUrl(String endpoint) { 61 | return String("http://") + String(_config.http_server) + ":" + String(_config.http_port) + "/" + endpoint; 62 | } 63 | 64 | String HTTPManager::makeRequest(String uri) { 65 | HTTPClient http; 66 | 67 | String url = serverUrl(uri); 68 | http.begin(url); 69 | int responseCode = http.GET(); 70 | String response = responseCode == HTTP_CODE_OK ? http.getString() : ""; 71 | 72 | if (HTTP_DEBUG) { 73 | Serial.print(url); 74 | Serial.print(" ("); 75 | Serial.print(responseCode); 76 | Serial.print("): "); 77 | Serial.println(response); 78 | } 79 | 80 | return response; 81 | } -------------------------------------------------------------------------------- /Firmware/src/MQTTManager.cpp: -------------------------------------------------------------------------------- 1 | #include "MQTTManager.h" 2 | 3 | MQTTManager::MQTTManager() : _client(_espClient) { 4 | } 5 | 6 | void MQTTManager::init() { 7 | randomSeed(micros()); 8 | _client.setServer(_config.mqtt_server, 1883); 9 | using namespace std::placeholders; 10 | _client.setCallback(std::bind(&MQTTManager::messageCallback, this, _1, _2, _3)); 11 | } 12 | 13 | void MQTTManager::handle() { 14 | checkConnection(); 15 | _client.loop(); 16 | } 17 | 18 | void MQTTManager::publishCubeIdentifier(String cubeUID) { 19 | checkConnection(); 20 | _client.publish("musicubes/cube", cubeUID.c_str()); 21 | } 22 | 23 | void MQTTManager::publishButtonState(uint8_t buttonIndex, bool state) { 24 | checkConnection(); 25 | String topic = String("musicubes/buttons/" + String(buttonIndex, 10)); 26 | String stateString = state ? "1" : "0"; 27 | _client.publish(topic.c_str(), stateString.c_str()); 28 | } 29 | 30 | void MQTTManager::setPlayStateChangedCallback(PlayStateChangedCallback callback) { 31 | _playStateChangedCallback = callback; 32 | } 33 | 34 | void MQTTManager::checkConnection() { 35 | // Loop until we're reconnected 36 | while (!_client.connected()) { 37 | // Create a random _client ID 38 | String clientId = "MusiCubes-"; 39 | clientId += String(random(0xffff), HEX); 40 | // Attempt to connect 41 | if (_client.connect(clientId.c_str(), _config.mqtt_user, _config.mqtt_password, "musicubes/connected", MQTTQOS2, true, "0")) { 42 | // Connected 43 | IPAddress ip = WiFi.localIP(); 44 | _client.publish("musicubes/connected","1", true); 45 | _client.publish("musicubes/ip", ip.toString().c_str(), true); 46 | _client.subscribe("musicubes/state"); 47 | } else { 48 | delay(250); 49 | } 50 | } 51 | } 52 | 53 | void MQTTManager::messageCallback(char* topic, byte* payload, unsigned int length) { 54 | String message; 55 | for (unsigned int i = 0; i < length; i++) { 56 | message += (char)payload[i]; 57 | } 58 | 59 | if (message == String("PLAYING")) { 60 | _playStateChangedCallback(Playing); 61 | } else if (message == String("TRANSITIONING")) { 62 | _playStateChangedCallback(Transitioning); 63 | } else { 64 | _playStateChangedCallback(Stopped); 65 | } 66 | } -------------------------------------------------------------------------------- /Firmware/src/LedController.cpp: -------------------------------------------------------------------------------- 1 | #include "LedController.h" 2 | 3 | LedController::LedController() 4 | { 5 | _baseColor = CRGB::Black; 6 | _needsUpdate = false; 7 | _effect = Sparkle; 8 | } 9 | 10 | void LedController::init() 11 | { 12 | FastLED.addLeds(_leds, NUM_LEDS); 13 | FastLED.setMaxPowerInVoltsAndMilliamps(5,750); 14 | 15 | FastLED.clear(); 16 | FastLED.show(); 17 | } 18 | 19 | void LedController::handle() 20 | { 21 | _tick++; 22 | 23 | // if (_effect == Sparkle) { 24 | // sparkle(); 25 | // } 26 | if (_needsUpdate) { 27 | if (_tick % FADE_SPEED == 0) { 28 | fadePixels(); 29 | } 30 | } 31 | } 32 | 33 | void LedController::flashColor(CRGB color) { 34 | for (uint8_t i = 0; i < NUM_LEDS; i++) { 35 | _leds[i] = color; 36 | } 37 | 38 | _needsUpdate = true; 39 | } 40 | 41 | void LedController::setBaseColor(CRGB color) { 42 | _baseColor = color; 43 | _needsUpdate = true; 44 | } 45 | 46 | void LedController::setEffectColor(CRGB color) 47 | { 48 | _effectColor = color; 49 | _needsUpdate = true; 50 | } 51 | 52 | void LedController::setEffect(Effect effect) 53 | { 54 | _effect = effect; 55 | _needsUpdate = true; 56 | } 57 | 58 | void LedController::fadePixels() 59 | { 60 | bool stripUpdate = false; 61 | for (uint8_t ledIndex = 0; ledIndex < NUM_LEDS; ledIndex++) { 62 | bool pixelUpdate = false; 63 | 64 | CRGB targetColor = _baseColor; 65 | CRGB currentColor = _leds[ledIndex]; 66 | 67 | if (currentColor.r != targetColor.r) { 68 | currentColor.r += (currentColor.r < targetColor.r) ? 1 : -1; 69 | pixelUpdate = true; 70 | } 71 | if (currentColor.g != targetColor.g) { 72 | currentColor.g += (currentColor.g < targetColor.g) ? 1 : -1; 73 | pixelUpdate = true; 74 | } 75 | if (currentColor.b != targetColor.b) { 76 | currentColor.b += (currentColor.b < targetColor.b) ? 1 : -1; 77 | pixelUpdate = true; 78 | } 79 | 80 | if (pixelUpdate) { 81 | _leds[ledIndex] = currentColor; 82 | stripUpdate = true; 83 | } 84 | 85 | // if (currentColor.r == targetColor.r && 86 | // currentColor.g == targetColor.g && 87 | // currentColor.b == targetColor.b) { 88 | // _targetColors[ledIndex] = _baseColor; 89 | // } 90 | } 91 | if (stripUpdate) { 92 | FastLED.show(); 93 | } else { 94 | _needsUpdate = false; 95 | } 96 | } 97 | 98 | void LedController::sparkle() 99 | { 100 | if (_tick % SPARKLE_SPEED == 0) { 101 | _targetColors[random(NUM_LEDS)] = _effectColor; 102 | _needsUpdate = true; 103 | } 104 | } -------------------------------------------------------------------------------- /Firmware/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "RFIDReader.h" 5 | #include "LedController.h" 6 | #include "HTTPManager.h" 7 | #include "TouchManager.h" 8 | 9 | #define TOUCH_IGNORE_AFTER_CUBE_CHANGE 1000 10 | 11 | LedController ledController; 12 | RFIDReader rfidReader; 13 | HTTPManager httpManager; 14 | TouchManager touchManager; 15 | 16 | // Define the callbacks. The implementation is at the bottom. 17 | void cubeChanged(String cubeUID); 18 | void buttonPressed(uint8_t buttonIndex, bool state); 19 | void playStateChanged(PlayState playState); 20 | 21 | // Setup & Loop 22 | void setup() { 23 | Serial.begin(9600); 24 | ledController.init(); 25 | 26 | WiFiManager wifiManager; 27 | wifiManager.autoConnect("MusiCubes"); 28 | 29 | ArduinoOTA.begin(); 30 | 31 | httpManager.init(); 32 | rfidReader.init(); 33 | touchManager.init(); 34 | 35 | rfidReader.setCubeChangeCallback(cubeChanged); 36 | touchManager.setButtonPressCallback(buttonPressed); 37 | httpManager.setPlayStateChangedCallback(playStateChanged); 38 | 39 | httpManager.log("Booted"); 40 | } 41 | 42 | void loop() { 43 | ArduinoOTA.handle(); 44 | httpManager.handle(); 45 | rfidReader.handle(); 46 | touchManager.handle(); 47 | ledController.handle(); 48 | } 49 | 50 | // Callbacks. 51 | void cubeChanged(String cubeUID) { 52 | Colors colors; 53 | 54 | httpManager.publishCubeIdentifier(cubeUID); 55 | if (rfidReader.cubePresent()) { 56 | ledController.flashColor(colors.newCube); 57 | } else { 58 | ledController.flashColor(colors.cubeRemoved); 59 | } 60 | } 61 | 62 | void playStateChanged(PlayState playState) { 63 | Colors colors; 64 | 65 | switch (playState) { 66 | case Playing: 67 | ledController.setBaseColor(colors.playing); 68 | break; 69 | case Transitioning: 70 | ledController.setBaseColor(colors.transitioning); 71 | default: 72 | ledController.setBaseColor(colors.stopped); 73 | break; 74 | } 75 | } 76 | 77 | void buttonPressed(uint8_t buttonIndex, bool longPress) { 78 | Colors colors; 79 | 80 | if (rfidReader.changeTimer < TOUCH_IGNORE_AFTER_CUBE_CHANGE) { 81 | Serial.println("Touch ignored because the cube has recently changed."); 82 | return; 83 | } 84 | 85 | /* 86 | if (httpManager.playState != Playing) { 87 | Serial.println("Not playing. Ignore button press."); 88 | ledController.flashColor(colors.cubeRemoved); 89 | return; 90 | } 91 | */ 92 | 93 | if (!longPress) { 94 | httpManager.changeVolume(buttonIndex == 0 ? Up : Down); 95 | ledController.flashColor(buttonIndex == 0 ? colors.volumeUp : colors.volumeDown); 96 | } else { 97 | httpManager.skipSong(buttonIndex == 0 ? Next : Previous); 98 | ledController.flashColor(buttonIndex == 0 ? colors.nextSong : colors.previousSong); 99 | } 100 | } -------------------------------------------------------------------------------- /Firmware/src/TouchManager.cpp: -------------------------------------------------------------------------------- 1 | #include "TouchManager.h" 2 | #include 3 | 4 | 5 | #ifndef _BV 6 | #define _BV(bit) (1 << (bit)) 7 | #endif 8 | 9 | TouchManager::TouchManager() { 10 | Wire.begin(TOUCH_SDA, TOUCH_SCL); 11 | } 12 | 13 | void TouchManager::init() { 14 | configureSensors(); 15 | } 16 | 17 | void TouchManager::handle() { 18 | if (_intervalTimer > TOUCH_CHECK_INTERVAL) { 19 | checkStates(); 20 | _intervalTimer = 0; 21 | } 22 | } 23 | 24 | void TouchManager::setButtonPressCallback(ButtonPressCallback callback) { 25 | _buttonPressCallback = callback; 26 | } 27 | 28 | void TouchManager::configureSensors() { 29 | for (uint8_t i = 0; i < TOUCH_SENSORS; i++) { 30 | _sensors[i] = Adafruit_MPR121(); 31 | if (!_sensors[i].begin(_sensorAddresses[i])) { 32 | Serial.println(String("TouchSensor not found: " + i)); 33 | continue; 34 | } 35 | 36 | _sensors[i].setThresholds(TOUCH_THRESHOLD_TOUCH, TOUCH_THRESHOLD_RELEASE); 37 | _sensors[i].writeRegister(MPR121_ECR, 0b00000001); // Only activate sensor 0. 38 | _sensors[i].writeRegister(MPR121_DEBOUNCE, 0b01110111); // Maximum Debounce 39 | _sensors[i].writeRegister(MPR121_CONFIG1, 0b11111111); 40 | _sensors[i].writeRegister(MPR121_CONFIG2, 0b11111111); 41 | 42 | // _sensors[i].writeRegister(MPR121_MHDR, 63); 43 | // _sensors[i].writeRegister(MPR121_NHDR, 0x01); 44 | // _sensors[i].writeRegister(MPR121_NCLR, 0xFF); 45 | _sensors[i].writeRegister(MPR121_FDLR, 0xFF); 46 | 47 | // _sensors[i].writeRegister(MPR121_MHDF, 63); 48 | // _sensors[i].writeRegister(MPR121_NHDF, 0x05); 49 | // _sensors[i].writeRegister(MPR121_NCLF, 0xFF); 50 | _sensors[i].writeRegister(MPR121_FDLF, 0xFF); 51 | 52 | // _sensors[i].writeRegister(MPR121_NHDT, 0x00); 53 | // _sensors[i].writeRegister(MPR121_NCLT, 0xFF); 54 | _sensors[i].writeRegister(MPR121_FDLT, 0xFF); 55 | 56 | } 57 | } 58 | 59 | void TouchManager::checkStates() { 60 | for (uint8_t i = 0; i < TOUCH_SENSORS; i++) { 61 | uint8_t newFields = activeFields(i); 62 | if (newFields != _lastFields[i]) { 63 | if (TOUCH_DEBUG && newFields > 0 && newFields < MINIMUM_NUM_OF_FIELDS_ACTIVE) { 64 | Serial.println("Button " + String(i) + " ignored. Not enough newFields active: " + String(newFields) + " of " + String(MINIMUM_NUM_OF_FIELDS_ACTIVE)); 65 | } 66 | 67 | bool newState = newFields >= MINIMUM_NUM_OF_FIELDS_ACTIVE; 68 | if (newState != _lastStates[i]) { 69 | if (newState == 0) { 70 | if (_touchTimers[i] >= TOUCH_SHORTPRESS) { 71 | if (TOUCH_DEBUG) Serial.println("Button " + String(i) + " released after " + String(_touchTimers[i]) + " ms. Longpress: " + String(_touchTimers[i] >= TOUCH_LONGPRESS)); 72 | _buttonPressCallback(i, _touchTimers[i] >= TOUCH_LONGPRESS); 73 | } else { 74 | if (TOUCH_DEBUG) Serial.println("Button " + String(i) + " ignored. Too short: " + String(_touchTimers[i]) + " ms"); 75 | } 76 | } 77 | _touchTimers[i] = 0; 78 | _lastStates[i] = newState; 79 | _lastFields[i] = newFields; 80 | } 81 | } 82 | } 83 | } 84 | 85 | uint8_t TouchManager::activeFields(uint8_t sensorIndex) { 86 | uint16_t state = _sensors[sensorIndex].touched(); 87 | uint8_t count = 0; 88 | while (state) { 89 | count += state & 0x1; 90 | state >>= 1; 91 | } 92 | return count; 93 | } -------------------------------------------------------------------------------- /Server/index.js: -------------------------------------------------------------------------------- 1 | require('log-timestamp')(function() { return '[' + new Date().toString() + '] ' }); 2 | 3 | var config = require('./config.js') 4 | var playlist = require('./playlist.js') 5 | var express = require('express') 6 | var axios = require('axios') 7 | var app = express() 8 | 9 | const baseUrl = config.sonos.baseUrl + '/' + config.sonos.room + '/' 10 | const CancelToken = axios.CancelToken; 11 | var cancelToken = null 12 | var lastPlayerState = null 13 | var lastCubeUid; 14 | 15 | console.log(playlist) 16 | 17 | /** 18 | * Start music based on a cube UID. 19 | */ 20 | app.get('/cube/:uid', function (req, res) { 21 | if (lastCubeUid === req.params.uid) return res.send('OK'); 22 | 23 | const uri = getMusiCube(req.params.uid) 24 | if (!uri) { 25 | res.send('Unknown MusiCube: ' + req.params.uid) 26 | return console.log('Unknown MusiCube: ' + req.params.uid) 27 | } 28 | requestSonosUri(uri) 29 | lastCubeUid = req.params.uid; 30 | 31 | res.send('OK') 32 | }) 33 | 34 | /** 35 | * Change the volume. 36 | */ 37 | app.get('/volume/:change', function (req, res) { 38 | if (req.params.change === 'up' || req.params.change === 'down') { 39 | requestSonosUri(req.params.change === 'up' ? 'volume/+3' : 'volume/-3', false); 40 | } 41 | 42 | res.send('OK') 43 | }); 44 | 45 | /** 46 | * Skip song. 47 | */ 48 | app.get('/skip/:direction', function (req, res) { 49 | if (req.params.direction === 'next' || req.params.direction === 'previous') { 50 | requestSonosUri(req.params.direction, false) 51 | } 52 | 53 | res.send('OK') 54 | }); 55 | 56 | /** 57 | * Toggle play/pause. 58 | */ 59 | app.get('/playpause', function (req, res) { 60 | requestSonosUri('playpause', false) 61 | 62 | res.send('OK') 63 | }); 64 | 65 | /** 66 | * Log string. 67 | */ 68 | app.get('/log/:string', function (req, res) { 69 | console.log('[' + req.ip + '] ' + req.params.string) 70 | res.send('OK') 71 | }); 72 | 73 | /** 74 | * Fetch player state. 75 | */ 76 | app.get('/state', function (req,res) { 77 | axios.get(baseUrl + 'state') 78 | .then(result => { 79 | res.send(result.data.playbackState) 80 | }) 81 | .catch(e => { 82 | console.log('Unable to fetch player state.') 83 | }) 84 | }) 85 | 86 | /** 87 | * Start webserver. 88 | */ 89 | app.listen(config.http.port, () => console.log(`MusiCubes app listening on port ${config.http.port}!`)) 90 | 91 | /** 92 | * Fetch playlist based on UID. 93 | * 94 | * @param {String} identifier 95 | */ 96 | function getMusiCube(identifier) { 97 | if (identifier == '00:00:00:00') return 'pause' 98 | if (identifier in playlist) return playlist[identifier] 99 | 100 | return false 101 | } 102 | 103 | /** 104 | * Request Sonos http api uri. 105 | * @param {String} uri 106 | * @param {Bool} cancelable 107 | */ 108 | function requestSonosUri(uri, cancelable = true) { 109 | console.log('Requesting: ' + uri) 110 | 111 | if (cancelable && cancelToken) { 112 | cancelToken.cancel(); 113 | } 114 | 115 | var params = {}; 116 | if (cancelable) { 117 | cancelToken = CancelToken.source(); 118 | params = { 119 | cancelToken: cancelToken.token 120 | } 121 | } 122 | 123 | axios.get(baseUrl + uri, params) 124 | .then(result => { 125 | console.log('Request confirmed: ' + uri) 126 | }) 127 | .catch(e => { 128 | if (axios.isCancel(e)) { 129 | return console.log('Request canceled: ', uri); 130 | } 131 | console.log(uri + ' is not a valid endpoint.') 132 | }) 133 | } 134 | -------------------------------------------------------------------------------- /DXF Files/MUSICUBES_LAYER_2-4.dxf: -------------------------------------------------------------------------------- 1 | 0 2 | SECTION 3 | 2 4 | HEADER 5 | 9 6 | $INSUNITS 7 | 70 8 | 4 9 | 9 10 | $ACADVER 11 | 1 12 | AC1014 13 | 9 14 | $HANDSEED 15 | 5 16 | FFFF 17 | 0 18 | ENDSEC 19 | 0 20 | SECTION 21 | 2 22 | TABLES 23 | 0 24 | TABLE 25 | 2 26 | VPORT 27 | 5 28 | 8 29 | 100 30 | AcDbSymbolTable 31 | 0 32 | ENDTAB 33 | 0 34 | TABLE 35 | 2 36 | LTYPE 37 | 5 38 | 5 39 | 100 40 | AcDbSymbolTable 41 | 0 42 | LTYPE 43 | 5 44 | 14 45 | 100 46 | AcDbSymbolTableRecord 47 | 100 48 | AcDbLinetypeTableRecord 49 | 2 50 | BYBLOCK 51 | 70 52 | 0 53 | 0 54 | LTYPE 55 | 5 56 | 15 57 | 100 58 | AcDbSymbolTableRecord 59 | 100 60 | AcDbLinetypeTableRecord 61 | 2 62 | BYLAYER 63 | 70 64 | 0 65 | 0 66 | ENDTAB 67 | 0 68 | TABLE 69 | 2 70 | LAYER 71 | 5 72 | 2 73 | 100 74 | AcDbSymbolTable 75 | 70 76 | 2 77 | 0 78 | LAYER 79 | 5 80 | 50 81 | 100 82 | AcDbSymbolTableRecord 83 | 100 84 | AcDbLayerTableRecord 85 | 2 86 | 0 87 | 70 88 | 0 89 | 6 90 | CONTINUOUS 91 | 0 92 | ENDTAB 93 | 0 94 | TABLE 95 | 2 96 | STYLE 97 | 5 98 | 3 99 | 100 100 | AcDbSymbolTable 101 | 70 102 | 1 103 | 0 104 | STYLE 105 | 5 106 | 11 107 | 100 108 | AcDbSymbolTableRecord 109 | 100 110 | AcDbTextStyleTableRecord 111 | 2 112 | STANDARD 113 | 70 114 | 0 115 | 0 116 | ENDTAB 117 | 0 118 | TABLE 119 | 2 120 | VIEW 121 | 5 122 | 6 123 | 100 124 | AcDbSymbolTable 125 | 70 126 | 0 127 | 0 128 | ENDTAB 129 | 0 130 | TABLE 131 | 2 132 | UCS 133 | 5 134 | 7 135 | 100 136 | AcDbSymbolTable 137 | 70 138 | 0 139 | 0 140 | ENDTAB 141 | 0 142 | TABLE 143 | 2 144 | APPID 145 | 5 146 | 9 147 | 100 148 | AcDbSymbolTable 149 | 70 150 | 2 151 | 0 152 | APPID 153 | 5 154 | 12 155 | 100 156 | AcDbSymbolTableRecord 157 | 100 158 | AcDbRegAppTableRecord 159 | 2 160 | ACAD 161 | 70 162 | 0 163 | 0 164 | ENDTAB 165 | 0 166 | TABLE 167 | 2 168 | DIMSTYLE 169 | 5 170 | A 171 | 100 172 | AcDbSymbolTable 173 | 70 174 | 1 175 | 0 176 | ENDTAB 177 | 0 178 | TABLE 179 | 2 180 | BLOCK_RECORD 181 | 5 182 | 1 183 | 100 184 | AcDbSymbolTable 185 | 70 186 | 1 187 | 0 188 | BLOCK_RECORD 189 | 5 190 | 1F 191 | 100 192 | AcDbSymbolTableRecord 193 | 100 194 | AcDbBlockTableRecord 195 | 2 196 | *MODEL_SPACE 197 | 0 198 | BLOCK_RECORD 199 | 5 200 | 1B 201 | 100 202 | AcDbSymbolTableRecord 203 | 100 204 | AcDbBlockTableRecord 205 | 2 206 | *PAPER_SPACE 207 | 0 208 | ENDTAB 209 | 0 210 | ENDSEC 211 | 0 212 | SECTION 213 | 2 214 | BLOCKS 215 | 0 216 | BLOCK 217 | 5 218 | 20 219 | 100 220 | AcDbEntity 221 | 100 222 | AcDbBlockBegin 223 | 2 224 | *MODEL_SPACE 225 | 0 226 | ENDBLK 227 | 5 228 | 21 229 | 100 230 | AcDbEntity 231 | 100 232 | AcDbBlockEnd 233 | 0 234 | BLOCK 235 | 5 236 | 1C 237 | 100 238 | AcDbEntity 239 | 100 240 | AcDbBlockBegin 241 | 2 242 | *PAPER_SPACE 243 | 0 244 | ENDBLK 245 | 5 246 | 1D 247 | 100 248 | AcDbEntity 249 | 100 250 | AcDbBlockEnd 251 | 0 252 | ENDSEC 253 | 0 254 | SECTION 255 | 2 256 | ENTITIES 257 | 0 258 | LWPOLYLINE 259 | 5 260 | 100 261 | 100 262 | AcDbEntity 263 | 8 264 | 0 265 | 100 266 | AcDbPolyline 267 | 90 268 | 8 269 | 70 270 | 1 271 | 43 272 | 0.0 273 | 10 274 | -261.99999999999983 275 | 20 276 | 135.99999999999994 277 | 10 278 | 9.9999999999999805 279 | 20 280 | 135.99999999999997 281 | 42 282 | -0.41421356237309509 283 | 10 284 | 20 285 | 20 286 | 125.99999999999994 287 | 10 288 | 20 289 | 20 290 | -72.999999999999972 291 | 42 292 | -0.41421356237309515 293 | 10 294 | 10 295 | 20 296 | -82.999999999999986 297 | 10 298 | -261.99999999999994 299 | 20 300 | -83 301 | 42 302 | -0.41421356237309476 303 | 10 304 | -271.99999999999994 305 | 20 306 | -73 307 | 10 308 | -271.99999999999994 309 | 20 310 | 125.99999999999983 311 | 42 312 | -0.41421356237309509 313 | 0 314 | LWPOLYLINE 315 | 5 316 | 101 317 | 100 318 | AcDbEntity 319 | 8 320 | 0 321 | 100 322 | AcDbPolyline 323 | 90 324 | 4 325 | 70 326 | 1 327 | 43 328 | 0.0 329 | 10 330 | -261.99999999999994 331 | 20 332 | -73 333 | 10 334 | -261.99999999999983 335 | 20 336 | 125.99999999999983 337 | 10 338 | 9.9999999999999822 339 | 20 340 | 125.99999999999994 341 | 10 342 | 10 343 | 20 344 | -72.999999999999986 345 | 0 346 | ENDSEC 347 | 0 348 | SECTION 349 | 2 350 | OBJECTS 351 | 0 352 | DICTIONARY 353 | 5 354 | C 355 | 100 356 | AcDbDictionary 357 | 3 358 | ACAD_GROUP 359 | 350 360 | D 361 | 3 362 | ACAD_MLINESTYLE 363 | 350 364 | 17 365 | 0 366 | DICTIONARY 367 | 5 368 | D 369 | 100 370 | AcDbDictionary 371 | 0 372 | DICTIONARY 373 | 5 374 | 1A 375 | 330 376 | C 377 | 100 378 | AcDbDictionary 379 | 0 380 | DICTIONARY 381 | 5 382 | 17 383 | 100 384 | AcDbDictionary 385 | 0 386 | ENDSEC 387 | 0 388 | EOF 389 | -------------------------------------------------------------------------------- /Server/playlist.js: -------------------------------------------------------------------------------- 1 | const playlist = { 2 | // Male 3 | '04:9a:63:b2': 'spotify/now/spotify:user:best-of-the-best:playlist:4Qp9icwIZ545w7rcI5irrW', // Robbie Williams 4 | '04:92:63:b2': 'spotify/now/spotify:user:george_michael:playlist:1Uv1EBo0pL7BzZ40afDrSi', // George Michael 5 | '04:8b:62:b2': 'spotify/now/spotify:user:kelchner:playlist:7ztZBGd2s1iTCPEQUiNJ7i', // Michael Bublé 6 | '04:96:63:b2': 'spotify/now/spotify:album:3VWrUk4vBznMYXGMPc7dRB', // Queen 7 | '04:8e:63:b2': 'spotify/now/spotify:album:1cW0de5T5fdedlS4YqvyCv', // Lenny Kravitz 8 | '04:29:3c:ba': 'spotify/now/spotify:user:ogietayag:playlist:6Uqvol9bqJkxEDxZFDdm3h', // Dire Straits 9 | 10 | // Female 11 | '04:d2:3d:ba': 'spotify/now/spotify:user:micahjesse:playlist:4AE2ERkTNZjhrhMQCx5DA5', // Beyonce 12 | '04:25:3c:ba': 'spotify/now/spotify:user:hafizarif13:playlist:69kTva1V51Ow4fQFP1LUxG', // Taylor Swift 13 | '04:ce:3d:ba': 'spotify/now/spotify:user:fredrikkarlsson96:playlist:62HtzJxggBFb1E2O005bUb', // Lady Gaga 14 | '04:c1:3d:ba': 'spotify/now/spotify:user:1191809760:playlist:76qjUjaQk7F9cBtoniKP1D', // Katy Perry 15 | '04:d6:3d:ba': 'spotify/now/spotify:user:felipefoggia:playlist:33EL1piBW36KuSiPGV6QRt', // Ariana Grande 16 | '04:da:3d:ba': 'spotify/now/spotify:user:216h7ziuz78j5tsieu71c4egy:playlist:0DZps7m41jMAhJO3dvNH3a', // Rihanna 17 | 18 | // Alt 19 | '04:d7:64:b2': 'spotify/now/spotify:user:franjav1984:playlist:2KVqduM0LCzmY5zfz2DDcQ', // Enigma 20 | '04:22:3d:ba': 'spotify/now/spotify:album:2FhkO0XspLqBtcanjn5Uzk', // Enya 21 | '04:df:64:b2': 'spotify/now/spotify:album:578k9Ef0aNVmpRxkTiQgua', // Bliss 22 | '04:db:64:b2': 'spotify/now/spotify:album:6xKKUwzK45UoA2wO5w1wYd', // Conjure One 23 | 24 | // EDM 25 | '04:31:3c:ba': 'spotify/now/spotify:user:alainpossiel:playlist:7q0BbZVzYfPAZJPk1KE7KE', // Martin Garixx 26 | '04:97:3d:ba': 'spotify/now/spotify:user:1185996266:playlist:1pdfLg56vOl9TYPMeKg9jG', // Massive Attack 27 | '04:9f:3d:ba': 'spotify/now/spotify:user:jtron44:playlist:1VUVQp70v2jULYnjd0JRln', // Tiesto 28 | '04:93:3d:ba': 'spotify/now/spotify:user:1128800583:playlist:4b7jEl8w7xtuieOLw3V6sj', // Avici 29 | '04:8f:3d:ba': 'spotify/now/spotify:user:daniel_lawson9999:playlist:6jeSKyPBU24fdGlYfOaSnx', // Daft Punk 30 | '04:9b:3d:ba': 'spotify/now/spotify:user:11129072476:playlist:5jsEhfhi9oL5NJ1hhS1pW0', // Armin van Buuren 31 | 32 | // Radio 33 | '04:8c:60:b2': 'favorite/BLUE MARLIN IBIZA RADIO', // Blue Marlin 34 | '04:ac:62:b2': 'favorite/Classic', // Klassiek 35 | '04:a8:62:b2': 'favorite/Koffee', // Koffee 36 | '04:0e:3d:ba': 'spotify/now/spotify:user:defected.records:playlist:08M2kTqmlPNHygrNfrZJuQ', // Defected 37 | '04:90:60:b2': 'favorite/538', // 538 38 | '04:8d:61:b2': 'favorite/Ibiza Global Radio', // Ibiza Global Radio 39 | 40 | // Moments 41 | '04:16:3d:ba': 'spotify/now/spotify:user:spotify:playlist:37i9dQZF1DX0Yxoavh5qJV', // Kerst 42 | '04:ec:3d:ba': 'spotify/now/spotify:user:1141402282:playlist:0y9f8tbQEyA2yJUCvQB9sw', // Birthday 43 | '04:f0:3d:ba': 'spotify/now/spotify:user:11175854168:playlist:20iG6ZtP6vDr146idkQCv4', // Sinterklaas 44 | 45 | // Kids 46 | '04:0a:3d:ba': 'spotify/now/spotify:user:c.koekoek:playlist:0MpXwWIaYmiodOK6gPlBbM', // Juf Roos 47 | '04:c6:3d:ba': 'spotify/now/spotify:album:1LVBv18hDtL8oyXJjARzSR', // Fien en Teun 48 | '04:ca:3d:ba': 'spotify/now/spotify:user:artsycloe90:playlist:5cgpouN7Z53NTyENJXoi7e', // Disney 49 | '04:de:3d:ba': 'playlist/kinderliedjes', // Kinderliedjes 50 | 51 | // Playlists 52 | '04:ca:64:b2': 'favorite/Lekkere%20nummertjes', // Lekkere Nummertjes 53 | '04:1a:3d:ba': 'spotify/now/spotify:user:9nkutxcrnrdggvmk4qtj8a2jk:playlist:3WX9wqcPBnLqGR2pErkZ1G', // Chillout 54 | '04:c3:63:b2': 'spotify/now/spotify:user:21ifzjxggdajdpc4w6iqxslkq:playlist:4hfe8itOfwwijAHHOlI6pp', // Top 40 55 | '04:ce:64:b2': 'favorite/Discover%20Weekly', // Discover Weekly 56 | '04:d3:64:b2': 'spotify/now/spotify:user:spotify:playlist:37i9dQZF1DWZz0dmtcndFR', // Party 57 | 58 | // Moods 59 | '04:b8:3d:ba': 'spotify/now/spotify:user:spotify:playlist:37i9dQZF1DX5dJCW6dyCUe', // Morning 60 | '04:9a:62:b2': 'spotify/now/spotify:user:vipmusik-fr:playlist:7kzI9Z2lU67PzhRaaiacC0', // Summer 61 | '04:a3:62:b2': 'spotify/now/spotify:user:eating_tv:playlist:0e1zsySwa4K8yu96GIBVZq', // Work 62 | '04:9e:62:b2': 'spotify/now/spotify:user:spotify:playlist:37i9dQZF1DX4H7FFUM2osB', // Winter 63 | '04:1e:3d:ba': 'spotify/now/spotify:user:spotify:playlist:37i9dQZF1DWZz0dmtcndFR', // Party 64 | '04:bc:3d:ba': 'spotify/now/spotify:user:spotify:playlist:37i9dQZF1DWU0ScTcjJBdj', // Relaxing 65 | } 66 | 67 | module.exports = playlist 68 | -------------------------------------------------------------------------------- /DXF Files/MUSICUBES_LAYER_1.dxf: -------------------------------------------------------------------------------- 1 | 0 2 | SECTION 3 | 2 4 | HEADER 5 | 9 6 | $INSUNITS 7 | 70 8 | 4 9 | 9 10 | $ACADVER 11 | 1 12 | AC1014 13 | 9 14 | $HANDSEED 15 | 5 16 | FFFF 17 | 0 18 | ENDSEC 19 | 0 20 | SECTION 21 | 2 22 | TABLES 23 | 0 24 | TABLE 25 | 2 26 | VPORT 27 | 5 28 | 8 29 | 100 30 | AcDbSymbolTable 31 | 0 32 | ENDTAB 33 | 0 34 | TABLE 35 | 2 36 | LTYPE 37 | 5 38 | 5 39 | 100 40 | AcDbSymbolTable 41 | 0 42 | LTYPE 43 | 5 44 | 14 45 | 100 46 | AcDbSymbolTableRecord 47 | 100 48 | AcDbLinetypeTableRecord 49 | 2 50 | BYBLOCK 51 | 70 52 | 0 53 | 0 54 | LTYPE 55 | 5 56 | 15 57 | 100 58 | AcDbSymbolTableRecord 59 | 100 60 | AcDbLinetypeTableRecord 61 | 2 62 | BYLAYER 63 | 70 64 | 0 65 | 0 66 | ENDTAB 67 | 0 68 | TABLE 69 | 2 70 | LAYER 71 | 5 72 | 2 73 | 100 74 | AcDbSymbolTable 75 | 70 76 | 2 77 | 0 78 | LAYER 79 | 5 80 | 50 81 | 100 82 | AcDbSymbolTableRecord 83 | 100 84 | AcDbLayerTableRecord 85 | 2 86 | 0 87 | 70 88 | 0 89 | 6 90 | CONTINUOUS 91 | 0 92 | ENDTAB 93 | 0 94 | TABLE 95 | 2 96 | STYLE 97 | 5 98 | 3 99 | 100 100 | AcDbSymbolTable 101 | 70 102 | 1 103 | 0 104 | STYLE 105 | 5 106 | 11 107 | 100 108 | AcDbSymbolTableRecord 109 | 100 110 | AcDbTextStyleTableRecord 111 | 2 112 | STANDARD 113 | 70 114 | 0 115 | 0 116 | ENDTAB 117 | 0 118 | TABLE 119 | 2 120 | VIEW 121 | 5 122 | 6 123 | 100 124 | AcDbSymbolTable 125 | 70 126 | 0 127 | 0 128 | ENDTAB 129 | 0 130 | TABLE 131 | 2 132 | UCS 133 | 5 134 | 7 135 | 100 136 | AcDbSymbolTable 137 | 70 138 | 0 139 | 0 140 | ENDTAB 141 | 0 142 | TABLE 143 | 2 144 | APPID 145 | 5 146 | 9 147 | 100 148 | AcDbSymbolTable 149 | 70 150 | 2 151 | 0 152 | APPID 153 | 5 154 | 12 155 | 100 156 | AcDbSymbolTableRecord 157 | 100 158 | AcDbRegAppTableRecord 159 | 2 160 | ACAD 161 | 70 162 | 0 163 | 0 164 | ENDTAB 165 | 0 166 | TABLE 167 | 2 168 | DIMSTYLE 169 | 5 170 | A 171 | 100 172 | AcDbSymbolTable 173 | 70 174 | 1 175 | 0 176 | ENDTAB 177 | 0 178 | TABLE 179 | 2 180 | BLOCK_RECORD 181 | 5 182 | 1 183 | 100 184 | AcDbSymbolTable 185 | 70 186 | 1 187 | 0 188 | BLOCK_RECORD 189 | 5 190 | 1F 191 | 100 192 | AcDbSymbolTableRecord 193 | 100 194 | AcDbBlockTableRecord 195 | 2 196 | *MODEL_SPACE 197 | 0 198 | BLOCK_RECORD 199 | 5 200 | 1B 201 | 100 202 | AcDbSymbolTableRecord 203 | 100 204 | AcDbBlockTableRecord 205 | 2 206 | *PAPER_SPACE 207 | 0 208 | ENDTAB 209 | 0 210 | ENDSEC 211 | 0 212 | SECTION 213 | 2 214 | BLOCKS 215 | 0 216 | BLOCK 217 | 5 218 | 20 219 | 100 220 | AcDbEntity 221 | 100 222 | AcDbBlockBegin 223 | 2 224 | *MODEL_SPACE 225 | 0 226 | ENDBLK 227 | 5 228 | 21 229 | 100 230 | AcDbEntity 231 | 100 232 | AcDbBlockEnd 233 | 0 234 | BLOCK 235 | 5 236 | 1C 237 | 100 238 | AcDbEntity 239 | 100 240 | AcDbBlockBegin 241 | 2 242 | *PAPER_SPACE 243 | 0 244 | ENDBLK 245 | 5 246 | 1D 247 | 100 248 | AcDbEntity 249 | 100 250 | AcDbBlockEnd 251 | 0 252 | ENDSEC 253 | 0 254 | SECTION 255 | 2 256 | ENTITIES 257 | 0 258 | LWPOLYLINE 259 | 5 260 | 100 261 | 100 262 | AcDbEntity 263 | 8 264 | 0 265 | 100 266 | AcDbPolyline 267 | 90 268 | 8 269 | 70 270 | 1 271 | 43 272 | 0.0 273 | 10 274 | 20 275 | 20 276 | -72.999999999999986 277 | 42 278 | -0.41421356237309509 279 | 10 280 | 10 281 | 20 282 | -82.999999999999986 283 | 10 284 | -261.99999999999994 285 | 20 286 | -83 287 | 42 288 | -0.41421356237309476 289 | 10 290 | -271.99999999999994 291 | 20 292 | -73 293 | 10 294 | -271.99999999999994 295 | 20 296 | 125.99999999999983 297 | 42 298 | -0.41421356237309509 299 | 10 300 | -261.99999999999983 301 | 20 302 | 135.99999999999994 303 | 10 304 | 9.9999999999999805 305 | 20 306 | 135.99999999999997 307 | 42 308 | -0.41421356237309509 309 | 10 310 | 20 311 | 20 312 | 125.99999999999994 313 | 0 314 | LWPOLYLINE 315 | 5 316 | 101 317 | 100 318 | AcDbEntity 319 | 8 320 | 0 321 | 100 322 | AcDbPolyline 323 | 90 324 | 4 325 | 70 326 | 1 327 | 43 328 | 0.0 329 | 10 330 | -63 331 | 20 332 | 115.99999999999994 333 | 10 334 | 2.2204460492503131e-15 335 | 20 336 | 115.99999999999994 337 | 10 338 | 8.8817841970012523e-15 339 | 20 340 | 62.999999999999936 341 | 10 342 | -63 343 | 20 344 | 62.999999999999936 345 | 0 346 | LWPOLYLINE 347 | 5 348 | 102 349 | 100 350 | AcDbEntity 351 | 8 352 | 0 353 | 100 354 | AcDbPolyline 355 | 90 356 | 4 357 | 70 358 | 1 359 | 43 360 | 0.0 361 | 10 362 | 0 363 | 20 364 | -63.000000000000014 365 | 10 366 | -63 367 | 20 368 | -63.000000000000007 369 | 10 370 | -63 371 | 20 372 | -9.9999999999999858 373 | 10 374 | 3.3306690738754696e-15 375 | 20 376 | -10.000000000000009 377 | 0 378 | LWPOLYLINE 379 | 5 380 | 103 381 | 100 382 | AcDbEntity 383 | 8 384 | 0 385 | 100 386 | AcDbPolyline 387 | 90 388 | 8 389 | 70 390 | 1 391 | 43 392 | 0.0 393 | 10 394 | 10 395 | 20 396 | -82.999999999999986 397 | 10 398 | -261.99999999999994 399 | 20 400 | -83 401 | 42 402 | -0.41421356237309342 403 | 10 404 | -271.99999999999994 405 | 20 406 | -73 407 | 10 408 | -271.99999999999994 409 | 20 410 | 125.99999999999983 411 | 42 412 | -0.41421356237309659 413 | 10 414 | -261.99999999999983 415 | 20 416 | 135.99999999999994 417 | 10 418 | 9.9999999999999805 419 | 20 420 | 135.99999999999994 421 | 42 422 | -0.41421356237309515 423 | 10 424 | 19.999999999999982 425 | 20 426 | 125.99999999999994 427 | 10 428 | 20 429 | 20 430 | -72.999999999999986 431 | 42 432 | -0.41421356237309526 433 | 0 434 | ENDSEC 435 | 0 436 | SECTION 437 | 2 438 | OBJECTS 439 | 0 440 | DICTIONARY 441 | 5 442 | C 443 | 100 444 | AcDbDictionary 445 | 3 446 | ACAD_GROUP 447 | 350 448 | D 449 | 3 450 | ACAD_MLINESTYLE 451 | 350 452 | 17 453 | 0 454 | DICTIONARY 455 | 5 456 | D 457 | 100 458 | AcDbDictionary 459 | 0 460 | DICTIONARY 461 | 5 462 | 1A 463 | 330 464 | C 465 | 100 466 | AcDbDictionary 467 | 0 468 | DICTIONARY 469 | 5 470 | 17 471 | 100 472 | AcDbDictionary 473 | 0 474 | ENDSEC 475 | 0 476 | EOF 477 | -------------------------------------------------------------------------------- /DXF Files/MUSICUBES_LAYER_0.dxf: -------------------------------------------------------------------------------- 1 | 0 2 | SECTION 3 | 2 4 | HEADER 5 | 9 6 | $INSUNITS 7 | 70 8 | 4 9 | 9 10 | $ACADVER 11 | 1 12 | AC1014 13 | 9 14 | $HANDSEED 15 | 5 16 | FFFF 17 | 0 18 | ENDSEC 19 | 0 20 | SECTION 21 | 2 22 | TABLES 23 | 0 24 | TABLE 25 | 2 26 | VPORT 27 | 5 28 | 8 29 | 100 30 | AcDbSymbolTable 31 | 0 32 | ENDTAB 33 | 0 34 | TABLE 35 | 2 36 | LTYPE 37 | 5 38 | 5 39 | 100 40 | AcDbSymbolTable 41 | 0 42 | LTYPE 43 | 5 44 | 14 45 | 100 46 | AcDbSymbolTableRecord 47 | 100 48 | AcDbLinetypeTableRecord 49 | 2 50 | BYBLOCK 51 | 70 52 | 0 53 | 0 54 | LTYPE 55 | 5 56 | 15 57 | 100 58 | AcDbSymbolTableRecord 59 | 100 60 | AcDbLinetypeTableRecord 61 | 2 62 | BYLAYER 63 | 70 64 | 0 65 | 0 66 | ENDTAB 67 | 0 68 | TABLE 69 | 2 70 | LAYER 71 | 5 72 | 2 73 | 100 74 | AcDbSymbolTable 75 | 70 76 | 2 77 | 0 78 | LAYER 79 | 5 80 | 50 81 | 100 82 | AcDbSymbolTableRecord 83 | 100 84 | AcDbLayerTableRecord 85 | 2 86 | 0 87 | 70 88 | 0 89 | 6 90 | CONTINUOUS 91 | 0 92 | ENDTAB 93 | 0 94 | TABLE 95 | 2 96 | STYLE 97 | 5 98 | 3 99 | 100 100 | AcDbSymbolTable 101 | 70 102 | 1 103 | 0 104 | STYLE 105 | 5 106 | 11 107 | 100 108 | AcDbSymbolTableRecord 109 | 100 110 | AcDbTextStyleTableRecord 111 | 2 112 | STANDARD 113 | 70 114 | 0 115 | 0 116 | ENDTAB 117 | 0 118 | TABLE 119 | 2 120 | VIEW 121 | 5 122 | 6 123 | 100 124 | AcDbSymbolTable 125 | 70 126 | 0 127 | 0 128 | ENDTAB 129 | 0 130 | TABLE 131 | 2 132 | UCS 133 | 5 134 | 7 135 | 100 136 | AcDbSymbolTable 137 | 70 138 | 0 139 | 0 140 | ENDTAB 141 | 0 142 | TABLE 143 | 2 144 | APPID 145 | 5 146 | 9 147 | 100 148 | AcDbSymbolTable 149 | 70 150 | 2 151 | 0 152 | APPID 153 | 5 154 | 12 155 | 100 156 | AcDbSymbolTableRecord 157 | 100 158 | AcDbRegAppTableRecord 159 | 2 160 | ACAD 161 | 70 162 | 0 163 | 0 164 | ENDTAB 165 | 0 166 | TABLE 167 | 2 168 | DIMSTYLE 169 | 5 170 | A 171 | 100 172 | AcDbSymbolTable 173 | 70 174 | 1 175 | 0 176 | ENDTAB 177 | 0 178 | TABLE 179 | 2 180 | BLOCK_RECORD 181 | 5 182 | 1 183 | 100 184 | AcDbSymbolTable 185 | 70 186 | 1 187 | 0 188 | BLOCK_RECORD 189 | 5 190 | 1F 191 | 100 192 | AcDbSymbolTableRecord 193 | 100 194 | AcDbBlockTableRecord 195 | 2 196 | *MODEL_SPACE 197 | 0 198 | BLOCK_RECORD 199 | 5 200 | 1B 201 | 100 202 | AcDbSymbolTableRecord 203 | 100 204 | AcDbBlockTableRecord 205 | 2 206 | *PAPER_SPACE 207 | 0 208 | ENDTAB 209 | 0 210 | ENDSEC 211 | 0 212 | SECTION 213 | 2 214 | BLOCKS 215 | 0 216 | BLOCK 217 | 5 218 | 20 219 | 100 220 | AcDbEntity 221 | 100 222 | AcDbBlockBegin 223 | 2 224 | *MODEL_SPACE 225 | 0 226 | ENDBLK 227 | 5 228 | 21 229 | 100 230 | AcDbEntity 231 | 100 232 | AcDbBlockEnd 233 | 0 234 | BLOCK 235 | 5 236 | 1C 237 | 100 238 | AcDbEntity 239 | 100 240 | AcDbBlockBegin 241 | 2 242 | *PAPER_SPACE 243 | 0 244 | ENDBLK 245 | 5 246 | 1D 247 | 100 248 | AcDbEntity 249 | 100 250 | AcDbBlockEnd 251 | 0 252 | ENDSEC 253 | 0 254 | SECTION 255 | 2 256 | ENTITIES 257 | 0 258 | LWPOLYLINE 259 | 5 260 | 100 261 | 100 262 | AcDbEntity 263 | 8 264 | 0 265 | 100 266 | AcDbPolyline 267 | 90 268 | 4 269 | 70 270 | 1 271 | 43 272 | 0.0 273 | 10 274 | -53 275 | 20 276 | -5.3422821943161069e-17 277 | 10 278 | 0 279 | 20 280 | 0 281 | 10 282 | 0 283 | 20 284 | -53 285 | 10 286 | -53 287 | 20 288 | -53 289 | 0 290 | LWPOLYLINE 291 | 5 292 | 101 293 | 100 294 | AcDbEntity 295 | 8 296 | 0 297 | 100 298 | AcDbPolyline 299 | 90 300 | 4 301 | 70 302 | 1 303 | 43 304 | 0.0 305 | 10 306 | -73 307 | 20 308 | 0 309 | 10 310 | -126.00000000000001 311 | 20 312 | 0 313 | 10 314 | -126.00000000000001 315 | 20 316 | -53 317 | 10 318 | -73 319 | 20 320 | -53 321 | 0 322 | LWPOLYLINE 323 | 5 324 | 102 325 | 100 326 | AcDbEntity 327 | 8 328 | 0 329 | 100 330 | AcDbPolyline 331 | 90 332 | 4 333 | 70 334 | 1 335 | 43 336 | 0.0 337 | 10 338 | -135.99999999999997 339 | 20 340 | 4.4408920985006262e-15 341 | 10 342 | -189 343 | 20 344 | 8.8817841970012523e-15 345 | 10 346 | -189 347 | 20 348 | -53 349 | 10 350 | -135.99999999999997 351 | 20 352 | -53.000000000000007 353 | 0 354 | LWPOLYLINE 355 | 5 356 | 103 357 | 100 358 | AcDbEntity 359 | 8 360 | 0 361 | 100 362 | AcDbPolyline 363 | 90 364 | 4 365 | 70 366 | 1 367 | 43 368 | 0.0 369 | 10 370 | -199 371 | 20 372 | -4.4408920985006262e-15 373 | 10 374 | -252 375 | 20 376 | -8.8817841970012523e-15 377 | 10 378 | -252 379 | 20 380 | -53 381 | 10 382 | -199.00000000000003 383 | 20 384 | -52.999999999999986 385 | 0 386 | LWPOLYLINE 387 | 5 388 | 104 389 | 100 390 | AcDbEntity 391 | 8 392 | 0 393 | 100 394 | AcDbPolyline 395 | 90 396 | 4 397 | 70 398 | 1 399 | 43 400 | 0.0 401 | 10 402 | -199.00000000000006 403 | 20 404 | -63 405 | 10 406 | -252.00000000000003 407 | 20 408 | -63 409 | 10 410 | -252 411 | 20 412 | -115.99999999999997 413 | 10 414 | -199.00000000000006 415 | 20 416 | -115.99999999999997 417 | 0 418 | LWPOLYLINE 419 | 5 420 | 105 421 | 100 422 | AcDbEntity 423 | 8 424 | 0 425 | 100 426 | AcDbPolyline 427 | 90 428 | 4 429 | 70 430 | 1 431 | 43 432 | 0.0 433 | 10 434 | -135.99999999999994 435 | 20 436 | -62.999999999999957 437 | 10 438 | -188.99999999999994 439 | 20 440 | -62.999999999999957 441 | 10 442 | -189 443 | 20 444 | -115.99999999999997 445 | 10 446 | -135.99999999999997 447 | 20 448 | -115.99999999999994 449 | 0 450 | LWPOLYLINE 451 | 5 452 | 106 453 | 100 454 | AcDbEntity 455 | 8 456 | 0 457 | 100 458 | AcDbPolyline 459 | 90 460 | 4 461 | 70 462 | 1 463 | 43 464 | 0.0 465 | 10 466 | -73 467 | 20 468 | -62.999999999999964 469 | 10 470 | -125.99999999999997 471 | 20 472 | -62.999999999999964 473 | 10 474 | -126.00000000000001 475 | 20 476 | -115.99999999999994 477 | 10 478 | -73 479 | 20 480 | -115.99999999999994 481 | 0 482 | LWPOLYLINE 483 | 5 484 | 107 485 | 100 486 | AcDbEntity 487 | 8 488 | 0 489 | 100 490 | AcDbPolyline 491 | 90 492 | 4 493 | 70 494 | 1 495 | 43 496 | 0.0 497 | 10 498 | -199 499 | 20 500 | 62.999999999999979 501 | 10 502 | -251.99999999999994 503 | 20 504 | 62.999999999999972 505 | 10 506 | -251.99999999999994 507 | 20 508 | 10.000000000000004 509 | 10 510 | -199 511 | 20 512 | 9.9999999999999911 513 | 0 514 | LWPOLYLINE 515 | 5 516 | 108 517 | 100 518 | AcDbEntity 519 | 8 520 | 0 521 | 100 522 | AcDbPolyline 523 | 90 524 | 4 525 | 70 526 | 1 527 | 43 528 | 0.0 529 | 10 530 | -135.99999999999997 531 | 20 532 | 62.999999999999979 533 | 10 534 | -189.00000000000003 535 | 20 536 | 62.999999999999957 537 | 10 538 | -189 539 | 20 540 | 9.9999999999999858 541 | 10 542 | -135.99999999999997 543 | 20 544 | 9.9999999999999911 545 | 0 546 | LWPOLYLINE 547 | 5 548 | 109 549 | 100 550 | AcDbEntity 551 | 8 552 | 0 553 | 100 554 | AcDbPolyline 555 | 90 556 | 4 557 | 70 558 | 1 559 | 43 560 | 0.0 561 | 10 562 | -73 563 | 20 564 | 9.9999999999999858 565 | 10 566 | -125.99999999999997 567 | 20 568 | 9.9999999999999911 569 | 10 570 | -125.99999999999997 571 | 20 572 | 62.999999999999979 573 | 10 574 | -73 575 | 20 576 | 62.999999999999972 577 | 0 578 | LWPOLYLINE 579 | 5 580 | 110 581 | 100 582 | AcDbEntity 583 | 8 584 | 0 585 | 100 586 | AcDbPolyline 587 | 90 588 | 8 589 | 70 590 | 1 591 | 43 592 | 0.0 593 | 10 594 | 10 595 | 20 596 | 82.999999999999986 597 | 10 598 | -261.99999999999994 599 | 20 600 | 82.999999999999986 601 | 42 602 | 0.41421356237309509 603 | 10 604 | -271.99999999999994 605 | 20 606 | 73 607 | 10 608 | -271.99999999999994 609 | 20 610 | -125.99999999999983 611 | 42 612 | 0.41421356237309509 613 | 10 614 | -261.99999999999983 615 | 20 616 | -135.99999999999994 617 | 10 618 | 9.9999999999999822 619 | 20 620 | -135.99999999999994 621 | 42 622 | 0.41421356237309509 623 | 10 624 | 20 625 | 20 626 | -125.99999999999994 627 | 10 628 | 20 629 | 20 630 | 72.999999999999986 631 | 42 632 | 0.41421356237309509 633 | 0 634 | ENDSEC 635 | 0 636 | SECTION 637 | 2 638 | OBJECTS 639 | 0 640 | DICTIONARY 641 | 5 642 | C 643 | 100 644 | AcDbDictionary 645 | 3 646 | ACAD_GROUP 647 | 350 648 | D 649 | 3 650 | ACAD_MLINESTYLE 651 | 350 652 | 17 653 | 0 654 | DICTIONARY 655 | 5 656 | D 657 | 100 658 | AcDbDictionary 659 | 0 660 | DICTIONARY 661 | 5 662 | 1A 663 | 330 664 | C 665 | 100 666 | AcDbDictionary 667 | 0 668 | DICTIONARY 669 | 5 670 | 17 671 | 100 672 | AcDbDictionary 673 | 0 674 | ENDSEC 675 | 0 676 | EOF 677 | -------------------------------------------------------------------------------- /Server/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "musiccube", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "accepts": { 8 | "version": "1.3.5", 9 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", 10 | "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", 11 | "requires": { 12 | "mime-types": "~2.1.18", 13 | "negotiator": "0.6.1" 14 | } 15 | }, 16 | "array-flatten": { 17 | "version": "1.1.1", 18 | "resolved": "http://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 19 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 20 | }, 21 | "axios": { 22 | "version": "0.18.0", 23 | "resolved": "http://registry.npmjs.org/axios/-/axios-0.18.0.tgz", 24 | "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", 25 | "requires": { 26 | "follow-redirects": "^1.3.0", 27 | "is-buffer": "^1.1.5" 28 | } 29 | }, 30 | "body-parser": { 31 | "version": "1.18.3", 32 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", 33 | "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", 34 | "requires": { 35 | "bytes": "3.0.0", 36 | "content-type": "~1.0.4", 37 | "debug": "2.6.9", 38 | "depd": "~1.1.2", 39 | "http-errors": "~1.6.3", 40 | "iconv-lite": "0.4.23", 41 | "on-finished": "~2.3.0", 42 | "qs": "6.5.2", 43 | "raw-body": "2.3.3", 44 | "type-is": "~1.6.16" 45 | }, 46 | "dependencies": { 47 | "debug": { 48 | "version": "2.6.9", 49 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 50 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 51 | "requires": { 52 | "ms": "2.0.0" 53 | } 54 | } 55 | } 56 | }, 57 | "bytes": { 58 | "version": "3.0.0", 59 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", 60 | "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" 61 | }, 62 | "content-disposition": { 63 | "version": "0.5.2", 64 | "resolved": "http://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", 65 | "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" 66 | }, 67 | "content-type": { 68 | "version": "1.0.4", 69 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 70 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 71 | }, 72 | "cookie": { 73 | "version": "0.3.1", 74 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", 75 | "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" 76 | }, 77 | "cookie-signature": { 78 | "version": "1.0.6", 79 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 80 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 81 | }, 82 | "debug": { 83 | "version": "3.1.0", 84 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 85 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 86 | "requires": { 87 | "ms": "2.0.0" 88 | } 89 | }, 90 | "depd": { 91 | "version": "1.1.2", 92 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 93 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 94 | }, 95 | "destroy": { 96 | "version": "1.0.4", 97 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 98 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 99 | }, 100 | "ee-first": { 101 | "version": "1.1.1", 102 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 103 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 104 | }, 105 | "encodeurl": { 106 | "version": "1.0.2", 107 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 108 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 109 | }, 110 | "escape-html": { 111 | "version": "1.0.3", 112 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 113 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 114 | }, 115 | "etag": { 116 | "version": "1.8.1", 117 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 118 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 119 | }, 120 | "express": { 121 | "version": "4.16.4", 122 | "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", 123 | "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", 124 | "requires": { 125 | "accepts": "~1.3.5", 126 | "array-flatten": "1.1.1", 127 | "body-parser": "1.18.3", 128 | "content-disposition": "0.5.2", 129 | "content-type": "~1.0.4", 130 | "cookie": "0.3.1", 131 | "cookie-signature": "1.0.6", 132 | "debug": "2.6.9", 133 | "depd": "~1.1.2", 134 | "encodeurl": "~1.0.2", 135 | "escape-html": "~1.0.3", 136 | "etag": "~1.8.1", 137 | "finalhandler": "1.1.1", 138 | "fresh": "0.5.2", 139 | "merge-descriptors": "1.0.1", 140 | "methods": "~1.1.2", 141 | "on-finished": "~2.3.0", 142 | "parseurl": "~1.3.2", 143 | "path-to-regexp": "0.1.7", 144 | "proxy-addr": "~2.0.4", 145 | "qs": "6.5.2", 146 | "range-parser": "~1.2.0", 147 | "safe-buffer": "5.1.2", 148 | "send": "0.16.2", 149 | "serve-static": "1.13.2", 150 | "setprototypeof": "1.1.0", 151 | "statuses": "~1.4.0", 152 | "type-is": "~1.6.16", 153 | "utils-merge": "1.0.1", 154 | "vary": "~1.1.2" 155 | }, 156 | "dependencies": { 157 | "debug": { 158 | "version": "2.6.9", 159 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 160 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 161 | "requires": { 162 | "ms": "2.0.0" 163 | } 164 | } 165 | } 166 | }, 167 | "finalhandler": { 168 | "version": "1.1.1", 169 | "resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", 170 | "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", 171 | "requires": { 172 | "debug": "2.6.9", 173 | "encodeurl": "~1.0.2", 174 | "escape-html": "~1.0.3", 175 | "on-finished": "~2.3.0", 176 | "parseurl": "~1.3.2", 177 | "statuses": "~1.4.0", 178 | "unpipe": "~1.0.0" 179 | }, 180 | "dependencies": { 181 | "debug": { 182 | "version": "2.6.9", 183 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 184 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 185 | "requires": { 186 | "ms": "2.0.0" 187 | } 188 | } 189 | } 190 | }, 191 | "follow-redirects": { 192 | "version": "1.5.10", 193 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", 194 | "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", 195 | "requires": { 196 | "debug": "=3.1.0" 197 | } 198 | }, 199 | "forwarded": { 200 | "version": "0.1.2", 201 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", 202 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 203 | }, 204 | "fresh": { 205 | "version": "0.5.2", 206 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 207 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 208 | }, 209 | "http-errors": { 210 | "version": "1.6.3", 211 | "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", 212 | "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", 213 | "requires": { 214 | "depd": "~1.1.2", 215 | "inherits": "2.0.3", 216 | "setprototypeof": "1.1.0", 217 | "statuses": ">= 1.4.0 < 2" 218 | } 219 | }, 220 | "iconv-lite": { 221 | "version": "0.4.23", 222 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", 223 | "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", 224 | "requires": { 225 | "safer-buffer": ">= 2.1.2 < 3" 226 | } 227 | }, 228 | "inherits": { 229 | "version": "2.0.3", 230 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 231 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 232 | }, 233 | "ipaddr.js": { 234 | "version": "1.8.0", 235 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", 236 | "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=" 237 | }, 238 | "is-buffer": { 239 | "version": "1.1.6", 240 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", 241 | "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" 242 | }, 243 | "log-prefix": { 244 | "version": "0.1.1", 245 | "resolved": "https://registry.npmjs.org/log-prefix/-/log-prefix-0.1.1.tgz", 246 | "integrity": "sha512-aP1Lst8OCdZKATqzXDN0JBissNVZuiKLyo6hOXDBxaQ1jHDsaxh2J1i5Pp0zMy6ayTKDWfUlLMXyLaQe1PJ48g==" 247 | }, 248 | "log-timestamp": { 249 | "version": "0.3.0", 250 | "resolved": "https://registry.npmjs.org/log-timestamp/-/log-timestamp-0.3.0.tgz", 251 | "integrity": "sha512-luRz6soxijd1aJh0GkLXFjKABihxthvTfWTzu3XhCgg5EivG2bsTpSd63QFbUgS+/KmFtL+0RfSpeaD2QvOV8Q==", 252 | "requires": { 253 | "log-prefix": "0.1.1" 254 | } 255 | }, 256 | "media-typer": { 257 | "version": "0.3.0", 258 | "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 259 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 260 | }, 261 | "merge-descriptors": { 262 | "version": "1.0.1", 263 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 264 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 265 | }, 266 | "methods": { 267 | "version": "1.1.2", 268 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 269 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 270 | }, 271 | "mime": { 272 | "version": "1.4.1", 273 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", 274 | "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" 275 | }, 276 | "mime-db": { 277 | "version": "1.37.0", 278 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", 279 | "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==" 280 | }, 281 | "mime-types": { 282 | "version": "2.1.21", 283 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", 284 | "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", 285 | "requires": { 286 | "mime-db": "~1.37.0" 287 | } 288 | }, 289 | "ms": { 290 | "version": "2.0.0", 291 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 292 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 293 | }, 294 | "negotiator": { 295 | "version": "0.6.1", 296 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", 297 | "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" 298 | }, 299 | "on-finished": { 300 | "version": "2.3.0", 301 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 302 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 303 | "requires": { 304 | "ee-first": "1.1.1" 305 | } 306 | }, 307 | "parseurl": { 308 | "version": "1.3.2", 309 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", 310 | "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" 311 | }, 312 | "path-to-regexp": { 313 | "version": "0.1.7", 314 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 315 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 316 | }, 317 | "proxy-addr": { 318 | "version": "2.0.4", 319 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", 320 | "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", 321 | "requires": { 322 | "forwarded": "~0.1.2", 323 | "ipaddr.js": "1.8.0" 324 | } 325 | }, 326 | "qs": { 327 | "version": "6.5.2", 328 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", 329 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" 330 | }, 331 | "range-parser": { 332 | "version": "1.2.0", 333 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", 334 | "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" 335 | }, 336 | "raw-body": { 337 | "version": "2.3.3", 338 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", 339 | "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", 340 | "requires": { 341 | "bytes": "3.0.0", 342 | "http-errors": "1.6.3", 343 | "iconv-lite": "0.4.23", 344 | "unpipe": "1.0.0" 345 | } 346 | }, 347 | "safe-buffer": { 348 | "version": "5.1.2", 349 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 350 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 351 | }, 352 | "safer-buffer": { 353 | "version": "2.1.2", 354 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 355 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 356 | }, 357 | "send": { 358 | "version": "0.16.2", 359 | "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", 360 | "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", 361 | "requires": { 362 | "debug": "2.6.9", 363 | "depd": "~1.1.2", 364 | "destroy": "~1.0.4", 365 | "encodeurl": "~1.0.2", 366 | "escape-html": "~1.0.3", 367 | "etag": "~1.8.1", 368 | "fresh": "0.5.2", 369 | "http-errors": "~1.6.2", 370 | "mime": "1.4.1", 371 | "ms": "2.0.0", 372 | "on-finished": "~2.3.0", 373 | "range-parser": "~1.2.0", 374 | "statuses": "~1.4.0" 375 | }, 376 | "dependencies": { 377 | "debug": { 378 | "version": "2.6.9", 379 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 380 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 381 | "requires": { 382 | "ms": "2.0.0" 383 | } 384 | } 385 | } 386 | }, 387 | "serve-static": { 388 | "version": "1.13.2", 389 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", 390 | "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", 391 | "requires": { 392 | "encodeurl": "~1.0.2", 393 | "escape-html": "~1.0.3", 394 | "parseurl": "~1.3.2", 395 | "send": "0.16.2" 396 | } 397 | }, 398 | "setprototypeof": { 399 | "version": "1.1.0", 400 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", 401 | "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" 402 | }, 403 | "statuses": { 404 | "version": "1.4.0", 405 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", 406 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" 407 | }, 408 | "type-is": { 409 | "version": "1.6.16", 410 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", 411 | "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", 412 | "requires": { 413 | "media-typer": "0.3.0", 414 | "mime-types": "~2.1.18" 415 | } 416 | }, 417 | "unpipe": { 418 | "version": "1.0.0", 419 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 420 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 421 | }, 422 | "utils-merge": { 423 | "version": "1.0.1", 424 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 425 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 426 | }, 427 | "vary": { 428 | "version": "1.1.2", 429 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 430 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 431 | } 432 | } 433 | } 434 | --------------------------------------------------------------------------------