├── CHANGELOG.md ├── LICENSE ├── README.md ├── VERSION ├── data ├── .gitignore ├── Dockerfile ├── index.js ├── package-lock.json └── package.json ├── docker-compose.yml ├── frontend ├── Dockerfile ├── index.js ├── package.json └── static │ ├── index.html │ ├── js │ ├── app.js │ └── main.js │ └── style │ ├── balena_logo.svg │ └── styles.css ├── haproxy ├── Dockerfile └── haproxy.cfg ├── repo.yml └── wpe ├── Dockerfile ├── LICENSE ├── public_html ├── balena_logo.svg ├── index.html └── styles.css └── wpe-init /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file 4 | automatically by Versionist. DO NOT EDIT THIS FILE MANUALLY! 5 | This project adheres to [Semantic Versioning](http://semver.org/). 6 | 7 | # v1.0.0 8 | ## (2019-08-29) 9 | 10 | * Update this project and fix some issues [Gergely Imreh] 11 | * haproxy: Update to 1.9 and use resolvers for dynamic host resolution [Pablo Carranza Velez] 12 | * logo: Update to the Balena logo [Gergely Imreh] 13 | * bumping WPE version to latest [Gergely Imreh] 14 | * script load retry and resin logo loading spinner [Gergely Imreh] 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2016 Resin.io 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Multicontainer on balenaCloud 2 | 3 | This example will get you up and running quickly with a multicontainer setup on balenaCloud. The application plots our devices' CPU temperature on the device URL and LCD screen which is piped over using websockets. The system is composed of a simple static site server, a websocket server and a proxy and GUI service. These 4 components are defined in our [docker-compose.yml](docker-compose.yml) as services and are only given as much privilege as is needed. 4 | 5 | To get this project up and running, you will first need to signup for a balenaCloud account [here](https://dashboard.balena-cloud.com/signup), create an application, and add a device. Have a look at our [Getting Started guide](https://www.balena.io/docs/learn/getting-started) if you need help. 6 | 7 | Once you are set up with an account, you will need to clone this repo locally: 8 | ``` 9 | $ git clone https://github.com/balena-io-projects/multicontainer-demo-rpi3 10 | ``` 11 | Then add your application's remote repository to your local repository: 12 | ``` 13 | $ git remote add balena username@git.balena-cloud.com:username/myapp.git 14 | ``` 15 | and push the code to the newly added remote: 16 | ``` 17 | $ git push balena master 18 | ``` 19 | It should take a few minutes for the code to push. While you wait, let's [enable device URLs](https://www.balena.io/docs/learn/manage/actions/#enable-public-device-url) so we can see the server outside of our local network. This option can be found in the Actions drop down in your device dashboard. 20 | 21 | ### Setup: 22 | 23 | Give the GPU some more memory to run the GUI. 24 | ``` 25 | BALENA_HOST_CONFIG_gpu_mem=192 26 | ``` 27 | 28 | Device Configuration for PiTFT screens: 29 | 30 | If you are using one of the piTFT screens, you will need to apply the following config. 31 | ``` 32 | BALENA_HOST_CONFIG_dtoverlay=pitft28-resistive,rotate=90,speed=62000000,fps=60 33 | BALENA_HOST_CONFIG_hdmi_force_hotplug 1 34 | BALENA_HOST_CONFIG_hdmi_group 2 35 | BALENA_HOST_CONFIG_hdmi_mode 87 36 | BALENA_HOST_CONFIG_hdmi_cvt 320 240 60 1 0 0 0 37 | ``` 38 | 39 | ### Demo: 40 | 41 | In order to demonstrate some visible changes after an update, you can follow these steps: 42 | 43 | - In https://github.com/balena-io-projects/multicontainer-demo-rpi3/blob/master/data/index.js 44 | - Uncomment `// data.color = '#FF0000'` . This will change the graph from the default blue to a more visible red color. 45 | - Comment out `getRandomTemp(socket);` and uncomment `// getCpuTemp(socket);`. After pushing this change, the graph should be less random, with values around the current CPU temperature. If you provision a local device, you can show off a cool effect by touching the CPU with your finger; the temperature will instantly drop and that will be visible in the graph. 46 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 1.0.0 2 | -------------------------------------------------------------------------------- /data/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log 3 | -------------------------------------------------------------------------------- /data/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM arm32v6/node:12-alpine 2 | 3 | # Defines our working directory in container 4 | WORKDIR /usr/src/app 5 | 6 | # Copies the package.json first for better cache on later pushes 7 | COPY package.json package.json 8 | 9 | # This install npm dependencies on the resin.io build server, 10 | # making sure to clean up the artifacts it creates in order to reduce the image size. 11 | RUN JOBS=MAX npm install --production 12 | # This will copy all files in our root to the working directory in the container 13 | COPY . ./ 14 | 15 | # server.js will run when container starts up on the device 16 | CMD ["npm", "start"] -------------------------------------------------------------------------------- /data/index.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const app = express(); 3 | const server = require('http').createServer(app); 4 | const io = require('socket.io')(server); 5 | const { 6 | exec 7 | } = require('child_process'); 8 | 9 | period = parseInt(process.env.PERIOD) || 500; 10 | 11 | server.listen(8080); 12 | 13 | let sendTemp = function(socket, data) { 14 | //data.color = '#FF0000' 15 | socket.emit('temperature', data); 16 | } 17 | 18 | let getCpuTemp = function(socket) { 19 | 'use strict'; 20 | exec('cat /sys/class/thermal/thermal_zone*/temp', (err, stdout) => { 21 | if (err) throw err; 22 | let data = { 23 | t: parseFloat(stdout) / 1000 24 | }; 25 | sendTemp(socket, data); 26 | }); 27 | }; 28 | 29 | let getRandomTemp = function(socket) { 30 | 'use strict' 31 | let data = { 32 | t: (20 + Math.floor(Math.random() * 30)) 33 | }; 34 | sendTemp(socket, data); 35 | }; 36 | 37 | io.on('connection', function(socket) { 38 | 'use strict'; 39 | console.log('a user connected'); 40 | let dataLoop = setInterval(function() { 41 | //getCpuTemp(socket); 42 | getRandomTemp(socket); 43 | }, period); 44 | socket.on('disconnect', function() { 45 | console.log('a user disconnected'); 46 | clearInterval(dataLoop); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /data/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "resin-websocket", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "accepts": { 8 | "version": "1.3.4", 9 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz", 10 | "integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=", 11 | "requires": { 12 | "mime-types": "2.1.17", 13 | "negotiator": "0.6.1" 14 | } 15 | }, 16 | "after": { 17 | "version": "0.8.2", 18 | "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", 19 | "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" 20 | }, 21 | "array-flatten": { 22 | "version": "1.1.1", 23 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 24 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 25 | }, 26 | "arraybuffer.slice": { 27 | "version": "0.0.6", 28 | "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz", 29 | "integrity": "sha1-8zshWfBTKj8xB6JywMz70a0peco=" 30 | }, 31 | "backo2": { 32 | "version": "1.0.2", 33 | "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", 34 | "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" 35 | }, 36 | "base64-arraybuffer": { 37 | "version": "0.1.5", 38 | "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", 39 | "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" 40 | }, 41 | "base64id": { 42 | "version": "1.0.0", 43 | "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", 44 | "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=" 45 | }, 46 | "better-assert": { 47 | "version": "1.0.2", 48 | "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", 49 | "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", 50 | "requires": { 51 | "callsite": "1.0.0" 52 | } 53 | }, 54 | "blob": { 55 | "version": "0.0.4", 56 | "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", 57 | "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=" 58 | }, 59 | "body-parser": { 60 | "version": "1.18.2", 61 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", 62 | "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", 63 | "requires": { 64 | "bytes": "3.0.0", 65 | "content-type": "1.0.4", 66 | "debug": "2.6.9", 67 | "depd": "1.1.2", 68 | "http-errors": "1.6.2", 69 | "iconv-lite": "0.4.19", 70 | "on-finished": "2.3.0", 71 | "qs": "6.5.1", 72 | "raw-body": "2.3.2", 73 | "type-is": "1.6.15" 74 | } 75 | }, 76 | "bytes": { 77 | "version": "3.0.0", 78 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", 79 | "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" 80 | }, 81 | "callsite": { 82 | "version": "1.0.0", 83 | "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", 84 | "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" 85 | }, 86 | "component-bind": { 87 | "version": "1.0.0", 88 | "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", 89 | "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" 90 | }, 91 | "component-emitter": { 92 | "version": "1.1.2", 93 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz", 94 | "integrity": "sha1-KWWU8nU9qmOZbSrwjRWpURbJrsM=" 95 | }, 96 | "component-inherit": { 97 | "version": "0.0.3", 98 | "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", 99 | "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" 100 | }, 101 | "content-disposition": { 102 | "version": "0.5.2", 103 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", 104 | "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" 105 | }, 106 | "content-type": { 107 | "version": "1.0.4", 108 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 109 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 110 | }, 111 | "cookie": { 112 | "version": "0.3.1", 113 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", 114 | "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" 115 | }, 116 | "cookie-signature": { 117 | "version": "1.0.6", 118 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 119 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 120 | }, 121 | "debug": { 122 | "version": "2.6.9", 123 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 124 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 125 | "requires": { 126 | "ms": "2.0.0" 127 | } 128 | }, 129 | "depd": { 130 | "version": "1.1.2", 131 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 132 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 133 | }, 134 | "destroy": { 135 | "version": "1.0.4", 136 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 137 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 138 | }, 139 | "ee-first": { 140 | "version": "1.1.1", 141 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 142 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 143 | }, 144 | "encodeurl": { 145 | "version": "1.0.2", 146 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 147 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 148 | }, 149 | "engine.io": { 150 | "version": "1.8.5", 151 | "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-1.8.5.tgz", 152 | "integrity": "sha512-j1DWIcktw4hRwrv6nWx++5nFH2X64x16MAG2P0Lmi5Dvdfi3I+Jhc7JKJIdAmDJa+5aZ/imHV7dWRPy2Cqjh3A==", 153 | "requires": { 154 | "accepts": "1.3.3", 155 | "base64id": "1.0.0", 156 | "cookie": "0.3.1", 157 | "debug": "2.3.3", 158 | "engine.io-parser": "1.3.2", 159 | "ws": "1.1.5" 160 | }, 161 | "dependencies": { 162 | "accepts": { 163 | "version": "1.3.3", 164 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz", 165 | "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=", 166 | "requires": { 167 | "mime-types": "2.1.17", 168 | "negotiator": "0.6.1" 169 | } 170 | }, 171 | "debug": { 172 | "version": "2.3.3", 173 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", 174 | "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", 175 | "requires": { 176 | "ms": "0.7.2" 177 | } 178 | }, 179 | "ms": { 180 | "version": "0.7.2", 181 | "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", 182 | "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=" 183 | } 184 | } 185 | }, 186 | "engine.io-client": { 187 | "version": "1.8.5", 188 | "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.8.5.tgz", 189 | "integrity": "sha512-AYTgHyeVUPitsseqjoedjhYJapNVoSPShbZ+tEUX9/73jgZ/Z3sUlJf9oYgdEBBdVhupUpUqSxH0kBCXlQnmZg==", 190 | "requires": { 191 | "component-emitter": "1.2.1", 192 | "component-inherit": "0.0.3", 193 | "debug": "2.3.3", 194 | "engine.io-parser": "1.3.2", 195 | "has-cors": "1.1.0", 196 | "indexof": "0.0.1", 197 | "parsejson": "0.0.3", 198 | "parseqs": "0.0.5", 199 | "parseuri": "0.0.5", 200 | "ws": "1.1.5", 201 | "xmlhttprequest-ssl": "1.5.3", 202 | "yeast": "0.1.2" 203 | }, 204 | "dependencies": { 205 | "component-emitter": { 206 | "version": "1.2.1", 207 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", 208 | "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" 209 | }, 210 | "debug": { 211 | "version": "2.3.3", 212 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", 213 | "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", 214 | "requires": { 215 | "ms": "0.7.2" 216 | } 217 | }, 218 | "ms": { 219 | "version": "0.7.2", 220 | "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", 221 | "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=" 222 | } 223 | } 224 | }, 225 | "engine.io-parser": { 226 | "version": "1.3.2", 227 | "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.3.2.tgz", 228 | "integrity": "sha1-k3sHnwAH0Ik+xW1GyyILjLQ1Igo=", 229 | "requires": { 230 | "after": "0.8.2", 231 | "arraybuffer.slice": "0.0.6", 232 | "base64-arraybuffer": "0.1.5", 233 | "blob": "0.0.4", 234 | "has-binary": "0.1.7", 235 | "wtf-8": "1.0.0" 236 | } 237 | }, 238 | "escape-html": { 239 | "version": "1.0.3", 240 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 241 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 242 | }, 243 | "etag": { 244 | "version": "1.8.1", 245 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 246 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 247 | }, 248 | "express": { 249 | "version": "4.16.2", 250 | "resolved": "https://registry.npmjs.org/express/-/express-4.16.2.tgz", 251 | "integrity": "sha1-41xt/i1kt9ygpc1PIXgb4ymeB2w=", 252 | "requires": { 253 | "accepts": "1.3.4", 254 | "array-flatten": "1.1.1", 255 | "body-parser": "1.18.2", 256 | "content-disposition": "0.5.2", 257 | "content-type": "1.0.4", 258 | "cookie": "0.3.1", 259 | "cookie-signature": "1.0.6", 260 | "debug": "2.6.9", 261 | "depd": "1.1.2", 262 | "encodeurl": "1.0.2", 263 | "escape-html": "1.0.3", 264 | "etag": "1.8.1", 265 | "finalhandler": "1.1.0", 266 | "fresh": "0.5.2", 267 | "merge-descriptors": "1.0.1", 268 | "methods": "1.1.2", 269 | "on-finished": "2.3.0", 270 | "parseurl": "1.3.2", 271 | "path-to-regexp": "0.1.7", 272 | "proxy-addr": "2.0.2", 273 | "qs": "6.5.1", 274 | "range-parser": "1.2.0", 275 | "safe-buffer": "5.1.1", 276 | "send": "0.16.1", 277 | "serve-static": "1.13.1", 278 | "setprototypeof": "1.1.0", 279 | "statuses": "1.3.1", 280 | "type-is": "1.6.15", 281 | "utils-merge": "1.0.1", 282 | "vary": "1.1.2" 283 | } 284 | }, 285 | "finalhandler": { 286 | "version": "1.1.0", 287 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", 288 | "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", 289 | "requires": { 290 | "debug": "2.6.9", 291 | "encodeurl": "1.0.2", 292 | "escape-html": "1.0.3", 293 | "on-finished": "2.3.0", 294 | "parseurl": "1.3.2", 295 | "statuses": "1.3.1", 296 | "unpipe": "1.0.0" 297 | } 298 | }, 299 | "forwarded": { 300 | "version": "0.1.2", 301 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", 302 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 303 | }, 304 | "fresh": { 305 | "version": "0.5.2", 306 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 307 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 308 | }, 309 | "has-binary": { 310 | "version": "0.1.7", 311 | "resolved": "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz", 312 | "integrity": "sha1-aOYesWIQyVRaClzOBqhzkS/h5ow=", 313 | "requires": { 314 | "isarray": "0.0.1" 315 | } 316 | }, 317 | "has-cors": { 318 | "version": "1.1.0", 319 | "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", 320 | "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" 321 | }, 322 | "http-errors": { 323 | "version": "1.6.2", 324 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", 325 | "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", 326 | "requires": { 327 | "depd": "1.1.1", 328 | "inherits": "2.0.3", 329 | "setprototypeof": "1.0.3", 330 | "statuses": "1.3.1" 331 | }, 332 | "dependencies": { 333 | "depd": { 334 | "version": "1.1.1", 335 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", 336 | "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" 337 | }, 338 | "setprototypeof": { 339 | "version": "1.0.3", 340 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", 341 | "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" 342 | } 343 | } 344 | }, 345 | "iconv-lite": { 346 | "version": "0.4.19", 347 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", 348 | "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" 349 | }, 350 | "indexof": { 351 | "version": "0.0.1", 352 | "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", 353 | "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" 354 | }, 355 | "inherits": { 356 | "version": "2.0.3", 357 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 358 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 359 | }, 360 | "ipaddr.js": { 361 | "version": "1.5.2", 362 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.5.2.tgz", 363 | "integrity": "sha1-1LUFvemUaYfM8PxY2QEP+WB+P6A=" 364 | }, 365 | "isarray": { 366 | "version": "0.0.1", 367 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 368 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" 369 | }, 370 | "json3": { 371 | "version": "3.3.2", 372 | "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", 373 | "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=" 374 | }, 375 | "media-typer": { 376 | "version": "0.3.0", 377 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 378 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 379 | }, 380 | "merge-descriptors": { 381 | "version": "1.0.1", 382 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 383 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 384 | }, 385 | "methods": { 386 | "version": "1.1.2", 387 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 388 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 389 | }, 390 | "mime": { 391 | "version": "1.4.1", 392 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", 393 | "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" 394 | }, 395 | "mime-db": { 396 | "version": "1.30.0", 397 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", 398 | "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" 399 | }, 400 | "mime-types": { 401 | "version": "2.1.17", 402 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", 403 | "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", 404 | "requires": { 405 | "mime-db": "1.30.0" 406 | } 407 | }, 408 | "ms": { 409 | "version": "2.0.0", 410 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 411 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 412 | }, 413 | "negotiator": { 414 | "version": "0.6.1", 415 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", 416 | "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" 417 | }, 418 | "object-assign": { 419 | "version": "4.1.0", 420 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz", 421 | "integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A=" 422 | }, 423 | "object-component": { 424 | "version": "0.0.3", 425 | "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", 426 | "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" 427 | }, 428 | "on-finished": { 429 | "version": "2.3.0", 430 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 431 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 432 | "requires": { 433 | "ee-first": "1.1.1" 434 | } 435 | }, 436 | "options": { 437 | "version": "0.0.6", 438 | "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", 439 | "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=" 440 | }, 441 | "parsejson": { 442 | "version": "0.0.3", 443 | "resolved": "https://registry.npmjs.org/parsejson/-/parsejson-0.0.3.tgz", 444 | "integrity": "sha1-q343WfIJ7OmUN5c/fQ8fZK4OZKs=", 445 | "requires": { 446 | "better-assert": "1.0.2" 447 | } 448 | }, 449 | "parseqs": { 450 | "version": "0.0.5", 451 | "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", 452 | "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", 453 | "requires": { 454 | "better-assert": "1.0.2" 455 | } 456 | }, 457 | "parseuri": { 458 | "version": "0.0.5", 459 | "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", 460 | "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", 461 | "requires": { 462 | "better-assert": "1.0.2" 463 | } 464 | }, 465 | "parseurl": { 466 | "version": "1.3.2", 467 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", 468 | "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" 469 | }, 470 | "path-to-regexp": { 471 | "version": "0.1.7", 472 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 473 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 474 | }, 475 | "proxy-addr": { 476 | "version": "2.0.2", 477 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.2.tgz", 478 | "integrity": "sha1-ZXFQT0e7mI7IGAJT+F3X4UlSvew=", 479 | "requires": { 480 | "forwarded": "0.1.2", 481 | "ipaddr.js": "1.5.2" 482 | } 483 | }, 484 | "qs": { 485 | "version": "6.5.1", 486 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", 487 | "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" 488 | }, 489 | "range-parser": { 490 | "version": "1.2.0", 491 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", 492 | "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" 493 | }, 494 | "raw-body": { 495 | "version": "2.3.2", 496 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", 497 | "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", 498 | "requires": { 499 | "bytes": "3.0.0", 500 | "http-errors": "1.6.2", 501 | "iconv-lite": "0.4.19", 502 | "unpipe": "1.0.0" 503 | } 504 | }, 505 | "safe-buffer": { 506 | "version": "5.1.1", 507 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 508 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" 509 | }, 510 | "send": { 511 | "version": "0.16.1", 512 | "resolved": "https://registry.npmjs.org/send/-/send-0.16.1.tgz", 513 | "integrity": "sha512-ElCLJdJIKPk6ux/Hocwhk7NFHpI3pVm/IZOYWqUmoxcgeyM+MpxHHKhb8QmlJDX1pU6WrgaHBkVNm73Sv7uc2A==", 514 | "requires": { 515 | "debug": "2.6.9", 516 | "depd": "1.1.2", 517 | "destroy": "1.0.4", 518 | "encodeurl": "1.0.2", 519 | "escape-html": "1.0.3", 520 | "etag": "1.8.1", 521 | "fresh": "0.5.2", 522 | "http-errors": "1.6.2", 523 | "mime": "1.4.1", 524 | "ms": "2.0.0", 525 | "on-finished": "2.3.0", 526 | "range-parser": "1.2.0", 527 | "statuses": "1.3.1" 528 | } 529 | }, 530 | "serve-static": { 531 | "version": "1.13.1", 532 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz", 533 | "integrity": "sha512-hSMUZrsPa/I09VYFJwa627JJkNs0NrfL1Uzuup+GqHfToR2KcsXFymXSV90hoyw3M+msjFuQly+YzIH/q0MGlQ==", 534 | "requires": { 535 | "encodeurl": "1.0.2", 536 | "escape-html": "1.0.3", 537 | "parseurl": "1.3.2", 538 | "send": "0.16.1" 539 | } 540 | }, 541 | "setprototypeof": { 542 | "version": "1.1.0", 543 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", 544 | "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" 545 | }, 546 | "socket.io": { 547 | "version": "1.7.4", 548 | "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-1.7.4.tgz", 549 | "integrity": "sha1-L37O3DORvy1cc+KR/iM+bjTU3QA=", 550 | "requires": { 551 | "debug": "2.3.3", 552 | "engine.io": "1.8.5", 553 | "has-binary": "0.1.7", 554 | "object-assign": "4.1.0", 555 | "socket.io-adapter": "0.5.0", 556 | "socket.io-client": "1.7.4", 557 | "socket.io-parser": "2.3.1" 558 | }, 559 | "dependencies": { 560 | "debug": { 561 | "version": "2.3.3", 562 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", 563 | "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", 564 | "requires": { 565 | "ms": "0.7.2" 566 | } 567 | }, 568 | "ms": { 569 | "version": "0.7.2", 570 | "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", 571 | "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=" 572 | } 573 | } 574 | }, 575 | "socket.io-adapter": { 576 | "version": "0.5.0", 577 | "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz", 578 | "integrity": "sha1-y21LuL7IHhB4uZZ3+c7QBGBmu4s=", 579 | "requires": { 580 | "debug": "2.3.3", 581 | "socket.io-parser": "2.3.1" 582 | }, 583 | "dependencies": { 584 | "debug": { 585 | "version": "2.3.3", 586 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", 587 | "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", 588 | "requires": { 589 | "ms": "0.7.2" 590 | } 591 | }, 592 | "ms": { 593 | "version": "0.7.2", 594 | "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", 595 | "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=" 596 | } 597 | } 598 | }, 599 | "socket.io-client": { 600 | "version": "1.7.4", 601 | "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.7.4.tgz", 602 | "integrity": "sha1-7J+CA1btme9tNX8HVtZIcXvdQoE=", 603 | "requires": { 604 | "backo2": "1.0.2", 605 | "component-bind": "1.0.0", 606 | "component-emitter": "1.2.1", 607 | "debug": "2.3.3", 608 | "engine.io-client": "1.8.5", 609 | "has-binary": "0.1.7", 610 | "indexof": "0.0.1", 611 | "object-component": "0.0.3", 612 | "parseuri": "0.0.5", 613 | "socket.io-parser": "2.3.1", 614 | "to-array": "0.1.4" 615 | }, 616 | "dependencies": { 617 | "component-emitter": { 618 | "version": "1.2.1", 619 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", 620 | "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" 621 | }, 622 | "debug": { 623 | "version": "2.3.3", 624 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", 625 | "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", 626 | "requires": { 627 | "ms": "0.7.2" 628 | } 629 | }, 630 | "ms": { 631 | "version": "0.7.2", 632 | "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", 633 | "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=" 634 | } 635 | } 636 | }, 637 | "socket.io-parser": { 638 | "version": "2.3.1", 639 | "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.3.1.tgz", 640 | "integrity": "sha1-3VMgJRA85Clpcya+/WQAX8/ltKA=", 641 | "requires": { 642 | "component-emitter": "1.1.2", 643 | "debug": "2.2.0", 644 | "isarray": "0.0.1", 645 | "json3": "3.3.2" 646 | }, 647 | "dependencies": { 648 | "debug": { 649 | "version": "2.2.0", 650 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", 651 | "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", 652 | "requires": { 653 | "ms": "0.7.1" 654 | } 655 | }, 656 | "ms": { 657 | "version": "0.7.1", 658 | "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", 659 | "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=" 660 | } 661 | } 662 | }, 663 | "statuses": { 664 | "version": "1.3.1", 665 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", 666 | "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" 667 | }, 668 | "to-array": { 669 | "version": "0.1.4", 670 | "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", 671 | "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" 672 | }, 673 | "type-is": { 674 | "version": "1.6.15", 675 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", 676 | "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=", 677 | "requires": { 678 | "media-typer": "0.3.0", 679 | "mime-types": "2.1.17" 680 | } 681 | }, 682 | "ultron": { 683 | "version": "1.0.2", 684 | "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", 685 | "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=" 686 | }, 687 | "unpipe": { 688 | "version": "1.0.0", 689 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 690 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 691 | }, 692 | "utils-merge": { 693 | "version": "1.0.1", 694 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 695 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 696 | }, 697 | "vary": { 698 | "version": "1.1.2", 699 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 700 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 701 | }, 702 | "ws": { 703 | "version": "1.1.5", 704 | "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz", 705 | "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==", 706 | "requires": { 707 | "options": "0.0.6", 708 | "ultron": "1.0.2" 709 | } 710 | }, 711 | "wtf-8": { 712 | "version": "1.0.0", 713 | "resolved": "https://registry.npmjs.org/wtf-8/-/wtf-8-1.0.0.tgz", 714 | "integrity": "sha1-OS2LotDxw00e4tYw8V0O+2jhBIo=" 715 | }, 716 | "xmlhttprequest-ssl": { 717 | "version": "1.5.3", 718 | "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz", 719 | "integrity": "sha1-GFqIjATspGw+QHDZn3tJ3jUomS0=" 720 | }, 721 | "yeast": { 722 | "version": "0.1.2", 723 | "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", 724 | "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" 725 | } 726 | } 727 | } 728 | -------------------------------------------------------------------------------- /data/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "resin-websocket", 3 | "version": "1.0.0", 4 | "description": "Websocket example", 5 | "main": "index.js", 6 | "homepage": "https://github.com/resin-io-projects/resin-websocket", 7 | "repository": { 8 | "type": "git", 9 | "url": "git@github.com:resin-io-projects/resin-websocket.git" 10 | }, 11 | "scripts": { 12 | "start": "node index.js" 13 | }, 14 | "author": "Kostas Lekkas ", 15 | "license": "Apache-2.0", 16 | "jshintConfig": { 17 | "esversion": 6, 18 | "strict": true 19 | }, 20 | "dependencies": { 21 | "express": "^4.17.1", 22 | "socket.io": "^2.2.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | frontend: 4 | build: ./frontend 5 | expose: 6 | - "80" 7 | proxy: 8 | build: ./haproxy 9 | depends_on: 10 | - frontend 11 | - data 12 | ports: 13 | - "80:80" 14 | data: 15 | build: ./data 16 | expose: 17 | - "8080" 18 | gui: 19 | build: ./wpe 20 | depends_on: 21 | - proxy 22 | - frontend 23 | devices: 24 | - "/dev/fb0:/dev/fb0" 25 | - "/dev/fb1:/dev/fb1" 26 | - "/dev/vchiq:/dev/vchiq" 27 | -------------------------------------------------------------------------------- /frontend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM arm32v6/node:12-alpine 2 | 3 | # Defines our working directory in container 4 | WORKDIR /usr/src/app 5 | 6 | # Required for wget to work in the next step 7 | RUN apk add --no-cache ca-certificates openssl 8 | 9 | # Static install required JS dependencies 10 | ENV JQUERY_VERSION=3.3.1 11 | ENV REQUIREJS_VERSION=2.3.5 12 | ENV HIGHCHARTS_VERSION=7.0.3 13 | RUN mkdir -p static/js && \ 14 | wget "https://code.jquery.com/jquery-${JQUERY_VERSION}.min.js" -O static/js/jquery.min.js && \ 15 | wget "https://code.highcharts.com/${HIGHCHARTS_VERSION}/highcharts.js" -O static/js/highcharts.js && \ 16 | wget "http://requirejs.org/docs/release/${REQUIREJS_VERSION}/minified/require.js" -O static/js/require.js 17 | 18 | # Copies the package.json first for better cache on later pushes 19 | COPY package.json package.json 20 | 21 | # This install npm dependencies on the resin.io build server, 22 | # making sure to clean up the artifacts it creates in order to reduce the image size. 23 | RUN JOBS=MAX npm install --production 24 | # This will copy all files in our root to the working directory in the container 25 | COPY . ./ 26 | 27 | # server.js will run when container starts up on the device 28 | CMD ["npm", "start"] 29 | -------------------------------------------------------------------------------- /frontend/index.js: -------------------------------------------------------------------------------- 1 | var http = require('http'); 2 | var express = require('express'); 3 | 4 | var PORT = 80; 5 | 6 | var app = express(); 7 | var server = http.createServer(app); 8 | 9 | app.use(express.static(__dirname + '/static')) 10 | server.listen(PORT, function() { 11 | console.log("server is listening on port", PORT); 12 | }); 13 | 14 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "resin-websocket", 3 | "version": "1.0.0", 4 | "description": "Websocket example", 5 | "main": "index.js", 6 | "homepage": "https://github.com/resin-io-projects/resin-websocket", 7 | "repository": { 8 | "type": "git", 9 | "url": "git@github.com:resin-io-projects/resin-websocket.git" 10 | }, 11 | "scripts": { 12 | "start": "node index.js" 13 | }, 14 | "author": "Kostas Lekkas ", 15 | "license": "Apache-2.0", 16 | "dependencies": { 17 | "express": "^4.17.1" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /frontend/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Live Data 4 | 8 | 9 | 10 | 11 |
12 | 13 |
14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /frontend/static/js/app.js: -------------------------------------------------------------------------------- 1 | requirejs.config({ 2 | paths: { 3 | jquery: "jquery.min", 4 | highcharts: "highcharts", 5 | socketio: "../socket.io/socket.io" 6 | }, 7 | shim: { 8 | highcharts: { 9 | exports: "Highcharts", 10 | deps: ["jquery"] 11 | }, 12 | socketio: { 13 | exports: "io" 14 | } 15 | } 16 | }); 17 | 18 | // Retry failed module loading 19 | function requireWithRetry(modules) { 20 | var retryInterval = 5000; 21 | var retryCount = 0; 22 | var retryOnError = function(err) { 23 | var failedId = err.requireModules && err.requireModules[0]; 24 | // this is what tells RequireJS not to cache the previous failure status 25 | requirejs.undef(failedId); 26 | retryCount++; 27 | console.log(`Retrying module loading #${retryCount} after wait...`); 28 | setTimeout(function() { 29 | requirejs([failedId], null, retryOnError); 30 | }, retryInterval); 31 | }; 32 | requirejs(modules, null, retryOnError); 33 | } 34 | // Start our main code 35 | requireWithRetry(["main"]); 36 | -------------------------------------------------------------------------------- /frontend/static/js/main.js: -------------------------------------------------------------------------------- 1 | define(["jquery", "highcharts", "socketio"], function($, Highcharts, io) { 2 | $(document).ready(function() { 3 | $("div#loading").hide(); 4 | var chart = new Highcharts.Chart({ 5 | chart: { 6 | type: "area", 7 | margin: [40, 20, 60, 40], 8 | renderTo: "container", 9 | animation: false 10 | }, 11 | title: { 12 | text: "CPU Temperature Feed" 13 | }, 14 | xAxis: { 15 | gridLineWidth: 1, 16 | minPadding: 0.1, 17 | maxPadding: 0.1, 18 | maxZoom: 60 19 | }, 20 | yAxis: { 21 | title: { 22 | text: null 23 | }, 24 | max: 100, 25 | minPadding: 0.1, 26 | maxPadding: 0.1, 27 | maxZoom: 60, 28 | plotLines: [ 29 | { 30 | value: 0, 31 | width: 1, 32 | color: "#000000" 33 | } 34 | ] 35 | }, 36 | plotOptions: { 37 | series: { 38 | lineWidth: 1, 39 | marker: { 40 | enabled: false 41 | } 42 | } 43 | }, 44 | series: [ 45 | { 46 | name: "Temperature", 47 | type: "area", 48 | color: "#008800", 49 | data: [] 50 | } 51 | ] 52 | }); 53 | 54 | var socket = io.connect( 55 | window.location.protocol + "//" + window.location.hostname 56 | ); 57 | 58 | socket.on("temperature", data => { 59 | var series = chart.series[0]; 60 | series.addPoint([data.t], true, series.data.length > 200); 61 | }); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /frontend/static/style/balena_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 13 | 14 | 15 | 16 | 18 | 19 | 21 | 24 | 25 | 26 | 27 | 30 | 31 | 33 | 36 | 37 | 38 | 39 | 41 | 42 | 45 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /frontend/static/style/styles.css: -------------------------------------------------------------------------------- 1 | div#loader { 2 | width: 70px; 3 | height: 70px; 4 | margin: -35px 0 0 -35px; 5 | position: absolute; 6 | top: 50%; 7 | left: 50%; 8 | animation-name: spin; 9 | animation-duration: 2000ms; 10 | animation-iteration-count: infinite; 11 | animation-timing-function: linear; 12 | } 13 | 14 | @keyframes spin { 15 | from { 16 | transform: rotate(360deg); 17 | } 18 | to { 19 | transform: rotate(0deg); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /haproxy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM arm32v6/haproxy:1.9.7-alpine 2 | 3 | COPY haproxy.cfg /usr/local/etc/haproxy/haproxy.cfg 4 | -------------------------------------------------------------------------------- /haproxy/haproxy.cfg: -------------------------------------------------------------------------------- 1 | global 2 | maxconn 4096 3 | 4 | defaults 5 | mode http 6 | balance roundrobin 7 | option redispatch 8 | option forwardfor 9 | timeout connect 5s 10 | timeout queue 5s 11 | timeout client 50s 12 | timeout server 50s 13 | 14 | frontend http 15 | bind *:80 16 | default_backend backend_static_server 17 | # Any URL beginning with socket.io will be flagged as 'is_websocket' 18 | acl is_websocket path_beg /socket.io 19 | acl is_websocket hdr(Upgrade) -i WebSocket 20 | acl is_websocket hdr_beg(Host) -i ws 21 | 22 | # The connection to use if 'is_websocket' is flagged 23 | use_backend backend_data if is_websocket 24 | 25 | backend backend_static_server 26 | mode http 27 | option forwardfor 28 | balance roundrobin 29 | timeout server 600s 30 | server static_1 frontend:80 check port 80 resolvers dns 31 | 32 | backend backend_data 33 | balance source 34 | option http-server-close 35 | option forceclose 36 | server api_1 data:8080 weight 1 maxconn 1024 check resolvers dns 37 | 38 | resolvers dns 39 | parse-resolv-conf 40 | hold valid 10s 41 | -------------------------------------------------------------------------------- /repo.yml: -------------------------------------------------------------------------------- 1 | type: 'generic' 2 | -------------------------------------------------------------------------------- /wpe/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM petrosagg/resin-wpe:raspberrypi3-30c7465 2 | 3 | COPY wpe-init /wpe-init 4 | 5 | COPY public_html /var/lib/public_html 6 | 7 | ENV JQUERY_VERSION=3.4.1 8 | RUN wget "https://code.jquery.com/jquery-${JQUERY_VERSION}.min.js" -O /var/lib/public_html/jquery.min.js 9 | 10 | ENV WPE_URL="file:///var/lib/public_html/index.html" 11 | 12 | CMD [ "/wpe-init" ] 13 | -------------------------------------------------------------------------------- /wpe/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /wpe/public_html/balena_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 13 | 14 | 15 | 16 | 18 | 19 | 21 | 24 | 25 | 26 | 27 | 30 | 31 | 33 | 36 | 37 | 38 | 39 | 41 | 42 | 45 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /wpe/public_html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 39 | 40 | 41 |
42 | 43 |
44 | 45 | 46 | -------------------------------------------------------------------------------- /wpe/public_html/styles.css: -------------------------------------------------------------------------------- 1 | div#loader { 2 | width: 70px; 3 | height: 70px; 4 | margin: -35px 0 0 -35px; 5 | position: absolute; 6 | top: 50%; 7 | left: 50%; 8 | animation-name: spin; 9 | animation-duration: 2000ms; 10 | animation-iteration-count: infinite; 11 | animation-timing-function: linear; 12 | } 13 | 14 | @keyframes spin { 15 | from { 16 | transform: rotate(0deg); 17 | } 18 | to { 19 | transform: rotate(360deg); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /wpe/wpe-init: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | fbcp & 4 | until ping -c1 proxy ; do :; done 5 | 6 | echo "loading WPE with url: $WPE_URL" 7 | # sleep 3s 8 | WPELauncher $WPE_URL > /dev/null 2>&1 9 | --------------------------------------------------------------------------------